@nextclaw/channel-extension-weixin 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +12 -0
- package/dist/services/weixin-channel-adapter.service.d.ts +5 -0
- package/dist/services/weixin-channel-adapter.service.js +14 -0
- package/dist/services/weixin-extension-runtime.service.d.ts +10 -3
- package/dist/services/weixin-extension-runtime.service.js +18 -13
- package/dist/types/weixin-extension.types.d.ts +6 -0
- package/dist/utils/weixin-config.utils.d.ts +3 -0
- package/dist/utils/weixin-config.utils.js +3 -0
- package/nextclaw.extension.json +3 -0
- package/package.json +4 -4
package/dist/main.js
CHANGED
|
@@ -3,10 +3,22 @@ import { WeixinChannelAdapter } from "./services/weixin-channel-adapter.service.
|
|
|
3
3
|
import { WeixinExtensionRuntime } from "./services/weixin-extension-runtime.service.js";
|
|
4
4
|
import { NextClawExtension } from "@nextclaw/extension-sdk";
|
|
5
5
|
//#region src/main.ts
|
|
6
|
+
function readRequiredString(value, name) {
|
|
7
|
+
if (typeof value !== "string" || !value.trim()) throw new Error(`${name} is required`);
|
|
8
|
+
return value.trim();
|
|
9
|
+
}
|
|
10
|
+
function readOptionalString(value) {
|
|
11
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
12
|
+
}
|
|
6
13
|
const extension = new NextClawExtension();
|
|
7
14
|
const weixin = extension.channels.use("weixin");
|
|
8
15
|
const runtime = new WeixinExtensionRuntime(weixin, new WeixinChannelAdapter());
|
|
9
16
|
extension.capabilities.provide("channel.auth", new WeixinAuthCapability({ channel: weixin }));
|
|
17
|
+
extension.capabilities.provideHandler("channel.outbound.sendText", async (payload) => await runtime.sendOutboundText({
|
|
18
|
+
to: readRequiredString(payload.to, "to"),
|
|
19
|
+
text: readRequiredString(payload.text, "text"),
|
|
20
|
+
accountId: readOptionalString(payload.accountId)
|
|
21
|
+
}));
|
|
10
22
|
await runtime.start();
|
|
11
23
|
//#endregion
|
|
12
24
|
export {};
|
|
@@ -38,6 +38,11 @@ declare class WeixinChannelAdapter {
|
|
|
38
38
|
text: string;
|
|
39
39
|
contextToken?: string;
|
|
40
40
|
}) => Promise<void>;
|
|
41
|
+
readonly sendOutboundText: (params: {
|
|
42
|
+
to: string;
|
|
43
|
+
text: string;
|
|
44
|
+
accountId?: string | null;
|
|
45
|
+
}) => Promise<void>;
|
|
41
46
|
private readonly resolveReplySession;
|
|
42
47
|
private readonly listAvailableAccountIds;
|
|
43
48
|
private readonly resolveCanonicalRoute;
|
|
@@ -161,6 +161,20 @@ var WeixinChannelAdapter = class {
|
|
|
161
161
|
contextToken
|
|
162
162
|
});
|
|
163
163
|
};
|
|
164
|
+
sendOutboundText = async (params) => {
|
|
165
|
+
const { accountId, text, to } = params;
|
|
166
|
+
const target = {
|
|
167
|
+
conversationId: to,
|
|
168
|
+
...accountId ? { accountId } : {}
|
|
169
|
+
};
|
|
170
|
+
const account = this.resolveSendAccount(target);
|
|
171
|
+
await this.sendText({
|
|
172
|
+
account,
|
|
173
|
+
conversationId: target.conversationId,
|
|
174
|
+
text,
|
|
175
|
+
contextToken: this.resolveContextToken(target, account.accountId)
|
|
176
|
+
});
|
|
177
|
+
};
|
|
164
178
|
resolveReplySession = (sessionId, route) => {
|
|
165
179
|
const existing = this.replySessions.get(sessionId);
|
|
166
180
|
if (existing) return existing;
|
|
@@ -5,15 +5,22 @@ import { ExtensionChannel } from "@nextclaw/extension-sdk";
|
|
|
5
5
|
declare class WeixinExtensionRuntime {
|
|
6
6
|
private readonly channel;
|
|
7
7
|
private readonly adapter;
|
|
8
|
-
private
|
|
9
|
-
private
|
|
10
|
-
private unsubscribeNcpEvents;
|
|
8
|
+
private readonly cleanups;
|
|
9
|
+
private started;
|
|
11
10
|
constructor(channel: ExtensionChannel, adapter: WeixinChannelAdapter);
|
|
12
11
|
readonly start: () => Promise<void>;
|
|
13
12
|
readonly stop: () => Promise<void>;
|
|
13
|
+
readonly sendOutboundText: (params: {
|
|
14
|
+
to: string;
|
|
15
|
+
text: string;
|
|
16
|
+
accountId?: string | null;
|
|
17
|
+
}) => Promise<{
|
|
18
|
+
accepted: true;
|
|
19
|
+
}>;
|
|
14
20
|
private readonly applyConfig;
|
|
15
21
|
private readonly submitMessage;
|
|
16
22
|
private readonly sendNcpEvent;
|
|
23
|
+
private readonly drainCleanups;
|
|
17
24
|
}
|
|
18
25
|
//#endregion
|
|
19
26
|
export { WeixinExtensionRuntime };
|
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
//#region src/services/weixin-extension-runtime.service.ts
|
|
2
2
|
var WeixinExtensionRuntime = class {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
unsubscribeNcpEvents = null;
|
|
3
|
+
cleanups = [];
|
|
4
|
+
started = false;
|
|
6
5
|
constructor(channel, adapter) {
|
|
7
6
|
this.channel = channel;
|
|
8
7
|
this.adapter = adapter;
|
|
9
8
|
}
|
|
10
9
|
start = async () => {
|
|
11
|
-
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
10
|
+
if (this.started) return;
|
|
11
|
+
this.started = true;
|
|
12
|
+
this.cleanups.push(this.adapter.onMessage(this.submitMessage));
|
|
13
|
+
this.cleanups.push(this.channel.onNcpEvent(this.sendNcpEvent));
|
|
14
|
+
this.cleanups.push(this.channel.config.onChange(async () => {
|
|
14
15
|
await this.applyConfig();
|
|
15
|
-
});
|
|
16
|
+
}));
|
|
16
17
|
await this.applyConfig();
|
|
17
18
|
};
|
|
18
19
|
stop = async () => {
|
|
19
|
-
this.
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
22
|
-
this.unsubscribeConfig = null;
|
|
23
|
-
this.unsubscribeMessages = null;
|
|
24
|
-
this.unsubscribeNcpEvents = null;
|
|
20
|
+
if (!this.started) return;
|
|
21
|
+
this.started = false;
|
|
22
|
+
this.drainCleanups();
|
|
25
23
|
await this.adapter.stop();
|
|
26
24
|
};
|
|
25
|
+
sendOutboundText = async (params) => {
|
|
26
|
+
await this.adapter.sendOutboundText(params);
|
|
27
|
+
return { accepted: true };
|
|
28
|
+
};
|
|
27
29
|
applyConfig = async () => {
|
|
28
30
|
const config = await this.channel.config.get();
|
|
29
31
|
await this.adapter.configure(config);
|
|
@@ -60,6 +62,9 @@ var WeixinExtensionRuntime = class {
|
|
|
60
62
|
console.warn(`[weixin] failed to send NCP event: ${message}`);
|
|
61
63
|
}
|
|
62
64
|
};
|
|
65
|
+
drainCleanups = () => {
|
|
66
|
+
for (const cleanup of this.cleanups.splice(0).reverse()) cleanup();
|
|
67
|
+
};
|
|
63
68
|
};
|
|
64
69
|
//#endregion
|
|
65
70
|
export { WeixinExtensionRuntime };
|
|
@@ -5,6 +5,7 @@ import { ChannelSubmittedAttachment } from "@nextclaw/extension-sdk";
|
|
|
5
5
|
type WeixinAccountConfig = {
|
|
6
6
|
enabled?: boolean;
|
|
7
7
|
baseUrl?: string;
|
|
8
|
+
userId?: string;
|
|
8
9
|
allowFrom?: string[];
|
|
9
10
|
};
|
|
10
11
|
type WeixinChannelConfig = {
|
|
@@ -38,6 +39,11 @@ type WeixinChannelAdapter = {
|
|
|
38
39
|
stop: () => Promise<void>;
|
|
39
40
|
onMessage: (handler: (message: WeixinInboundMessage) => void | Promise<void>) => () => void;
|
|
40
41
|
sendNcpEvent: (event: NcpEndpointEvent) => Promise<void>;
|
|
42
|
+
sendOutboundText: (params: {
|
|
43
|
+
to: string;
|
|
44
|
+
text: string;
|
|
45
|
+
accountId?: string | null;
|
|
46
|
+
}) => Promise<void>;
|
|
41
47
|
};
|
|
42
48
|
//#endregion
|
|
43
49
|
export { WeixinAccountConfig, WeixinChannelAdapter, WeixinChannelConfig, WeixinInboundMessage, WeixinRuntimeAccount };
|
|
@@ -21,6 +21,7 @@ function normalizeAccountConfig(value) {
|
|
|
21
21
|
return {
|
|
22
22
|
enabled: typeof record.enabled === "boolean" ? record.enabled : void 0,
|
|
23
23
|
baseUrl: readString(record.baseUrl),
|
|
24
|
+
userId: readString(record.userId),
|
|
24
25
|
allowFrom: readStringArray(record.allowFrom)
|
|
25
26
|
};
|
|
26
27
|
}
|
|
@@ -59,6 +60,7 @@ function buildLoggedInWeixinChannelConfig(params) {
|
|
|
59
60
|
...currentAccount,
|
|
60
61
|
enabled: true,
|
|
61
62
|
baseUrl,
|
|
63
|
+
...allowUserId ? { userId: allowUserId } : {},
|
|
62
64
|
allowFrom: allowFrom.size > 0 ? [...allowFrom] : void 0
|
|
63
65
|
}
|
|
64
66
|
}
|
|
@@ -84,6 +86,7 @@ const WEIXIN_CHANNEL_CONFIG_SCHEMA = {
|
|
|
84
86
|
properties: {
|
|
85
87
|
enabled: { type: "boolean" },
|
|
86
88
|
baseUrl: { type: "string" },
|
|
89
|
+
userId: { type: "string" },
|
|
87
90
|
allowFrom: {
|
|
88
91
|
type: "array",
|
|
89
92
|
items: { type: "string" }
|
package/nextclaw.extension.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/channel-extension-weixin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "NextClaw Weixin channel extension process.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
"README.md"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@nextclaw/
|
|
22
|
-
"@nextclaw/
|
|
23
|
-
"@nextclaw/ncp-toolkit": "0.5.
|
|
21
|
+
"@nextclaw/extension-sdk": "0.1.6",
|
|
22
|
+
"@nextclaw/ncp": "0.5.12",
|
|
23
|
+
"@nextclaw/ncp-toolkit": "0.5.17"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/node": "^20.17.6",
|