@pawastation/wechat-kf 0.1.2 → 0.2.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.
Files changed (55) hide show
  1. package/README.md +34 -28
  2. package/README.zh-CN.md +34 -28
  3. package/dist/index.d.ts +5 -15
  4. package/dist/index.js +5 -5
  5. package/dist/index.js.map +1 -1
  6. package/dist/src/accounts.d.ts +2 -1
  7. package/dist/src/accounts.js +61 -19
  8. package/dist/src/accounts.js.map +1 -1
  9. package/dist/src/api.d.ts +31 -2
  10. package/dist/src/api.js +41 -13
  11. package/dist/src/api.js.map +1 -1
  12. package/dist/src/bot.d.ts +10 -8
  13. package/dist/src/bot.js +231 -78
  14. package/dist/src/bot.js.map +1 -1
  15. package/dist/src/channel.d.ts +7 -106
  16. package/dist/src/channel.js +208 -71
  17. package/dist/src/channel.js.map +1 -1
  18. package/dist/src/config-schema.d.ts +0 -6
  19. package/dist/src/config-schema.js +2 -7
  20. package/dist/src/config-schema.js.map +1 -1
  21. package/dist/src/constants.d.ts +20 -0
  22. package/dist/src/constants.js +29 -0
  23. package/dist/src/constants.js.map +1 -1
  24. package/dist/src/crypto.js +7 -6
  25. package/dist/src/crypto.js.map +1 -1
  26. package/dist/src/monitor.d.ts +27 -14
  27. package/dist/src/monitor.js +67 -120
  28. package/dist/src/monitor.js.map +1 -1
  29. package/dist/src/outbound.d.ts +10 -44
  30. package/dist/src/outbound.js +277 -92
  31. package/dist/src/outbound.js.map +1 -1
  32. package/dist/src/reply-dispatcher.d.ts +2 -6
  33. package/dist/src/reply-dispatcher.js +131 -32
  34. package/dist/src/reply-dispatcher.js.map +1 -1
  35. package/dist/src/runtime.d.ts +1 -119
  36. package/dist/src/runtime.js +2 -1
  37. package/dist/src/runtime.js.map +1 -1
  38. package/dist/src/send-utils.d.ts +13 -0
  39. package/dist/src/send-utils.js +56 -4
  40. package/dist/src/send-utils.js.map +1 -1
  41. package/dist/src/token.js +7 -3
  42. package/dist/src/token.js.map +1 -1
  43. package/dist/src/types.d.ts +68 -6
  44. package/dist/src/webhook.d.ts +16 -16
  45. package/dist/src/webhook.js +92 -75
  46. package/dist/src/webhook.js.map +1 -1
  47. package/dist/src/wechat-kf-directives.d.ts +132 -9
  48. package/dist/src/wechat-kf-directives.js +535 -24
  49. package/dist/src/wechat-kf-directives.js.map +1 -1
  50. package/index.ts +22 -12
  51. package/openclaw.plugin.json +1 -3
  52. package/package.json +3 -2
  53. package/dist/src/chunk-utils.d.ts +0 -18
  54. package/dist/src/chunk-utils.js +0 -58
  55. package/dist/src/chunk-utils.js.map +0 -1
@@ -4,15 +4,10 @@ export type WechatKfConfig = {
4
4
  appSecret?: string;
5
5
  token?: string;
6
6
  encodingAESKey?: string;
7
- webhookPort?: number;
8
7
  webhookPath?: string;
9
8
  dmPolicy?: "open" | "pairing" | "allowlist" | "disabled";
10
9
  allowFrom?: string[];
11
10
  };
