@clowder-ai/connector-weixin 0.0.0-stage → 0.1.0-alpha.5
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.en.md +55 -0
- package/README.md +27 -2
- package/assets/icon.svg +3 -0
- package/dist/WeixinAdapter.d.ts +255 -0
- package/dist/WeixinAdapter.d.ts.map +1 -0
- package/dist/WeixinAdapter.js +1130 -0
- package/dist/WeixinAdapter.js.map +1 -0
- package/dist/command-ingress.d.ts +10 -0
- package/dist/command-ingress.d.ts.map +1 -0
- package/dist/command-ingress.js +13 -0
- package/dist/command-ingress.js.map +1 -0
- package/dist/inbound-download.d.ts +13 -0
- package/dist/inbound-download.d.ts.map +1 -0
- package/dist/inbound-download.js +70 -0
- package/dist/inbound-download.js.map +1 -0
- package/dist/inbound-media-source.d.ts +25 -0
- package/dist/inbound-media-source.d.ts.map +1 -0
- package/dist/inbound-media-source.js +111 -0
- package/dist/inbound-media-source.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/materialize-media.d.ts +7 -0
- package/dist/materialize-media.d.ts.map +1 -0
- package/dist/materialize-media.js +35 -0
- package/dist/materialize-media.js.map +1 -0
- package/dist/media-notice.d.ts +6 -0
- package/dist/media-notice.d.ts.map +1 -0
- package/dist/media-notice.js +50 -0
- package/dist/media-notice.js.map +1 -0
- package/dist/plugin-entrypoint.d.ts +8 -0
- package/dist/plugin-entrypoint.d.ts.map +1 -0
- package/dist/plugin-entrypoint.js +295 -0
- package/dist/plugin-entrypoint.js.map +1 -0
- package/dist/reply-sender-map.d.ts +10 -0
- package/dist/reply-sender-map.d.ts.map +1 -0
- package/dist/reply-sender-map.js +123 -0
- package/dist/reply-sender-map.js.map +1 -0
- package/dist/rich-block-plaintext.d.ts +5 -0
- package/dist/rich-block-plaintext.d.ts.map +1 -0
- package/dist/rich-block-plaintext.js +45 -0
- package/dist/rich-block-plaintext.js.map +1 -0
- package/dist/runtime.d.ts +51 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +142 -0
- package/dist/runtime.js.map +1 -0
- package/dist/settings.d.ts +19 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +39 -0
- package/dist/settings.js.map +1 -0
- package/dist/thread-mappings.d.ts +46 -0
- package/dist/thread-mappings.d.ts.map +1 -0
- package/dist/thread-mappings.js +62 -0
- package/dist/thread-mappings.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/weixin-cdn.d.ts +43 -0
- package/dist/weixin-cdn.d.ts.map +1 -0
- package/dist/weixin-cdn.js +226 -0
- package/dist/weixin-cdn.js.map +1 -0
- package/npm-shrinkwrap.json +1013 -0
- package/package.json +58 -4
- package/plugin.yaml +107 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { isPluginDeliveryInput } from '@clowder-ai/plugin-contract';
|
|
2
|
+
import { definePluginModule } from '@clowder-ai/plugin-sdk';
|
|
3
|
+
import { threadMappings } from './thread-mappings.js';
|
|
4
|
+
import { createWeixinSettings } from './settings.js';
|
|
5
|
+
import { createConnectorCommandBridge } from '@clowder-ai/plugin-sdk';
|
|
6
|
+
import { definePlugin, defineDeliveryAction, requireConnectorOutboundDelivery, } from '@clowder-ai/plugin-sdk';
|
|
7
|
+
import { createWeixinConnectorRuntime, } from './runtime.js';
|
|
8
|
+
import { renderTypedMediaNotice } from './media-notice.js';
|
|
9
|
+
import { createInboundMediaSource, releaseInboundMedia, retainInboundMedia } from './inbound-media-source.js';
|
|
10
|
+
import { renderAllRichBlocksPlaintext } from './rich-block-plaintext.js';
|
|
11
|
+
import { createReplySenderMap } from './reply-sender-map.js';
|
|
12
|
+
import { connectorCommandFacts } from './command-ingress.js';
|
|
13
|
+
const CONNECTOR_ID = 'weixin';
|
|
14
|
+
const IDENTITY_ID = 'weixin-bot';
|
|
15
|
+
function object(value) {
|
|
16
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
function requireDelivery(candidate) {
|
|
19
|
+
if (!isPluginDeliveryInput(candidate) || candidate.kind !== 'message')
|
|
20
|
+
throw new TypeError('weixin requires a message delivery');
|
|
21
|
+
return structuredClone(candidate);
|
|
22
|
+
}
|
|
23
|
+
async function draft(context, message) {
|
|
24
|
+
const retained = await retainInboundMedia(context, CONNECTOR_ID, 'weixin-media', message.providerMessageId, (message.attachments ?? []).map(attachment => ({
|
|
25
|
+
type: attachment.type, platformKey: attachment.platformKey,
|
|
26
|
+
...(attachment.fileName === undefined ? {} : { fileName: attachment.fileName }),
|
|
27
|
+
})));
|
|
28
|
+
const messageDraft = {
|
|
29
|
+
idempotencyKey: message.providerMessageId,
|
|
30
|
+
sourceEventId: message.providerMessageId,
|
|
31
|
+
identity: IDENTITY_ID,
|
|
32
|
+
sender: { id: message.externalSenderId },
|
|
33
|
+
payload: {
|
|
34
|
+
provenance: {
|
|
35
|
+
origin: { kind: 'external', connectorId: CONNECTOR_ID, sourceAddress: { connectorId: CONNECTOR_ID, chatId: message.externalConversationId, messageId: message.providerMessageId } },
|
|
36
|
+
epistemicStatus: 'observation',
|
|
37
|
+
},
|
|
38
|
+
elements: [
|
|
39
|
+
{ elementId: 'text-1', kind: 'text', payload: { text: message.text } },
|
|
40
|
+
...retained.elements,
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
return { messageDraft, ownership: retained.ownership };
|
|
45
|
+
}
|
|
46
|
+
async function createMessageBridge(context, reply) {
|
|
47
|
+
const replySenders = createReplySenderMap(context);
|
|
48
|
+
const subscriptions = new Map();
|
|
49
|
+
const subscribe = (threadId) => {
|
|
50
|
+
const current = subscriptions.get(threadId);
|
|
51
|
+
if (current !== undefined)
|
|
52
|
+
return current;
|
|
53
|
+
let pending;
|
|
54
|
+
pending = context.messaging.subscribe(threadId, { contributionId: CONNECTOR_ID }).catch((error) => {
|
|
55
|
+
if (subscriptions.get(threadId) === pending)
|
|
56
|
+
subscriptions.delete(threadId);
|
|
57
|
+
throw error;
|
|
58
|
+
});
|
|
59
|
+
subscriptions.set(threadId, pending);
|
|
60
|
+
return pending;
|
|
61
|
+
};
|
|
62
|
+
for (const binding of await threadMappings(context).listBindings())
|
|
63
|
+
await subscribe(binding.threadId);
|
|
64
|
+
const routeCommand = createConnectorCommandBridge(context, {
|
|
65
|
+
connectorId: CONNECTOR_ID, identityId: IDENTITY_ID, reply,
|
|
66
|
+
settle: async () => { },
|
|
67
|
+
async bindingChanged(change) {
|
|
68
|
+
if (change.threadId !== undefined)
|
|
69
|
+
await subscribe(change.threadId);
|
|
70
|
+
if (change.previousThreadId !== undefined && change.previousThreadId !== change.threadId &&
|
|
71
|
+
!(await threadMappings(context).listBindings()).some(binding => binding.threadId === change.previousThreadId)) {
|
|
72
|
+
await context.messaging.unsubscribe(change.previousThreadId);
|
|
73
|
+
subscriptions.delete(change.previousThreadId);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
return {
|
|
78
|
+
async deliver(message) {
|
|
79
|
+
await routeCommand(connectorCommandFacts(message), async () => {
|
|
80
|
+
const thread = await threadMappings(context).ensureByKey(message.externalConversationId, { title: `WeChat ${message.externalConversationId}`.slice(0, 200) });
|
|
81
|
+
await subscribe(thread.id);
|
|
82
|
+
const prepared = await draft(context, message);
|
|
83
|
+
try {
|
|
84
|
+
const sent = await context.messaging.send(thread.id, prepared.messageDraft);
|
|
85
|
+
if (prepared.messageDraft.sender !== undefined) {
|
|
86
|
+
try {
|
|
87
|
+
await replySenders.record(sent.messageId, prepared.messageDraft.sender);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
context.log('warn', 'Weixin reply-sender mapping record failed', {
|
|
91
|
+
errorName: error instanceof Error ? error.name : 'unknown',
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
await releaseInboundMedia(context, prepared.ownership, error);
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
async outbound(candidate) {
|
|
103
|
+
const input = requireDelivery(candidate);
|
|
104
|
+
const bindings = (await threadMappings(context).listBindings()).filter(item => item.threadId === input.threadId);
|
|
105
|
+
if (bindings.length === 0)
|
|
106
|
+
throw new TypeError(`weixin thread ${input.threadId} has no provider binding`);
|
|
107
|
+
const text = input.envelope.payload.elements.flatMap((element) => {
|
|
108
|
+
if (element.kind === 'text')
|
|
109
|
+
return [element.payload.text];
|
|
110
|
+
const notice = renderTypedMediaNotice(element, {
|
|
111
|
+
elements: input.envelope.payload.elements,
|
|
112
|
+
warnInvalid: elementId => context.log('warn', 'Invalid typed media notice ignored', { elementId }),
|
|
113
|
+
});
|
|
114
|
+
return notice === undefined ? [] : [notice];
|
|
115
|
+
}).join('\n\n');
|
|
116
|
+
const richBlocks = input.envelope.payload.elements.filter(element => element.kind === 'rich_block').map(element => element.payload);
|
|
117
|
+
const media = input.envelope.payload.elements.flatMap((element) => {
|
|
118
|
+
if (element.kind !== 'media_ref' || !object(element.payload))
|
|
119
|
+
return [];
|
|
120
|
+
const type = element.payload.type;
|
|
121
|
+
const reference = element.payload.reference;
|
|
122
|
+
if (!['image', 'file', 'audio', 'video'].includes(String(type)) || typeof reference !== 'string')
|
|
123
|
+
return [];
|
|
124
|
+
return [{ type, reference, ...(typeof element.payload.fileName === 'string' ? { fileName: element.payload.fileName } : {}) }];
|
|
125
|
+
});
|
|
126
|
+
const displayName = input.presentation?.actor.displayName || input.envelope.actor.id;
|
|
127
|
+
const replyPrefix = input.envelope.actor.kind === 'cat' ? `【${displayName}🐱】\n` : '';
|
|
128
|
+
const replyToSender = await replySenders.resolve(input.envelope.replyTo);
|
|
129
|
+
// One thread can carry several provider bindings (the Host allows
|
|
130
|
+
// rebinding different external chats onto the same thread), so the
|
|
131
|
+
// same Host delivery fans out to every binding.
|
|
132
|
+
return {
|
|
133
|
+
replyPrefix,
|
|
134
|
+
inputs: bindings.map(binding => requireConnectorOutboundDelivery({
|
|
135
|
+
deliveryId: input.deliveryId,
|
|
136
|
+
externalConversationId: binding.key,
|
|
137
|
+
presentation: { header: displayName, body: text, origin: input.envelope.actor.kind === 'cat' ? 'agent' : input.envelope.actor.kind === 'system' ? 'system' : 'direct' },
|
|
138
|
+
...(replyToSender === undefined ? {} : { metadata: { replyToSender } }),
|
|
139
|
+
...(richBlocks.length === 0 ? {} : { richBlocks }),
|
|
140
|
+
...(media.length === 0 ? {} : { media }),
|
|
141
|
+
})),
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function optionalString(value, key) {
|
|
147
|
+
if (value === undefined)
|
|
148
|
+
return undefined;
|
|
149
|
+
if (typeof value !== 'string')
|
|
150
|
+
throw new TypeError(`${key} must be a declared string`);
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
function optionalBoolean(value, key) {
|
|
154
|
+
if (value === undefined)
|
|
155
|
+
return undefined;
|
|
156
|
+
if (typeof value !== 'boolean')
|
|
157
|
+
throw new TypeError(`${key} must be a declared boolean`);
|
|
158
|
+
return value;
|
|
159
|
+
}
|
|
160
|
+
function sessionStatePort(context) {
|
|
161
|
+
return {
|
|
162
|
+
async load() {
|
|
163
|
+
const value = (await context.storage.get('provider-session'))?.value;
|
|
164
|
+
return value !== null && typeof value === 'object' ? value : null;
|
|
165
|
+
},
|
|
166
|
+
async save(value) { await context.storage.set('provider-session', value); },
|
|
167
|
+
async clear() { await context.storage.set('provider-session', null); },
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
async function deliverOutbound(outbound, input, context, replyPrefix) {
|
|
171
|
+
const text = [input.presentation.subtitle, input.presentation.body, input.presentation.footer]
|
|
172
|
+
.filter((value) => value !== undefined && value.length > 0)
|
|
173
|
+
.join('\n\n');
|
|
174
|
+
const blocks = [...(input.richBlocks ?? [])];
|
|
175
|
+
await outbound.sendReply(input.externalConversationId, `${replyPrefix}${blocks.length > 0 ? text + '\n\n' + renderAllRichBlocksPlaintext(blocks) : text}`, input.metadata);
|
|
176
|
+
for (const media of input.media ?? []) {
|
|
177
|
+
if (media.type === 'video') {
|
|
178
|
+
await outbound.sendReply(input.externalConversationId, `${replyPrefix}⚠️ 视频附件暂不支持发送`, input.metadata);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (!media.reference.startsWith('hmr_')) {
|
|
182
|
+
await outbound.sendReply(input.externalConversationId, `${replyPrefix}⚠️ 媒体不可用(旧引用无法读取)`, input.metadata);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
await outbound.sendMedia(input.externalConversationId, {
|
|
187
|
+
type: media.type,
|
|
188
|
+
content: context.streams.read(media.reference),
|
|
189
|
+
...(media.fileName === undefined ? {} : { fileName: media.fileName }),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
context.log('warn', 'Weixin outbound media delivery failed', {
|
|
194
|
+
mediaType: media.type,
|
|
195
|
+
errorName: error instanceof Error ? error.name : 'unknown',
|
|
196
|
+
});
|
|
197
|
+
await outbound.sendReply(input.externalConversationId, `${replyPrefix}${error instanceof RangeError ? '⚠️ 媒体过大,超过插件的安全上限 25 MiB' : '⚠️ 媒体不可用(读取或上传失败)'}`, input.metadata);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
export function createWeixinPluginModule(createRuntime = createWeixinConnectorRuntime) {
|
|
202
|
+
const runtimeModule = definePluginModule((manifest) => definePlugin({
|
|
203
|
+
manifest,
|
|
204
|
+
activate: {
|
|
205
|
+
'weixin-messaging': async (context) => {
|
|
206
|
+
let runtime;
|
|
207
|
+
const bridge = await createMessageBridge(context, (input, result) => runtime.outbound.sendReply(input.chatId, result.response));
|
|
208
|
+
const configure = async () => {
|
|
209
|
+
await runtime?.stop();
|
|
210
|
+
const [botToken, voiceItemMode, unsafeModesValue, captureVoiceValue] = await Promise.all([
|
|
211
|
+
context.secrets.get('botToken'),
|
|
212
|
+
context.config.get('voiceItemMode'),
|
|
213
|
+
context.config.get('enableUnsafeVoiceModes'),
|
|
214
|
+
context.config.get('captureInboundVoiceMedia'),
|
|
215
|
+
]);
|
|
216
|
+
const mode = optionalString(voiceItemMode, 'voiceItemMode');
|
|
217
|
+
if (mode !== undefined && !['minimal', 'playtime', 'playtime-sec', 'playtime-encode', 'metadata'].includes(mode)) {
|
|
218
|
+
throw new TypeError('voiceItemMode is not declared by the manifest');
|
|
219
|
+
}
|
|
220
|
+
const unsafeModes = optionalBoolean(unsafeModesValue, 'enableUnsafeVoiceModes');
|
|
221
|
+
const captureVoice = optionalBoolean(captureVoiceValue, 'captureInboundVoiceMedia');
|
|
222
|
+
// Credentials may arrive only later via the weixin_qr_login operation —
|
|
223
|
+
// the runtime starts healthy and idle (no connect, no polling) without them.
|
|
224
|
+
const token = typeof botToken === 'string' ? botToken : '';
|
|
225
|
+
runtime = createRuntime({
|
|
226
|
+
config: {
|
|
227
|
+
botToken: token,
|
|
228
|
+
...(mode === undefined ? {} : { voiceItemMode: mode }),
|
|
229
|
+
...(unsafeModes === undefined ? {} : { enableUnsafeVoiceModes: unsafeModes }),
|
|
230
|
+
...(captureVoice === undefined ? {} : { captureInboundVoiceMedia: captureVoice }),
|
|
231
|
+
},
|
|
232
|
+
state: sessionStatePort(context),
|
|
233
|
+
host: { deliver: bridge.deliver },
|
|
234
|
+
logger: { debug: (...args) => context.log('debug', String(args[0]), { args }), info: (...args) => context.log('info', String(args[0]), { args }), warn: (...args) => context.log('warn', String(args[0]), { args }), error: (...args) => context.log('error', String(args[0]), { args }) },
|
|
235
|
+
});
|
|
236
|
+
await runtime.start();
|
|
237
|
+
};
|
|
238
|
+
await configure();
|
|
239
|
+
const mediaSource = createInboundMediaSource(context, locator => runtime.outbound.downloadInboundMedia(locator));
|
|
240
|
+
return {
|
|
241
|
+
configRefresh: configure,
|
|
242
|
+
streams: mediaSource,
|
|
243
|
+
actions: {
|
|
244
|
+
...createWeixinSettings(context).actions,
|
|
245
|
+
'weixin.test': async () => {
|
|
246
|
+
const ok = runtime.isConnected();
|
|
247
|
+
return { ok, ...(ok ? {} : { message: '微信未连接(需要扫码登录)' }) };
|
|
248
|
+
},
|
|
249
|
+
'weixin.outbound': defineDeliveryAction(async (candidate) => {
|
|
250
|
+
if (candidate.kind === 'execution_status') {
|
|
251
|
+
return { deliveryId: candidate.deliveryId };
|
|
252
|
+
}
|
|
253
|
+
const { inputs, replyPrefix } = await bridge.outbound(candidate);
|
|
254
|
+
// Per-binding isolation: one thread can fan out to several
|
|
255
|
+
// provider bindings, and a failure on one chat must not block
|
|
256
|
+
// or fail the others. A single binding keeps the old fail-fast
|
|
257
|
+
// behavior so the Host redelivers; with several bindings the
|
|
258
|
+
// action only rejects when every binding failed.
|
|
259
|
+
let firstFailure;
|
|
260
|
+
let delivered = 0;
|
|
261
|
+
for (const input of inputs) {
|
|
262
|
+
try {
|
|
263
|
+
await deliverOutbound(runtime.outbound, input, context, replyPrefix);
|
|
264
|
+
delivered += 1;
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
if (firstFailure === undefined)
|
|
268
|
+
firstFailure = error;
|
|
269
|
+
context.log('warn', 'Weixin outbound delivery to one binding failed', {
|
|
270
|
+
externalConversationId: input.externalConversationId,
|
|
271
|
+
errorName: error instanceof Error ? error.name : 'unknown',
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (delivered === 0) {
|
|
276
|
+
if (firstFailure !== undefined)
|
|
277
|
+
throw firstFailure;
|
|
278
|
+
throw new Error('Weixin outbound delivery failed for all bindings (provider did not report an error)');
|
|
279
|
+
}
|
|
280
|
+
return { deliveryId: candidate.deliveryId };
|
|
281
|
+
}),
|
|
282
|
+
},
|
|
283
|
+
dispose: () => runtime.stop(),
|
|
284
|
+
};
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
}));
|
|
288
|
+
return {
|
|
289
|
+
create(manifest) {
|
|
290
|
+
return { ...runtimeModule.create(manifest), settings: host => createWeixinSettings(host) };
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
export default createWeixinPluginModule();
|
|
295
|
+
//# sourceMappingURL=plugin-entrypoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-entrypoint.js","sourceRoot":"","sources":["../src/plugin-entrypoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FeatureContext } from '@clowder-ai/plugin-sdk';
|
|
2
|
+
export interface ReplySender {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly name?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function createReplySenderMap(context: FeatureContext): {
|
|
7
|
+
record(hostMessageId: string, replySender: ReplySender): Promise<void>;
|
|
8
|
+
resolve(hostMessageId: string | undefined): Promise<ReplySender | undefined>;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=reply-sender-map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reply-sender-map.d.ts","sourceRoot":"","sources":["../src/reply-sender-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AA0CD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc;0BAkD5B,MAAM,eAAe,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;2BAgB/C,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;EAmBrF"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
const KEY_PREFIX = 'reply-sender:';
|
|
2
|
+
const ENTRY_TTL_MS = 24 * 60 * 60 * 1000;
|
|
3
|
+
const SWEEP_EVERY_RECORDS = 50;
|
|
4
|
+
const ENTRY_CAP = 2000;
|
|
5
|
+
function object(value) {
|
|
6
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
function errorName(error) {
|
|
9
|
+
return error instanceof Error ? error.name : 'unknown';
|
|
10
|
+
}
|
|
11
|
+
function parseEntry(value) {
|
|
12
|
+
if (typeof value !== 'string')
|
|
13
|
+
return undefined;
|
|
14
|
+
let parsed;
|
|
15
|
+
try {
|
|
16
|
+
parsed = JSON.parse(value);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
if (!object(parsed) || parsed.version !== 1 || typeof parsed.storedAt !== 'number')
|
|
22
|
+
return undefined;
|
|
23
|
+
const candidate = parsed.sender;
|
|
24
|
+
if (!object(candidate) || typeof candidate.id !== 'string' || candidate.id.length === 0)
|
|
25
|
+
return undefined;
|
|
26
|
+
return {
|
|
27
|
+
version: 1,
|
|
28
|
+
storedAt: parsed.storedAt,
|
|
29
|
+
sender: {
|
|
30
|
+
id: candidate.id,
|
|
31
|
+
...(typeof candidate.name === 'string' ? { name: candidate.name } : {}),
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function createReplySenderMap(context) {
|
|
36
|
+
let recordedSinceSweep = 0;
|
|
37
|
+
let sweepInFlight = false;
|
|
38
|
+
const sweep = async () => {
|
|
39
|
+
let listed;
|
|
40
|
+
try {
|
|
41
|
+
listed = await context.storage.list();
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
context.log('warn', 'Connector reply-sender mapping sweep failed', { errorName: errorName(error) });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const now = Date.now();
|
|
48
|
+
const live = [];
|
|
49
|
+
for (const [key, item] of Object.entries(listed)) {
|
|
50
|
+
if (!key.startsWith(KEY_PREFIX))
|
|
51
|
+
continue;
|
|
52
|
+
const entry = parseEntry(item?.value);
|
|
53
|
+
if (entry === undefined || entry.storedAt + ENTRY_TTL_MS < now) {
|
|
54
|
+
await context.storage.delete(key).catch(() => undefined);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
live.push({ key, storedAt: entry.storedAt });
|
|
58
|
+
}
|
|
59
|
+
live.sort((a, b) => a.storedAt - b.storedAt);
|
|
60
|
+
let overflow = live.length - (ENTRY_CAP - 1);
|
|
61
|
+
for (let index = 0; overflow > 0 && index < live.length; index += 1, overflow -= 1) {
|
|
62
|
+
await context.storage.delete(live[index].key).catch(() => undefined);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
// Sweep single-flight in the background: recording stays on the inbound
|
|
66
|
+
// hot path and overlapping bursts never stack sweeps. sweep() already
|
|
67
|
+
// swallows and logs its own storage failures. context.log is intentionally
|
|
68
|
+
// NOT used here: log() runs assertActive() and throws
|
|
69
|
+
// FeatureContextRevokedError after stop/revoke, so a sweep racing feature
|
|
70
|
+
// shutdown would turn into an unhandled rejection; console.warn is the
|
|
71
|
+
// reviewer-sanctioned exception that stays callable past revocation.
|
|
72
|
+
const sweepInBackground = () => {
|
|
73
|
+
if (sweepInFlight)
|
|
74
|
+
return;
|
|
75
|
+
sweepInFlight = true;
|
|
76
|
+
void sweep()
|
|
77
|
+
.catch((error) => {
|
|
78
|
+
console.warn('Connector reply-sender mapping sweep failed', { errorName: errorName(error) });
|
|
79
|
+
})
|
|
80
|
+
.finally(() => {
|
|
81
|
+
sweepInFlight = false;
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
async record(hostMessageId, replySender) {
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
try {
|
|
88
|
+
await context.storage.set(`${KEY_PREFIX}${hostMessageId}`, JSON.stringify({ version: 1, sender: replySender, storedAt: now }));
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
context.log('warn', 'Connector reply-sender mapping record failed', { errorName: errorName(error) });
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
recordedSinceSweep += 1;
|
|
95
|
+
if (recordedSinceSweep < SWEEP_EVERY_RECORDS)
|
|
96
|
+
return;
|
|
97
|
+
recordedSinceSweep = 0;
|
|
98
|
+
sweepInBackground();
|
|
99
|
+
},
|
|
100
|
+
async resolve(hostMessageId) {
|
|
101
|
+
if (hostMessageId === undefined)
|
|
102
|
+
return undefined;
|
|
103
|
+
const key = `${KEY_PREFIX}${hostMessageId}`;
|
|
104
|
+
let stored;
|
|
105
|
+
try {
|
|
106
|
+
stored = await context.storage.get(key);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
context.log('warn', 'Connector reply-sender mapping lookup failed', { errorName: errorName(error) });
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
const entry = parseEntry(stored?.value);
|
|
113
|
+
if (entry === undefined)
|
|
114
|
+
return undefined;
|
|
115
|
+
if (entry.storedAt + ENTRY_TTL_MS < Date.now()) {
|
|
116
|
+
await context.storage.delete(key).catch(() => undefined);
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
return entry.sender;
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=reply-sender-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reply-sender-map.js","sourceRoot":"","sources":["../src/reply-sender-map.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type RichBlockLike = Readonly<Record<string, unknown>>;
|
|
2
|
+
export declare function renderRichBlockPlaintext(block: RichBlockLike): string;
|
|
3
|
+
export declare function renderAllRichBlocksPlaintext(blocks: readonly RichBlockLike[]): string;
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=rich-block-plaintext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-block-plaintext.d.ts","sourceRoot":"","sources":["../src/rich-block-plaintext.ts"],"names":[],"mappings":"AAAA,KAAK,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEvD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAuCrE;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,CAErF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function renderRichBlockPlaintext(block) {
|
|
2
|
+
switch (block.kind) {
|
|
3
|
+
case 'card': {
|
|
4
|
+
const parts = [`📋 ${block.title}`];
|
|
5
|
+
if (block.bodyMarkdown)
|
|
6
|
+
parts.push(String(block.bodyMarkdown));
|
|
7
|
+
if (Array.isArray(block.fields) && block.fields.length > 0) {
|
|
8
|
+
parts.push(block.fields
|
|
9
|
+
.map((field) => ` ${field.label}: ${field.value}`)
|
|
10
|
+
.join('\n'));
|
|
11
|
+
}
|
|
12
|
+
return parts.join('\n');
|
|
13
|
+
}
|
|
14
|
+
case 'checklist': {
|
|
15
|
+
const header = block.title ? `☑️ ${block.title}` : '☑️ Checklist';
|
|
16
|
+
const items = Array.isArray(block.items)
|
|
17
|
+
? block.items
|
|
18
|
+
.map((item) => `${item.checked ? '✅' : '☐'} ${item.text}`)
|
|
19
|
+
.join('\n')
|
|
20
|
+
: '';
|
|
21
|
+
return `${header}\n${items}`;
|
|
22
|
+
}
|
|
23
|
+
case 'diff':
|
|
24
|
+
return `📝 ${block.filePath}\n\`\`\`\n${block.diff}\n\`\`\``;
|
|
25
|
+
case 'audio':
|
|
26
|
+
return block.text ? `🔊 ${block.text}` : `🔊 [Audio: ${block.url}]`;
|
|
27
|
+
case 'media_gallery': {
|
|
28
|
+
const header = block.title ? `🖼️ ${block.title}` : '🖼️ Gallery';
|
|
29
|
+
const items = Array.isArray(block.items)
|
|
30
|
+
? block.items
|
|
31
|
+
.map((item) => item.caption
|
|
32
|
+
|| item.alt
|
|
33
|
+
|| item.url)
|
|
34
|
+
.join('\n')
|
|
35
|
+
: '';
|
|
36
|
+
return `${header}\n${items}`;
|
|
37
|
+
}
|
|
38
|
+
default:
|
|
39
|
+
return `[${block.kind}]`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function renderAllRichBlocksPlaintext(blocks) {
|
|
43
|
+
return blocks.map(renderRichBlockPlaintext).join('\n\n');
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=rich-block-plaintext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-block-plaintext.js","sourceRoot":"","sources":["../src/rich-block-plaintext.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,wBAAwB,CAAC,KAAoB;IAC3D,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,KAAK,GAAG,CAAC,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YACpC,IAAI,KAAK,CAAC,YAAY;gBAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;YAC/D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3D,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;qBACpB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAM,KAAiC,CAAC,KAAK,KAAM,KAAiC,CAAC,KAAK,EAAE,CAAC;qBAC5G,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACjB,CAAC;YACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QACD,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC;YAClE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;gBACtC,CAAC,CAAC,KAAK,CAAC,KAAK;qBACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAI,IAAgC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAK,IAAgC,CAAC,IAAI,EAAE,CAAC;qBACnH,IAAI,CAAC,IAAI,CAAC;gBACb,CAAC,CAAC,EAAE,CAAC;YACP,OAAO,GAAG,MAAM,KAAK,KAAK,EAAE,CAAC;QAC/B,CAAC;QACD,KAAK,MAAM;YACT,OAAO,MAAM,KAAK,CAAC,QAAQ,aAAa,KAAK,CAAC,IAAI,UAAU,CAAC;QAC/D,KAAK,OAAO;YACV,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,cAAc,KAAK,CAAC,GAAG,GAAG,CAAC;QACtE,KAAK,eAAe,CAAC,CAAC,CAAC;YACrB,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;YAClE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;gBACtC,CAAC,CAAC,KAAK,CAAC,KAAK;qBACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAE,IAAgC,CAAC,OAAO;uBAClD,IAAgC,CAAC,GAAG;uBACpC,IAAgC,CAAC,GAAG,CAAC;qBAC1C,IAAI,CAAC,IAAI,CAAC;gBACb,CAAC,CAAC,EAAE,CAAC;YACP,OAAO,GAAG,MAAM,KAAK,KAAK,EAAE,CAAC;QAC/B,CAAC;QACD;YACE,OAAO,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;IAC7B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,MAAgC;IAC3E,OAAO,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { WeixinAdapter, type WeixinInboundMessage, type WeixinRuntimeOptions, type WeixinSessionStateStore } from './WeixinAdapter.js';
|
|
2
|
+
import type { ConnectorLogger } from './types.js';
|
|
3
|
+
export interface WeixinRuntimeConfig extends WeixinRuntimeOptions {
|
|
4
|
+
readonly botToken: string;
|
|
5
|
+
}
|
|
6
|
+
export interface WeixinHostInboundMessage {
|
|
7
|
+
readonly externalConversationId: string;
|
|
8
|
+
readonly externalSenderId: string;
|
|
9
|
+
readonly providerMessageId: string;
|
|
10
|
+
readonly text: string;
|
|
11
|
+
readonly attachments?: readonly Readonly<{
|
|
12
|
+
type: 'image' | 'file' | 'audio';
|
|
13
|
+
platformKey: string;
|
|
14
|
+
fileName?: string;
|
|
15
|
+
}>[];
|
|
16
|
+
}
|
|
17
|
+
export interface WeixinRuntimeHost {
|
|
18
|
+
deliver(message: WeixinHostInboundMessage): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export interface WeixinRuntimeAdapter {
|
|
21
|
+
readonly connectorId: string;
|
|
22
|
+
restoreSessionState(): Promise<void>;
|
|
23
|
+
startPolling(handler: (message: WeixinInboundMessage) => Promise<void>): void | Promise<void>;
|
|
24
|
+
stopPolling(): Promise<void>;
|
|
25
|
+
hasBotToken(): boolean;
|
|
26
|
+
isPolling(): boolean;
|
|
27
|
+
setBotToken(token: string): void;
|
|
28
|
+
disconnect(): Promise<void>;
|
|
29
|
+
sendReply: WeixinAdapter['sendReply'];
|
|
30
|
+
sendMedia: WeixinAdapter['sendMedia'];
|
|
31
|
+
}
|
|
32
|
+
export interface WeixinConnectorRuntime<Adapter extends WeixinRuntimeAdapter = WeixinAdapter> {
|
|
33
|
+
readonly outbound: Adapter;
|
|
34
|
+
start(): Promise<void>;
|
|
35
|
+
stop(): Promise<void>;
|
|
36
|
+
/** Adopt a bot token in-process and begin polling (idles until the runtime is started). */
|
|
37
|
+
connect(botToken: string): Promise<void>;
|
|
38
|
+
/** Stop polling and drop the connection in-process (bot token and session cleared). */
|
|
39
|
+
disconnect(): Promise<void>;
|
|
40
|
+
/** True when a bot token is adopted and provider polling is live. */
|
|
41
|
+
isConnected(): boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface WeixinConnectorRuntimeOptions<Adapter extends WeixinRuntimeAdapter = WeixinAdapter> {
|
|
44
|
+
readonly config: WeixinRuntimeConfig;
|
|
45
|
+
readonly state: WeixinSessionStateStore;
|
|
46
|
+
readonly host: WeixinRuntimeHost;
|
|
47
|
+
readonly logger: ConnectorLogger;
|
|
48
|
+
readonly createAdapter?: (botToken: string, logger: ConnectorLogger, state: WeixinSessionStateStore, runtimeOptions: WeixinRuntimeOptions) => Adapter;
|
|
49
|
+
}
|
|
50
|
+
export declare function createWeixinConnectorRuntime<Adapter extends WeixinRuntimeAdapter = WeixinAdapter>(options: WeixinConnectorRuntimeOptions<Adapter>): WeixinConnectorRuntime<Adapter>;
|
|
51
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,mBAAoB,SAAQ,oBAAoB;IAC/D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,QAAQ,CAAC;QACvC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;QACjC,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC,EAAE,CAAC;CACN;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,YAAY,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9F,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,WAAW,IAAI,OAAO,CAAC;IACvB,SAAS,IAAI,OAAO,CAAC;IACrB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,SAAS,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IACtC,SAAS,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,sBAAsB,CAAC,OAAO,SAAS,oBAAoB,GAAG,aAAa;IAC1F,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,2FAA2F;IAC3F,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,uFAAuF;IACvF,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,qEAAqE;IACrE,WAAW,IAAI,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,6BAA6B,CAAC,OAAO,SAAS,oBAAoB,GAAG,aAAa;IACjG,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,CACvB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,uBAAuB,EAC9B,cAAc,EAAE,oBAAoB,KACjC,OAAO,CAAC;CACd;AAiBD,wBAAgB,4BAA4B,CAAC,OAAO,SAAS,oBAAoB,GAAG,aAAa,EAC/F,OAAO,EAAE,6BAA6B,CAAC,OAAO,CAAC,GAC9C,sBAAsB,CAAC,OAAO,CAAC,CAyHjC"}
|