@xpert-ai/plugin-community-wechat 0.1.0
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 +353 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +139 -0
- package/dist/lib/constants.d.ts +23 -0
- package/dist/lib/constants.js +23 -0
- package/dist/lib/conversation-user-key.d.ts +13 -0
- package/dist/lib/conversation-user-key.js +28 -0
- package/dist/lib/conversation.service.d.ts +215 -0
- package/dist/lib/conversation.service.js +1179 -0
- package/dist/lib/decorators.d.ts +2 -0
- package/dist/lib/decorators.js +3 -0
- package/dist/lib/entities/index.d.ts +4 -0
- package/dist/lib/entities/index.js +4 -0
- package/dist/lib/entities/wechat-personal-account.entity.d.ts +19 -0
- package/dist/lib/entities/wechat-personal-account.entity.js +83 -0
- package/dist/lib/entities/wechat-personal-conversation-binding.entity.d.ts +14 -0
- package/dist/lib/entities/wechat-personal-conversation-binding.entity.js +65 -0
- package/dist/lib/entities/wechat-personal-message-log.entity.d.ts +27 -0
- package/dist/lib/entities/wechat-personal-message-log.entity.js +108 -0
- package/dist/lib/entities/wechat-personal-trigger-binding.entity.d.ts +17 -0
- package/dist/lib/entities/wechat-personal-trigger-binding.entity.js +71 -0
- package/dist/lib/handoff/index.d.ts +4 -0
- package/dist/lib/handoff/index.js +4 -0
- package/dist/lib/handoff/wechat-personal-chat-callback.processor.d.ts +26 -0
- package/dist/lib/handoff/wechat-personal-chat-callback.processor.js +312 -0
- package/dist/lib/handoff/wechat-personal-chat-dispatch.service.d.ts +26 -0
- package/dist/lib/handoff/wechat-personal-chat-dispatch.service.js +187 -0
- package/dist/lib/handoff/wechat-personal-chat-run-state.service.d.ts +21 -0
- package/dist/lib/handoff/wechat-personal-chat-run-state.service.js +39 -0
- package/dist/lib/handoff/wechat-personal-chat.types.d.ts +69 -0
- package/dist/lib/handoff/wechat-personal-chat.types.js +2 -0
- package/dist/lib/message.d.ts +49 -0
- package/dist/lib/message.js +64 -0
- package/dist/lib/remote-components/wechat-personal-workbench/app.js +1831 -0
- package/dist/lib/tokens.d.ts +1 -0
- package/dist/lib/tokens.js +1 -0
- package/dist/lib/types.d.ts +48 -0
- package/dist/lib/types.js +365 -0
- package/dist/lib/views/wechat-personal-view.provider.d.ts +17 -0
- package/dist/lib/views/wechat-personal-view.provider.js +441 -0
- package/dist/lib/wechat-personal-channel.strategy.d.ts +33 -0
- package/dist/lib/wechat-personal-channel.strategy.js +197 -0
- package/dist/lib/wechat-personal-integration.strategy.d.ts +56 -0
- package/dist/lib/wechat-personal-integration.strategy.js +217 -0
- package/dist/lib/wechat-personal.client.d.ts +29 -0
- package/dist/lib/wechat-personal.client.js +146 -0
- package/dist/lib/wechat-personal.controller.d.ts +50 -0
- package/dist/lib/wechat-personal.controller.js +270 -0
- package/dist/lib/wechat-personal.middleware.d.ts +20 -0
- package/dist/lib/wechat-personal.middleware.js +267 -0
- package/dist/lib/wechat-personal.plugin.d.ts +2 -0
- package/dist/lib/wechat-personal.plugin.js +58 -0
- package/dist/lib/wechat-personal.templates.d.ts +2 -0
- package/dist/lib/wechat-personal.templates.js +100 -0
- package/dist/lib/workflow/index.d.ts +5 -0
- package/dist/lib/workflow/index.js +5 -0
- package/dist/lib/workflow/wechat-personal-trigger-aggregation.service.d.ts +10 -0
- package/dist/lib/workflow/wechat-personal-trigger-aggregation.service.js +39 -0
- package/dist/lib/workflow/wechat-personal-trigger-aggregation.types.d.ts +30 -0
- package/dist/lib/workflow/wechat-personal-trigger-aggregation.types.js +2 -0
- package/dist/lib/workflow/wechat-personal-trigger-flush.processor.d.ts +8 -0
- package/dist/lib/workflow/wechat-personal-trigger-flush.processor.js +39 -0
- package/dist/lib/workflow/wechat-personal-trigger.strategy.d.ts +65 -0
- package/dist/lib/workflow/wechat-personal-trigger.strategy.js +511 -0
- package/dist/lib/workflow/wechat-personal-trigger.types.d.ts +10 -0
- package/dist/lib/workflow/wechat-personal-trigger.types.js +2 -0
- package/dist/xpert-wechat-personal-admin-assistant.yaml +103 -0
- package/dist/xpert-wechat-personal-user-assistant.yaml +127 -0
- package/package.json +79 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { IIntegration, TIntegrationProvider } from '@xpert-ai/contracts';
|
|
2
|
+
import { IntegrationStrategy, TIntegrationStrategyParams } from '@xpert-ai/plugin-sdk';
|
|
3
|
+
import { TIntegrationWechatPersonalOptions } from './types.js';
|
|
4
|
+
export declare const WECHAT_PERSONAL_CALLBACK_HINTS: readonly ["推荐:wx2.0 config webhook.allMessagePushUrl / AllMsgPushUrl 指向 Xpert webhook URL", "兼容:对单个账号调用 /message/SetCallback?key=<uuid> 设置 CallbackURL", "消息回复:Xpert 插件调用 wx2.0 /v1/message/sendtext,失败时可回退旧接口"];
|
|
5
|
+
type WechatPersonalIntegrationViewExtensionMeta = {
|
|
6
|
+
key: string;
|
|
7
|
+
provider: string;
|
|
8
|
+
plugin: string;
|
|
9
|
+
hostType: 'integration';
|
|
10
|
+
slot: 'detail.main_tabs';
|
|
11
|
+
viewType: 'remote_component';
|
|
12
|
+
runtime: 'react';
|
|
13
|
+
entry: string;
|
|
14
|
+
};
|
|
15
|
+
type WechatPersonalIntegrationProviderMeta = TIntegrationProvider & {
|
|
16
|
+
targetApps?: string[];
|
|
17
|
+
targetAppMeta?: {
|
|
18
|
+
'data-xpert'?: {
|
|
19
|
+
types?: string[];
|
|
20
|
+
capabilities?: string[];
|
|
21
|
+
runtime?: {
|
|
22
|
+
viewProviders?: string[];
|
|
23
|
+
};
|
|
24
|
+
extensions?: {
|
|
25
|
+
views?: WechatPersonalIntegrationViewExtensionMeta[];
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
extensions?: {
|
|
30
|
+
views?: WechatPersonalIntegrationViewExtensionMeta[];
|
|
31
|
+
};
|
|
32
|
+
extensionViews?: WechatPersonalIntegrationViewExtensionMeta[];
|
|
33
|
+
};
|
|
34
|
+
export declare class WechatPersonalIntegrationStrategy implements IntegrationStrategy<TIntegrationWechatPersonalOptions> {
|
|
35
|
+
readonly meta: WechatPersonalIntegrationProviderMeta;
|
|
36
|
+
execute(_integration: IIntegration<TIntegrationWechatPersonalOptions>, _payload: TIntegrationStrategyParams): Promise<any>;
|
|
37
|
+
validateConfig(config: TIntegrationWechatPersonalOptions, integration?: IIntegration<TIntegrationWechatPersonalOptions>): Promise<{
|
|
38
|
+
webhookUrl: string;
|
|
39
|
+
callback: {
|
|
40
|
+
mode: string;
|
|
41
|
+
callbackUrl: string;
|
|
42
|
+
globalWebhookConfigKeys: string[];
|
|
43
|
+
setCallback: {
|
|
44
|
+
method: string;
|
|
45
|
+
urlTemplate: string;
|
|
46
|
+
body: {
|
|
47
|
+
CallbackURL: string;
|
|
48
|
+
Enabled: boolean;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
expectedAckMs: number;
|
|
52
|
+
subscriptionHints: ("推荐:wx2.0 config webhook.allMessagePushUrl / AllMsgPushUrl 指向 Xpert webhook URL" | "兼容:对单个账号调用 /message/SetCallback?key=<uuid> 设置 CallbackURL" | "消息回复:Xpert 插件调用 wx2.0 /v1/message/sendtext,失败时可回退旧接口")[];
|
|
53
|
+
};
|
|
54
|
+
}>;
|
|
55
|
+
}
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Injectable } from '@nestjs/common';
|
|
8
|
+
import { IntegrationStrategyKey } from '@xpert-ai/plugin-sdk';
|
|
9
|
+
import { WECHAT_PERSONAL_FEATURE, WECHAT_PERSONAL_ICON, WECHAT_PERSONAL_PLUGIN_NAME, WECHAT_PERSONAL_PROVIDER_KEY, WECHAT_PERSONAL_REMOTE_ENTRY_KEY, WECHAT_PERSONAL_RUNTIME_FEATURE, WECHAT_PERSONAL_VIEW_KEY, WECHAT_PERSONAL_VIEW_PROVIDER_KEY, WECHAT_PERSONAL_WORKBENCH_FEATURE } from './constants.js';
|
|
10
|
+
import { normalizeApiVersion, normalizeBaseUrl, normalizeGroupTriggerMode, normalizeKeywords, normalizeTimeoutMs } from './types.js';
|
|
11
|
+
export const WECHAT_PERSONAL_CALLBACK_HINTS = [
|
|
12
|
+
'推荐:wx2.0 config webhook.allMessagePushUrl / AllMsgPushUrl 指向 Xpert webhook URL',
|
|
13
|
+
'兼容:对单个账号调用 /message/SetCallback?key=<uuid> 设置 CallbackURL',
|
|
14
|
+
'消息回复:Xpert 插件调用 wx2.0 /v1/message/sendtext,失败时可回退旧接口'
|
|
15
|
+
];
|
|
16
|
+
const WECHAT_PERSONAL_INTEGRATION_VIEW_EXTENSION = {
|
|
17
|
+
key: WECHAT_PERSONAL_VIEW_KEY,
|
|
18
|
+
provider: WECHAT_PERSONAL_VIEW_PROVIDER_KEY,
|
|
19
|
+
plugin: WECHAT_PERSONAL_PLUGIN_NAME,
|
|
20
|
+
hostType: 'integration',
|
|
21
|
+
slot: 'detail.main_tabs',
|
|
22
|
+
viewType: 'remote_component',
|
|
23
|
+
runtime: 'react',
|
|
24
|
+
entry: WECHAT_PERSONAL_REMOTE_ENTRY_KEY
|
|
25
|
+
};
|
|
26
|
+
let WechatPersonalIntegrationStrategy = class WechatPersonalIntegrationStrategy {
|
|
27
|
+
constructor() {
|
|
28
|
+
this.meta = {
|
|
29
|
+
name: WECHAT_PERSONAL_PROVIDER_KEY,
|
|
30
|
+
label: {
|
|
31
|
+
en_US: 'Personal WeChat (wx2.0)',
|
|
32
|
+
zh_Hans: '个人微信 wx2.0'
|
|
33
|
+
},
|
|
34
|
+
icon: {
|
|
35
|
+
type: 'svg',
|
|
36
|
+
value: WECHAT_PERSONAL_ICON
|
|
37
|
+
},
|
|
38
|
+
description: {
|
|
39
|
+
en_US: 'Bridge wx2.0 personal WeChat webhooks and outbound text replies to Xpert agents.',
|
|
40
|
+
zh_Hans: '连接 wx2.0 个人微信 webhook 与 Xpert Agent 文本回复。'
|
|
41
|
+
},
|
|
42
|
+
targetApps: ['data-xpert'],
|
|
43
|
+
targetAppMeta: {
|
|
44
|
+
'data-xpert': {
|
|
45
|
+
types: ['integration', 'workbench-view'],
|
|
46
|
+
capabilities: [WECHAT_PERSONAL_FEATURE, WECHAT_PERSONAL_RUNTIME_FEATURE, WECHAT_PERSONAL_WORKBENCH_FEATURE],
|
|
47
|
+
runtime: {
|
|
48
|
+
viewProviders: [WECHAT_PERSONAL_VIEW_PROVIDER_KEY]
|
|
49
|
+
},
|
|
50
|
+
extensions: {
|
|
51
|
+
views: [WECHAT_PERSONAL_INTEGRATION_VIEW_EXTENSION]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
extensions: {
|
|
56
|
+
views: [WECHAT_PERSONAL_INTEGRATION_VIEW_EXTENSION]
|
|
57
|
+
},
|
|
58
|
+
extensionViews: [WECHAT_PERSONAL_INTEGRATION_VIEW_EXTENSION],
|
|
59
|
+
webhook: true,
|
|
60
|
+
schema: {
|
|
61
|
+
type: 'object',
|
|
62
|
+
properties: {
|
|
63
|
+
baseUrl: {
|
|
64
|
+
type: 'string',
|
|
65
|
+
title: {
|
|
66
|
+
en_US: 'wx2.0 Base URL',
|
|
67
|
+
zh_Hans: 'wx2.0 服务地址'
|
|
68
|
+
},
|
|
69
|
+
description: {
|
|
70
|
+
en_US: 'Example: http://127.0.0.1:8058',
|
|
71
|
+
zh_Hans: '例如:http://127.0.0.1:8058'
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
apiVersion: {
|
|
75
|
+
type: 'string',
|
|
76
|
+
title: {
|
|
77
|
+
en_US: 'API Version Prefix',
|
|
78
|
+
zh_Hans: 'API 版本前缀'
|
|
79
|
+
},
|
|
80
|
+
default: '/v1/'
|
|
81
|
+
},
|
|
82
|
+
timeoutMs: {
|
|
83
|
+
type: 'number',
|
|
84
|
+
title: {
|
|
85
|
+
en_US: 'Request Timeout (ms)',
|
|
86
|
+
zh_Hans: '请求超时(毫秒)'
|
|
87
|
+
},
|
|
88
|
+
default: 10000
|
|
89
|
+
},
|
|
90
|
+
apiToken: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
title: {
|
|
93
|
+
en_US: 'API Token',
|
|
94
|
+
zh_Hans: 'API Token'
|
|
95
|
+
},
|
|
96
|
+
description: {
|
|
97
|
+
en_US: 'Optional token header reserved for wx2.0 TokenAuth.',
|
|
98
|
+
zh_Hans: '可选,作为 token header 发送,兼容后续 wx2.0 TokenAuth。'
|
|
99
|
+
},
|
|
100
|
+
'x-ui': {
|
|
101
|
+
component: 'password'
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
preferLanguage: {
|
|
105
|
+
type: 'string',
|
|
106
|
+
title: {
|
|
107
|
+
en_US: 'Preferred Language',
|
|
108
|
+
zh_Hans: '首选语言'
|
|
109
|
+
},
|
|
110
|
+
enum: ['en', 'zh-Hans'],
|
|
111
|
+
default: 'zh-Hans'
|
|
112
|
+
},
|
|
113
|
+
callbackSecret: {
|
|
114
|
+
type: 'string',
|
|
115
|
+
title: {
|
|
116
|
+
en_US: 'Callback Secret',
|
|
117
|
+
zh_Hans: '回调密钥'
|
|
118
|
+
},
|
|
119
|
+
description: {
|
|
120
|
+
en_US: 'Optional secret passed by query secret or x-wechat-callback-secret header.',
|
|
121
|
+
zh_Hans: '可选,通过 query secret 或 x-wechat-callback-secret header 校验。'
|
|
122
|
+
},
|
|
123
|
+
'x-ui': {
|
|
124
|
+
component: 'password'
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
groupTriggerMode: {
|
|
128
|
+
type: 'string',
|
|
129
|
+
title: {
|
|
130
|
+
en_US: 'Group Trigger Mode',
|
|
131
|
+
zh_Hans: '群聊触发方式'
|
|
132
|
+
},
|
|
133
|
+
enum: ['mention_or_keywords', 'all', 'mentions', 'keywords', 'off'],
|
|
134
|
+
default: 'mention_or_keywords'
|
|
135
|
+
},
|
|
136
|
+
groupKeywords: {
|
|
137
|
+
type: 'array',
|
|
138
|
+
title: {
|
|
139
|
+
en_US: 'Group Keywords',
|
|
140
|
+
zh_Hans: '群聊关键词'
|
|
141
|
+
},
|
|
142
|
+
items: {
|
|
143
|
+
type: 'string'
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
ignoreSelfMessages: {
|
|
147
|
+
type: 'boolean',
|
|
148
|
+
title: {
|
|
149
|
+
en_US: 'Ignore Self Messages',
|
|
150
|
+
zh_Hans: '忽略自己发出的消息'
|
|
151
|
+
},
|
|
152
|
+
default: true
|
|
153
|
+
},
|
|
154
|
+
fallbackToLegacySendText: {
|
|
155
|
+
type: 'boolean',
|
|
156
|
+
title: {
|
|
157
|
+
en_US: 'Fallback to Legacy SendText',
|
|
158
|
+
zh_Hans: '失败时回退旧发送接口'
|
|
159
|
+
},
|
|
160
|
+
default: true
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
required: ['baseUrl'],
|
|
164
|
+
secret: ['apiToken', 'callbackSecret']
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
async execute(_integration, _payload) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
async validateConfig(config, integration) {
|
|
172
|
+
const baseUrl = normalizeBaseUrl(config?.baseUrl);
|
|
173
|
+
if (!baseUrl) {
|
|
174
|
+
throw new Error('wx2.0 baseUrl is required');
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
new URL(baseUrl);
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
throw new Error('wx2.0 baseUrl must be a valid URL');
|
|
181
|
+
}
|
|
182
|
+
config.apiVersion = normalizeApiVersion(config.apiVersion);
|
|
183
|
+
config.timeoutMs = normalizeTimeoutMs(config.timeoutMs);
|
|
184
|
+
config.groupTriggerMode = normalizeGroupTriggerMode(config.groupTriggerMode);
|
|
185
|
+
config.groupKeywords = normalizeKeywords(config.groupKeywords);
|
|
186
|
+
config.ignoreSelfMessages = config.ignoreSelfMessages !== false;
|
|
187
|
+
config.fallbackToLegacySendText = config.fallbackToLegacySendText !== false;
|
|
188
|
+
const apiBaseUrl = (process.env.API_BASE_URL || '').replace(/\/+$/, '');
|
|
189
|
+
const integrationId = integration?.id || '<save_and_get_your_integration_id>';
|
|
190
|
+
const callbackSecret = config.callbackSecret?.trim();
|
|
191
|
+
const callbackUrl = `${apiBaseUrl}/api/wechat-personal/webhook/${integrationId}${callbackSecret ? `?secret=${encodeURIComponent(callbackSecret)}` : ''}`;
|
|
192
|
+
const redactedCallbackUrl = `${apiBaseUrl}/api/wechat-personal/webhook/${integrationId}${callbackSecret ? '?secret=***' : ''}`;
|
|
193
|
+
return {
|
|
194
|
+
webhookUrl: callbackUrl,
|
|
195
|
+
callback: {
|
|
196
|
+
mode: 'http',
|
|
197
|
+
callbackUrl,
|
|
198
|
+
globalWebhookConfigKeys: ['webhook.allMessagePushUrl', 'AllMsgPushUrl'],
|
|
199
|
+
setCallback: {
|
|
200
|
+
method: 'POST',
|
|
201
|
+
urlTemplate: `${baseUrl}/message/SetCallback?key=<uuid>`,
|
|
202
|
+
body: {
|
|
203
|
+
CallbackURL: redactedCallbackUrl,
|
|
204
|
+
Enabled: true
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
expectedAckMs: 1500,
|
|
208
|
+
subscriptionHints: [...WECHAT_PERSONAL_CALLBACK_HINTS]
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
WechatPersonalIntegrationStrategy = __decorate([
|
|
214
|
+
Injectable(),
|
|
215
|
+
IntegrationStrategyKey(WECHAT_PERSONAL_PROVIDER_KEY)
|
|
216
|
+
], WechatPersonalIntegrationStrategy);
|
|
217
|
+
export { WechatPersonalIntegrationStrategy };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { IIntegration } from '@xpert-ai/contracts';
|
|
2
|
+
import { TIntegrationWechatPersonalOptions } from './types.js';
|
|
3
|
+
export interface WechatPersonalSendTextInput {
|
|
4
|
+
uuid: string;
|
|
5
|
+
contactId: string;
|
|
6
|
+
content: string;
|
|
7
|
+
atUsers?: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface WechatPersonalSendResult {
|
|
10
|
+
success: boolean;
|
|
11
|
+
messageId?: string;
|
|
12
|
+
error?: string;
|
|
13
|
+
raw?: unknown;
|
|
14
|
+
}
|
|
15
|
+
export declare class WechatPersonalClient {
|
|
16
|
+
sendText(integration: IIntegration<TIntegrationWechatPersonalOptions>, input: WechatPersonalSendTextInput): Promise<WechatPersonalSendResult>;
|
|
17
|
+
registerCallback(params: {
|
|
18
|
+
integration: IIntegration<TIntegrationWechatPersonalOptions>;
|
|
19
|
+
uuid: string;
|
|
20
|
+
callbackUrl: string;
|
|
21
|
+
enabled?: boolean;
|
|
22
|
+
}): Promise<WechatPersonalSendResult>;
|
|
23
|
+
private buildV2Url;
|
|
24
|
+
private postJson;
|
|
25
|
+
private readPayload;
|
|
26
|
+
private resolveResponseCode;
|
|
27
|
+
private resolveResponseText;
|
|
28
|
+
private resolveMessageId;
|
|
29
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Injectable } from '@nestjs/common';
|
|
8
|
+
import { normalizeApiVersion, normalizeBaseUrl, normalizeString, normalizeTimeoutMs } from './types.js';
|
|
9
|
+
let WechatPersonalClient = class WechatPersonalClient {
|
|
10
|
+
async sendText(integration, input) {
|
|
11
|
+
const options = integration.options || {};
|
|
12
|
+
const primary = await this.postJson(integration, this.buildV2Url(options, 'message/sendtext'), {
|
|
13
|
+
uuid: input.uuid,
|
|
14
|
+
contactid: input.contactId,
|
|
15
|
+
textcontent: input.content,
|
|
16
|
+
atusers: input.atUsers ?? []
|
|
17
|
+
});
|
|
18
|
+
if (primary.success || options.fallbackToLegacySendText === false) {
|
|
19
|
+
return primary;
|
|
20
|
+
}
|
|
21
|
+
const legacy = await this.postJson(integration, `${normalizeBaseUrl(options.baseUrl)}/message/SendTextMessage?key=${encodeURIComponent(input.uuid)}`, {
|
|
22
|
+
MsgItem: [
|
|
23
|
+
{
|
|
24
|
+
ToUserName: input.contactId,
|
|
25
|
+
TextContent: input.content,
|
|
26
|
+
MsgType: 1,
|
|
27
|
+
AtWxIDList: input.atUsers ?? []
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
});
|
|
31
|
+
if (!legacy.success) {
|
|
32
|
+
return {
|
|
33
|
+
...legacy,
|
|
34
|
+
error: `${primary.error || 'primary send failed'}; fallback: ${legacy.error || 'legacy send failed'}`
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return legacy;
|
|
38
|
+
}
|
|
39
|
+
async registerCallback(params) {
|
|
40
|
+
const baseUrl = normalizeBaseUrl(params.integration.options?.baseUrl);
|
|
41
|
+
return this.postJson(params.integration, `${baseUrl}/message/SetCallback?key=${encodeURIComponent(params.uuid)}`, {
|
|
42
|
+
CallbackURL: params.callbackUrl,
|
|
43
|
+
Enabled: params.enabled !== false
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
buildV2Url(options, path) {
|
|
47
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl);
|
|
48
|
+
const apiVersion = normalizeApiVersion(options.apiVersion);
|
|
49
|
+
return `${baseUrl}${apiVersion}${path.replace(/^\/+/, '')}`;
|
|
50
|
+
}
|
|
51
|
+
async postJson(integration, url, body) {
|
|
52
|
+
const options = integration.options || {};
|
|
53
|
+
if (!normalizeBaseUrl(options.baseUrl)) {
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
error: 'wx2.0 baseUrl is required'
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const controller = new AbortController();
|
|
60
|
+
const timer = setTimeout(() => controller.abort(), normalizeTimeoutMs(options.timeoutMs));
|
|
61
|
+
try {
|
|
62
|
+
const headers = {
|
|
63
|
+
'Content-Type': 'application/json'
|
|
64
|
+
};
|
|
65
|
+
const token = normalizeString(options.apiToken);
|
|
66
|
+
if (token) {
|
|
67
|
+
headers.token = token;
|
|
68
|
+
}
|
|
69
|
+
const response = await fetch(url, {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers,
|
|
72
|
+
body: JSON.stringify(body),
|
|
73
|
+
signal: controller.signal
|
|
74
|
+
});
|
|
75
|
+
const payload = await this.readPayload(response);
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
error: `wx2.0 HTTP ${response.status}`,
|
|
80
|
+
raw: payload
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const code = this.resolveResponseCode(payload);
|
|
84
|
+
if (typeof code === 'number' && code !== 0 && code !== 200) {
|
|
85
|
+
return {
|
|
86
|
+
success: false,
|
|
87
|
+
error: this.resolveResponseText(payload) || `wx2.0 returned code ${code}`,
|
|
88
|
+
raw: payload
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
success: true,
|
|
93
|
+
messageId: this.resolveMessageId(payload),
|
|
94
|
+
raw: payload
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
return {
|
|
99
|
+
success: false,
|
|
100
|
+
error: error instanceof Error ? error.message : String(error)
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
clearTimeout(timer);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async readPayload(response) {
|
|
108
|
+
const text = await response.text().catch(() => '');
|
|
109
|
+
if (!text) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
return JSON.parse(text);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return text;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
resolveResponseCode(payload) {
|
|
120
|
+
if (!payload || typeof payload !== 'object') {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
const record = payload;
|
|
124
|
+
const value = record.code ?? record.Code;
|
|
125
|
+
return typeof value === 'number' ? value : undefined;
|
|
126
|
+
}
|
|
127
|
+
resolveResponseText(payload) {
|
|
128
|
+
if (!payload || typeof payload !== 'object') {
|
|
129
|
+
return typeof payload === 'string' ? payload : undefined;
|
|
130
|
+
}
|
|
131
|
+
const record = payload;
|
|
132
|
+
return normalizeString(record.text || record.Text || record.message || record.Message) || undefined;
|
|
133
|
+
}
|
|
134
|
+
resolveMessageId(payload) {
|
|
135
|
+
if (!payload || typeof payload !== 'object') {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
const record = payload;
|
|
139
|
+
const data = record.data && typeof record.data === 'object' ? record.data : record;
|
|
140
|
+
return normalizeString(data.newmsgid || data.newMsgId || data.messageId || data.msgid) || undefined;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
WechatPersonalClient = __decorate([
|
|
144
|
+
Injectable()
|
|
145
|
+
], WechatPersonalClient);
|
|
146
|
+
export { WechatPersonalClient };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type PluginContext } from '@xpert-ai/plugin-sdk';
|
|
2
|
+
import { WechatPersonalConversationService } from './conversation.service.js';
|
|
3
|
+
import { WechatPersonalChannelStrategy } from './wechat-personal-channel.strategy.js';
|
|
4
|
+
type HttpRequestLike = {
|
|
5
|
+
user?: unknown;
|
|
6
|
+
protocol?: string;
|
|
7
|
+
headers?: Record<string, unknown>;
|
|
8
|
+
get?: (name: string) => string | undefined;
|
|
9
|
+
};
|
|
10
|
+
export declare class WechatPersonalController {
|
|
11
|
+
private readonly conversation;
|
|
12
|
+
private readonly wechatChannel;
|
|
13
|
+
private readonly pluginContext;
|
|
14
|
+
private _integrationPermissionService;
|
|
15
|
+
constructor(conversation: WechatPersonalConversationService, wechatChannel: WechatPersonalChannelStrategy, pluginContext: PluginContext);
|
|
16
|
+
private get integrationPermissionService();
|
|
17
|
+
webhook(integrationId: string, req: HttpRequestLike, body: unknown, querySecret?: string): Promise<string>;
|
|
18
|
+
getIntegrationSelectOptions(req: HttpRequestLike, keyword?: string): Promise<{
|
|
19
|
+
value: string;
|
|
20
|
+
label: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
icon?: string;
|
|
23
|
+
}[]>;
|
|
24
|
+
getCallbackConfig(integrationId: string): Promise<{
|
|
25
|
+
webhookUrl: string;
|
|
26
|
+
globalWebhookUrl: string;
|
|
27
|
+
setCallbackUrlTemplate: string;
|
|
28
|
+
setCallbackCurlTemplate: string;
|
|
29
|
+
}>;
|
|
30
|
+
registerCallback(integrationId: string, uuid: string, body: {
|
|
31
|
+
callbackUrl?: string;
|
|
32
|
+
enabled?: boolean;
|
|
33
|
+
}): Promise<import("@xpert-ai/plugin-sdk").TChatSendResult>;
|
|
34
|
+
sendText(integrationId: string, body: {
|
|
35
|
+
uuid?: string;
|
|
36
|
+
contactId?: string;
|
|
37
|
+
contactid?: string;
|
|
38
|
+
text?: string;
|
|
39
|
+
content?: string;
|
|
40
|
+
textcontent?: string;
|
|
41
|
+
atUsers?: string[];
|
|
42
|
+
atusers?: string[];
|
|
43
|
+
}): Promise<import("@xpert-ai/plugin-sdk").TChatSendResult>;
|
|
44
|
+
private readWechatPersonalIntegration;
|
|
45
|
+
private verifyCallbackSecret;
|
|
46
|
+
private fetchProviderSelectOptions;
|
|
47
|
+
private parseBodyToObject;
|
|
48
|
+
private toSafeString;
|
|
49
|
+
}
|
|
50
|
+
export {};
|