12
- export type OpenClawConfig = {
13
- channels?: Record<string, unknown>;
14
- [key: string]: unknown;
15
- };
16
11
  export type ResolvedWechatKfAccount = {
17
12
  accountId: string;
18
13
  enabled: boolean;
@@ -22,7 +17,6 @@ export type ResolvedWechatKfAccount = {
22
17
  token?: string;
23
18
  encodingAESKey?: string;
24
19
  openKfId?: string;
25
- webhookPort: number;
26
20
  webhookPath: string;
27
21
  config: WechatKfConfig;
28
22
  };
@@ -42,6 +36,8 @@ export type WechatKfSyncMsgRequest = {
42
36
  export type WechatKfMergedMsgItem = {
43
37
  sender_name?: string;
44
38
  msg_content?: string;
39
+ send_time?: number;
40
+ msgtype?: string;
45
41
  };
46
42
  export type WechatKfMessage = {
47
43
  msgid: string;
@@ -53,6 +49,7 @@ export type WechatKfMessage = {
53
49
  msgtype: string;
54
50
  text?: {
55
51
  content: string;
52
+ menu_id?: string;
56
53
  };
57
54
  image?: {
58
55
  media_id: string;
@@ -103,6 +100,7 @@ export type WechatKfMessage = {
103
100
  title?: string;
104
101
  appid?: string;
105
102
  pagepath?: string;
103
+ thumb_media_id?: string;
106
104
  };
107
105
  business_card?: {
108
106
  userid?: string;
@@ -115,6 +113,22 @@ export type WechatKfMessage = {
115
113
  }[];
116
114
  tail_content?: string;
117
115
  };
116
+ channels_shop_product?: {
117
+ product_id?: string;
118
+ head_image?: string;
119
+ title?: string;
120
+ sales_price?: string;
121
+ shop_nickname?: string;
122
+ shop_head_image?: string;
123
+ };
124
+ channels_shop_order?: {
125
+ order_id?: string;
126
+ product_titles?: string;
127
+ price_wording?: string;
128
+ state?: string;
129
+ image_url?: string;
130
+ shop_nickname?: string;
131
+ };
118
132
  };
119
133
  export type WechatKfSyncMsgResponse = {
120
134
  errcode: number;
@@ -149,6 +163,54 @@ export type WechatKfSendMsgRequest = {
149
163
  url: string;
150
164
  thumb_media_id: string;
151
165
  };
166
+ miniprogram?: {
167
+ appid: string;
168
+ title?: string;
169
+ thumb_media_id: string;
170
+ pagepath: string;
171
+ };
172
+ msgmenu?: {
173
+ head_content?: string;
174
+ list?: Array<{
175
+ type: "click";
176
+ click: {
177
+ id?: string;
178
+ content: string;
179
+ };
180
+ } | {
181
+ type: "view";
182
+ view: {
183
+ url: string;
184
+ content: string;
185
+ };
186
+ } | {
187
+ type: "miniprogram";
188
+ miniprogram: {
189
+ appid: string;
190
+ pagepath: string;
191
+ content: string;
192
+ };
193
+ } | {
194
+ type: "text";
195
+ text: {
196
+ content: string;
197
+ no_newline?: number;
198
+ };
199
+ }>;
200
+ tail_content?: string;
201
+ };
202
+ location?: {
203
+ name?: string;
204
+ address?: string;
205
+ latitude: number;
206
+ longitude: number;
207
+ };
208
+ business_card?: {
209
+ userid: string;
210
+ };
211
+ ca_link?: {
212
+ link_url: string;
213
+ };
152
214
  };
153
215
  export type WechatKfSendMsgResponse = {
154
216
  errcode: number;
@@ -1,22 +1,22 @@
1
1
  /**
2
- * HTTP webhook server for WeChat KF callbacks
2
+ * HTTP webhook handler for WeChat KF callbacks
3
3
  *
4
4
  * Handles:
5
5
  * - GET: URL verification (echostr decrypt)
6
6
  * - POST: Event notification (decrypt XML → trigger sync_msg)
7
+ *
8
+ * Designed to be registered on the framework's shared gateway server
9
+ * via api.registerHttpHandler(handleWechatKfWebhook).
10
+ */
11
+ import type { IncomingMessage, ServerResponse } from "node:http";
12
+ export declare function parseQuery(url: string): Record<string, string>;
13
+ export declare function readBody(req: IncomingMessage, maxSize?: number): Promise<string>;
14
+ /** Extract a tag value from XML string */
15
+ export declare function xmlTag(xml: string, tag: string): string | undefined;
16
+ /**
17
+ * Framework-compatible HTTP handler for WeChat KF webhooks.
18
+ *
19
+ * Returns `true` if the request was handled, `false` if the path doesn't
20
+ * match (so the framework can try other plugins).
7
21
  */
8
- import { type Server } from "node:http";
9
- export type WebhookHandler = (openKfId: string, token: string) => void | Promise<void>;
10
- export type WebhookOptions = {
11
- port: number;
12
- path: string;
13
- callbackToken: string;
14
- encodingAESKey: string;
15
- corpId: string;
16
- onEvent: WebhookHandler;
17
- log?: {
18
- info: (...a: unknown[]) => void;
19
- error: (...a: unknown[]) => void;
20
- };
21
- };
22
- export declare function createWebhookServer(opts: WebhookOptions): Server;
22
+ export declare function handleWechatKfWebhook(req: IncomingMessage, res: ServerResponse): Promise<boolean>;
@@ -1,13 +1,19 @@
1
1
  /**
2
- * HTTP webhook server for WeChat KF callbacks
2
+ * HTTP webhook handler for WeChat KF callbacks
3
3
  *
4
4
  * Handles:
5
5
  * - GET: URL verification (echostr decrypt)
6
6
  * - POST: Event notification (decrypt XML → trigger sync_msg)
7
+ *
8
+ * Designed to be registered on the framework's shared gateway server
9
+ * via api.registerHttpHandler(handleWechatKfWebhook).
7
10
  */
8
- import { createServer } from "node:http";
11
+ import { registerKfId } from "./accounts.js";
12
+ import { handleWebhookEvent } from "./bot.js";
13
+ import { formatError, logTag } from "./constants.js";
9
14
  import { decrypt, verifySignature } from "./crypto.js";
10
- function parseQuery(url) {
15
+ import { getSharedContext } from "./monitor.js";
16
+ export function parseQuery(url) {
11
17
  const idx = url.indexOf("?");
12
18
  if (idx < 0)
13
19
  return {};
@@ -23,7 +29,7 @@ function parseQuery(url) {
23
29
  }
24
30
  return params;
25
31
  }
26
- function readBody(req, maxSize = 64 * 1024) {
32
+ export function readBody(req, maxSize = 64 * 1024) {
27
33
  return new Promise((resolve, reject) => {
28
34
  const chunks = [];
29
35
  let size = 0;
@@ -38,7 +44,7 @@ function readBody(req, maxSize = 64 * 1024) {
38
44
  // can still write a response (413). Resume drains remaining data.
39
45
  req.removeAllListeners("data");
40
46
  req.resume();
41
- reject(new Error("[wechat-kf] request body too large"));
47
+ reject(new Error(`${logTag()} request body too large`));
42
48
  return;
43
49
  }
44
50
  chunks.push(c);
@@ -54,85 +60,96 @@ function readBody(req, maxSize = 64 * 1024) {
54
60
  });
55
61
  }
56
62
  /** Extract a tag value from XML string */
57
- function xmlTag(xml, tag) {
63
+ export function xmlTag(xml, tag) {
58
64
  const re = new RegExp(`<${tag}><!\\[CDATA\\[(.+?)\\]\\]></${tag}>|<${tag}>(.+?)</${tag}>`);
59
65
  const m = xml.match(re);
60
66
  return m?.[1] ?? m?.[2];
61
67
  }
62
- export function createWebhookServer(opts) {
63
- const { path, callbackToken, encodingAESKey, onEvent, log } = opts;
64
- const server = createServer(async (req, res) => {
65
- const url = req.url ?? "/";
66
- const pathname = url.split("?")[0];
67
- if (pathname !== path) {
68
- res.writeHead(404);
69
- res.end("not found");
70
- return;
71
- }
72
- const query = parseQuery(url);
73
- try {
74
- if (req.method === "GET") {
75
- // URL verification
76
- const { msg_signature, timestamp, nonce, echostr } = query;
77
- if (!msg_signature || !timestamp || !nonce || !echostr) {
78
- res.writeHead(400);
79
- res.end("missing params");
80
- return;
81
- }
82
- if (!verifySignature(callbackToken, timestamp, nonce, echostr, msg_signature)) {
83
- res.writeHead(403);
84
- res.end("signature mismatch");
85
- return;
86
- }
87
- const { message } = decrypt(encodingAESKey, echostr);
88
- res.writeHead(200, { "Content-Type": "text/plain" });
89
- res.end(message);
90
- return;
68
+ /**
69
+ * Framework-compatible HTTP handler for WeChat KF webhooks.
70
+ *
71
+ * Returns `true` if the request was handled, `false` if the path doesn't
72
+ * match (so the framework can try other plugins).
73
+ */
74
+ export async function handleWechatKfWebhook(req, res) {
75
+ const ctx = getSharedContext();
76
+ if (!ctx)
77
+ return false;
78
+ const url = req.url ?? "/";
79
+ const pathname = url.split("?")[0];
80
+ if (pathname !== ctx.webhookPath)
81
+ return false;
82
+ const query = parseQuery(url);
83
+ try {
84
+ if (req.method === "GET") {
85
+ // URL verification
86
+ const { msg_signature, timestamp, nonce, echostr } = query;
87
+ if (!msg_signature || !timestamp || !nonce || !echostr) {
88
+ res.writeHead(400);
89
+ res.end("missing params");
90
+ return true;
91
91
  }
92
- if (req.method === "POST") {
93
- const { msg_signature, timestamp, nonce } = query;
94
- const body = await readBody(req);
95
- // Extract Encrypt from XML
96
- const encryptedMsg = xmlTag(body, "Encrypt");
97
- if (!encryptedMsg || !msg_signature || !timestamp || !nonce) {
98
- res.writeHead(400);
99
- res.end("bad request");
100
- return;
101
- }
102
- if (!verifySignature(callbackToken, timestamp, nonce, encryptedMsg, msg_signature)) {
103
- res.writeHead(403);
104
- res.end("signature mismatch");
105
- return;
106
- }
107
- const { message } = decrypt(encodingAESKey, encryptedMsg);
108
- // Parse decrypted XML for Token and OpenKfId
109
- const eventToken = xmlTag(message, "Token") ?? "";
110
- const openKfId = xmlTag(message, "OpenKfId") ?? "";
111
- // Respond immediately, process async
112
- res.writeHead(200, { "Content-Type": "text/plain" });
113
- res.end("success");
114
- // Trigger message sync
115
- Promise.resolve(onEvent(openKfId, eventToken)).catch((err) => {
116
- (log?.error ?? console.error)("[wechat-kf] onEvent error:", err);
117
- });
118
- return;
92
+ if (!verifySignature(ctx.callbackToken, timestamp, nonce, echostr, msg_signature)) {
93
+ ctx.botCtx.log?.warn(`${logTag()} callback signature verification failed (GET)`);
94
+ res.writeHead(403);
95
+ res.end("signature mismatch");
96
+ return true;
119
97
  }
120
- res.writeHead(405);
121
- res.end("method not allowed");
98
+ const { message } = decrypt(ctx.encodingAESKey, echostr);
99
+ res.writeHead(200, { "Content-Type": "text/plain" });
100
+ res.end(message);
101
+ return true;
122
102
  }
123
- catch (err) {
124
- if (err instanceof Error && err.message.includes("body too large")) {
125
- res.writeHead(413);
126
- res.end("payload too large");
127
- return;
103
+ if (req.method === "POST") {
104
+ const { msg_signature, timestamp, nonce } = query;
105
+ const body = await readBody(req);
106
+ // Extract Encrypt from XML
107
+ const encryptedMsg = xmlTag(body, "Encrypt");
108
+ if (!encryptedMsg || !msg_signature || !timestamp || !nonce) {
109
+ res.writeHead(400);
110
+ res.end("bad request");
111
+ return true;
128
112
  }
129
- (log?.error ?? console.error)("[wechat-kf] webhook error:", err);
130
- if (!res.headersSent) {
131
- res.writeHead(500);
132
- res.end("internal error");
113
+ if (!verifySignature(ctx.callbackToken, timestamp, nonce, encryptedMsg, msg_signature)) {
114
+ ctx.botCtx.log?.warn(`${logTag()} callback signature verification failed (POST)`);
115
+ res.writeHead(403);
116
+ res.end("signature mismatch");
117
+ return true;
133
118
  }
119
+ const { message } = decrypt(ctx.encodingAESKey, encryptedMsg);
120
+ // Parse decrypted XML for Token and OpenKfId
121
+ const eventToken = xmlTag(message, "Token") ?? "";
122
+ const openKfId = xmlTag(message, "OpenKfId") ?? "";
123
+ // Respond immediately, process async
124
+ res.writeHead(200, { "Content-Type": "text/plain" });
125
+ res.end("success");
126
+ // Fire-and-forget: register kfId and trigger message sync
127
+ Promise.resolve((async () => {
128
+ if (openKfId) {
129
+ await registerKfId(openKfId);
130
+ }
131
+ await handleWebhookEvent(ctx.botCtx, openKfId, eventToken);
132
+ })()).catch((err) => {
133
+ ctx.botCtx.log?.error(`${logTag()} webhook event processing error: ${formatError(err)}`);
134
+ });
135
+ return true;
134
136
  }
135
- });
136
- return server;
137
+ res.writeHead(405);
138
+ res.end("method not allowed");
139
+ return true;
140
+ }
141
+ catch (err) {
142
+ if (err instanceof Error && err.message.includes("body too large")) {
143
+ res.writeHead(413);
144
+ res.end("payload too large");
145
+ return true;
146
+ }
147
+ ctx.botCtx.log?.error(`${logTag()} webhook error: ${formatError(err)}`);
148
+ if (!res.headersSent) {
149
+ res.writeHead(500);
150
+ res.end("internal error");
151
+ }
152
+ return true;
153
+ }
137
154
  }
138
155
  //# sourceMappingURL=webhook.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/webhook.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/webhook.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,17 @@
1
1
  /**
2
2
  * WeChat KF directive parser
3
3
  *
4
- * Parses [[wechat_link: title | desc | url | thumbUrl]] directives
5
- * embedded in agent text replies. The framework doesn't recognize these
6
- * directives, so the text arrives intact for plugin-level interception.
4
+ * Parses [[wechat_*: ...]] directives embedded in agent text replies.
5
+ * The framework doesn't recognize these directives, so the text arrives
6
+ * intact for plugin-level interception.
7
7
  *
8
- * Syntax (pipe-separated fields):
9
- * [[wechat_link: title | url]] → 2 fields
10
- * [[wechat_link: title | desc | url]] → 3 fields
11
- * [[wechat_link: title | desc | url | thumbUrl]] → 4 fields
8
+ * Supported directives:
9
+ * [[wechat_link: title | desc | url | thumbUrl]]
10
+ * [[wechat_location: name | address | lat | lng]]
11
+ * [[wechat_miniprogram: appid | title | pagepath | thumbUrl]]
12
+ * [[wechat_menu: header | Option1, Option2, Option3 | footer]]
13
+ * [[wechat_business_card: USERID]]
14
+ * [[wechat_ca_link: https://work.weixin.qq.com/ca/...]]
12
15
  */
13
16
  export type WechatLinkDirective = {
14
17
  title: string;
@@ -16,12 +19,78 @@ export type WechatLinkDirective = {
16
19
  url: string;
17
20
  thumbUrl?: string;
18
21
  };
22
+ export type WechatLocationDirective = {
23
+ name: string;
24
+ address?: string;
25
+ latitude: number;
26
+ longitude: number;
27
+ };
28
+ export type WechatMenuItemDirective = {
29
+ type: "click";
30
+ id?: string;
31
+ content: string;
32
+ } | {
33
+ type: "view";
34
+ url: string;
35
+ content: string;
36
+ } | {
37
+ type: "miniprogram";
38
+ appid: string;
39
+ pagepath: string;
40
+ content: string;
41
+ } | {
42
+ type: "text";
43
+ content: string;
44
+ noNewline?: boolean;
45
+ };
46
+ export type WechatMenuDirective = {
47
+ headContent?: string;
48
+ items: WechatMenuItemDirective[];
49
+ tailContent?: string;
50
+ };
51
+ export type WechatMiniprogramDirective = {
52
+ appid: string;
53
+ title: string;
54
+ pagepath: string;
55
+ thumbUrl?: string;
56
+ };
57
+ export type WechatBusinessCardDirective = {
58
+ userid: string;
59
+ };
60
+ export type WechatCaLinkDirective = {
61
+ link_url: string;
62
+ };
63
+ export type WechatRawDirective = {
64
+ msgtype: string;
65
+ payload: Record<string, unknown>;
66
+ };
19
67
  export type WechatDirectiveResult = {
20
68
  text: string;
21
69
  link?: WechatLinkDirective;
70
+ location?: WechatLocationDirective;
71
+ miniprogram?: WechatMiniprogramDirective;
72
+ menu?: WechatMenuDirective;
73
+ businessCard?: WechatBusinessCardDirective;
74
+ caLink?: WechatCaLinkDirective;
75
+ raw?: WechatRawDirective;
76
+ };
77
+ export type ProtectedRange = {
78
+ start: number;
79
+ end: number;
22
80
  };
23
81
  /**
24
- * Quick check whether text contains a `[[wechat_link:...]]` directive.
82
+ * Scan text left-to-right and collect ranges that should be treated as
83
+ * "protected" — i.e. directive syntax inside them must be ignored.
84
+ *
85
+ * Three zone types (checked in priority order):
86
+ * 1. Fenced code blocks (``` or ~~~, with optional 0-3 leading spaces + lang tag)
87
+ * 2. Inline code spans (backtick sequences, matching equal-length closer)
88
+ * 3. Blockquote lines (line starting with optional whitespace + `>`)
89
+ */
90
+ export declare function findProtectedRanges(text: string): ProtectedRange[];
91
+ /**
92
+ * Quick check whether text contains a `[[wechat_link:...]]` directive
93
+ * outside of markdown code blocks, inline code, and blockquotes.
25
94
  */
26
95
  export declare function hasWechatLinkDirective(text: string): boolean;
27
96
  /**
@@ -31,4 +100,58 @@ export declare function hasWechatLinkDirective(text: string): boolean;
31
100
  * plus the parsed link fields. If parsing fails (e.g. invalid URL),
32
101
  * returns the original text unchanged with no link.
33
102
  */
34
- export declare function parseWechatLinkDirective(text: string): WechatDirectiveResult;
103
+ export declare function parseWechatLinkDirective(text: string, protectedRanges?: ProtectedRange[]): WechatDirectiveResult;
104
+ export declare function parseWechatLocationDirective(text: string, protectedRanges?: ProtectedRange[]): WechatDirectiveResult;
105
+ export declare function parseWechatMiniprogramDirective(text: string, protectedRanges?: ProtectedRange[]): WechatDirectiveResult;
106
+ export declare function parseWechatMenuDirective(text: string, protectedRanges?: ProtectedRange[]): WechatDirectiveResult;
107
+ /**
108
+ * Convert a parsed WechatMenuDirective into the API `msgmenu` payload.
109
+ *
110
+ * Click items get auto-incrementing IDs (only among click items that lack
111
+ * an explicit `id`). Explicit IDs are preserved as-is.
112
+ */
113
+ export declare function buildMsgMenuPayload(menu: WechatMenuDirective): {
114
+ head_content?: string;
115
+ list: Array<{
116
+ type: "click";
117
+ click: {
118
+ id: string;
119
+ content: string;
120
+ };
121
+ } | {
122
+ type: "view";
123
+ view: {
124
+ url: string;
125
+ content: string;
126
+ };
127
+ } | {
128
+ type: "miniprogram";
129
+ miniprogram: {
130
+ appid: string;
131
+ pagepath: string;
132
+ content: string;
133
+ };
134
+ } | {
135
+ type: "text";
136
+ text: {
137
+ content: string;
138
+ no_newline?: number;
139
+ };
140
+ }>;
141
+ tail_content?: string;
142
+ };
143
+ export declare function parseWechatBusinessCardDirective(text: string, protectedRanges?: ProtectedRange[]): WechatDirectiveResult;
144
+ export declare function parseWechatCaLinkDirective(text: string, protectedRanges?: ProtectedRange[]): WechatDirectiveResult;
145
+ export declare function parseWechatRawDirective(text: string, protectedRanges?: ProtectedRange[]): WechatDirectiveResult;
146
+ /**
147
+ * Quick check whether text contains any `[[wechat_*:...]]` directive
148
+ * outside of markdown code blocks, inline code, and blockquotes.
149
+ */
150
+ export declare function hasWechatDirective(text: string): boolean;
151
+ /**
152
+ * Parse the first matching directive from text.
153
+ * Tries parsers in order: link → location → miniprogram → menu → business_card → ca_link → raw.
154
+ * Returns the first successful parse result.
155
+ * Directives inside markdown code blocks, inline code, or blockquotes are ignored.
156
+ */
157
+ export declare function parseWechatDirective(text: string): WechatDirectiveResult;