@openclaw/crabline 0.1.7 → 0.1.9
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 +43 -1
- package/dist/src/cli/program.js +16 -2
- package/dist/src/cli/program.js.map +1 -1
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/openclaw/bridges/zalo.d.ts +1 -0
- package/dist/src/openclaw/bridges/zalo.js +102 -0
- package/dist/src/openclaw/bridges/zalo.js.map +1 -0
- package/dist/src/openclaw/shared.d.ts +2 -0
- package/dist/src/openclaw/shared.js.map +1 -1
- package/dist/src/openclaw.js +3 -0
- package/dist/src/openclaw.js.map +1 -1
- package/dist/src/servers/index.d.ts +9 -3
- package/dist/src/servers/index.js +5 -0
- package/dist/src/servers/index.js.map +1 -1
- package/dist/src/servers/matrix.d.ts +2 -0
- package/dist/src/servers/matrix.js +3 -3
- package/dist/src/servers/matrix.js.map +1 -1
- package/dist/src/servers/mattermost.d.ts +2 -0
- package/dist/src/servers/mattermost.js +3 -3
- package/dist/src/servers/mattermost.js.map +1 -1
- package/dist/src/servers/recorder.d.ts +7 -0
- package/dist/src/servers/recorder.js +8 -0
- package/dist/src/servers/recorder.js.map +1 -0
- package/dist/src/servers/signal.d.ts +2 -0
- package/dist/src/servers/signal.js +3 -3
- package/dist/src/servers/signal.js.map +1 -1
- package/dist/src/servers/slack.d.ts +2 -0
- package/dist/src/servers/slack.js +3 -3
- package/dist/src/servers/slack.js.map +1 -1
- package/dist/src/servers/telegram.d.ts +2 -0
- package/dist/src/servers/telegram.js +3 -3
- package/dist/src/servers/telegram.js.map +1 -1
- package/dist/src/servers/whatsapp.d.ts +2 -0
- package/dist/src/servers/whatsapp.js +3 -3
- package/dist/src/servers/whatsapp.js.map +1 -1
- package/dist/src/servers/zalo.d.ts +33 -0
- package/dist/src/servers/zalo.js +276 -0
- package/dist/src/servers/zalo.js.map +1 -0
- package/docs/channel-setup.md +39 -0
- package/package.json +1 -1
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { adminAuthError, hasAdminToken, jsonResponse, parseRequestBody, queryRecord, readTrimmedString, startHttpJsonServer, } from "./http.js";
|
|
4
|
+
import { recordServerEvent } from "./recorder.js";
|
|
5
|
+
async function appendEvent(state, event) {
|
|
6
|
+
await recordServerEvent({ event, onEvent: state.onEvent, recorderPath: state.recorderPath });
|
|
7
|
+
}
|
|
8
|
+
function zaloOk(result) {
|
|
9
|
+
return jsonResponse(result === undefined ? { ok: true } : { ok: true, result });
|
|
10
|
+
}
|
|
11
|
+
function zaloError(description, status) {
|
|
12
|
+
return jsonResponse({ description, error_code: status, ok: false }, status);
|
|
13
|
+
}
|
|
14
|
+
function messageId(state) {
|
|
15
|
+
return `${Date.now().toString(16)}${(state.nextMessage++).toString(16).padStart(6, "0")}`;
|
|
16
|
+
}
|
|
17
|
+
function readChatType(value) {
|
|
18
|
+
return readTrimmedString(value)?.toUpperCase() === "GROUP" ? "GROUP" : "PRIVATE";
|
|
19
|
+
}
|
|
20
|
+
function requestParams(url, body) {
|
|
21
|
+
return { ...Object.fromEntries(url.searchParams.entries()), ...body };
|
|
22
|
+
}
|
|
23
|
+
function redactParams(params) {
|
|
24
|
+
return Object.fromEntries(Object.entries(params).map(([key, value]) => [
|
|
25
|
+
key,
|
|
26
|
+
key === "secret_token" ? "<redacted>" : value,
|
|
27
|
+
]));
|
|
28
|
+
}
|
|
29
|
+
function requireParam(body, name) {
|
|
30
|
+
return readTrimmedString(body[name]) ?? zaloError(`${name} is required`, 400);
|
|
31
|
+
}
|
|
32
|
+
function firstError(...values) {
|
|
33
|
+
return values.find((value) => value instanceof Response);
|
|
34
|
+
}
|
|
35
|
+
function nextUpdate(state) {
|
|
36
|
+
const update = state.updates.shift();
|
|
37
|
+
return update ? zaloOk(update) : undefined;
|
|
38
|
+
}
|
|
39
|
+
function waitForUpdate(state, timeoutSeconds) {
|
|
40
|
+
const queued = nextUpdate(state);
|
|
41
|
+
if (queued) {
|
|
42
|
+
return Promise.resolve(queued);
|
|
43
|
+
}
|
|
44
|
+
if (timeoutSeconds <= 0) {
|
|
45
|
+
return Promise.resolve(zaloError("Request timeout", 408));
|
|
46
|
+
}
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
const pending = {
|
|
49
|
+
resolve,
|
|
50
|
+
timeout: setTimeout(() => {
|
|
51
|
+
const index = state.pendingRequests.indexOf(pending);
|
|
52
|
+
if (index >= 0) {
|
|
53
|
+
state.pendingRequests.splice(index, 1);
|
|
54
|
+
}
|
|
55
|
+
resolve(zaloError("Request timeout", 408));
|
|
56
|
+
}, timeoutSeconds * 1000),
|
|
57
|
+
};
|
|
58
|
+
state.pendingRequests.push(pending);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function deliverPollingUpdate(state, update) {
|
|
62
|
+
const pending = state.pendingRequests.shift();
|
|
63
|
+
if (!pending) {
|
|
64
|
+
state.updates.push(update);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
clearTimeout(pending.timeout);
|
|
68
|
+
pending.resolve(zaloOk(update));
|
|
69
|
+
}
|
|
70
|
+
async function deliverWebhookUpdate(webhook, update) {
|
|
71
|
+
try {
|
|
72
|
+
const response = await fetch(webhook.url, {
|
|
73
|
+
body: JSON.stringify({ ok: true, result: update }),
|
|
74
|
+
headers: {
|
|
75
|
+
"content-type": "application/json",
|
|
76
|
+
"x-bot-api-secret-token": webhook.secretToken,
|
|
77
|
+
},
|
|
78
|
+
method: "POST",
|
|
79
|
+
});
|
|
80
|
+
if (!response.ok) {
|
|
81
|
+
return zaloError(`Webhook delivery failed with HTTP ${response.status}`, 502);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
return zaloError(`Webhook delivery failed: ${error instanceof Error ? error.message : String(error)}`, 502);
|
|
86
|
+
}
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
async function handleAdminInbound(request, state, url) {
|
|
90
|
+
if (!hasAdminToken(request, state.adminToken)) {
|
|
91
|
+
return adminAuthError();
|
|
92
|
+
}
|
|
93
|
+
const body = await parseRequestBody(request);
|
|
94
|
+
const chatId = requireParam(body, "chatId");
|
|
95
|
+
const senderId = requireParam(body, "senderId");
|
|
96
|
+
const text = requireParam(body, "text");
|
|
97
|
+
if (chatId instanceof Response || senderId instanceof Response || text instanceof Response) {
|
|
98
|
+
return [chatId, senderId, text].find((value) => value instanceof Response);
|
|
99
|
+
}
|
|
100
|
+
const update = {
|
|
101
|
+
event_name: "message.text.received",
|
|
102
|
+
message: {
|
|
103
|
+
chat: { chat_type: readChatType(body.chatType), id: chatId },
|
|
104
|
+
date: Date.now(),
|
|
105
|
+
from: {
|
|
106
|
+
display_name: readTrimmedString(body.senderName) ?? senderId,
|
|
107
|
+
id: senderId,
|
|
108
|
+
is_bot: false,
|
|
109
|
+
},
|
|
110
|
+
message_id: messageId(state),
|
|
111
|
+
text,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
await appendEvent(state, {
|
|
115
|
+
at: new Date().toISOString(),
|
|
116
|
+
body,
|
|
117
|
+
method: request.method ?? "POST",
|
|
118
|
+
path: url.pathname,
|
|
119
|
+
query: queryRecord(url),
|
|
120
|
+
type: "admin",
|
|
121
|
+
});
|
|
122
|
+
if (state.webhook?.url) {
|
|
123
|
+
const error = await deliverWebhookUpdate(state.webhook, update);
|
|
124
|
+
if (error) {
|
|
125
|
+
return error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
deliverPollingUpdate(state, update);
|
|
130
|
+
}
|
|
131
|
+
return zaloOk(update);
|
|
132
|
+
}
|
|
133
|
+
async function handleZaloMethod(request, state, url, method) {
|
|
134
|
+
const body = requestParams(url, await parseRequestBody(request));
|
|
135
|
+
await appendEvent(state, {
|
|
136
|
+
at: new Date().toISOString(),
|
|
137
|
+
...(Object.keys(body).length > 0 ? { body: redactParams(body) } : {}),
|
|
138
|
+
method: request.method ?? "GET",
|
|
139
|
+
path: `/bot<redacted>/${method}`,
|
|
140
|
+
query: redactParams(queryRecord(url)),
|
|
141
|
+
type: "api",
|
|
142
|
+
});
|
|
143
|
+
if (method === "getMe") {
|
|
144
|
+
return zaloOk({
|
|
145
|
+
account_name: state.botName,
|
|
146
|
+
account_type: "BASIC",
|
|
147
|
+
can_join_groups: true,
|
|
148
|
+
id: state.botId,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
if (method === "getUpdates") {
|
|
152
|
+
if (state.webhook?.url) {
|
|
153
|
+
return zaloError("Webhook is configured; delete it before using getUpdates", 400);
|
|
154
|
+
}
|
|
155
|
+
const parsedTimeout = Number(readTrimmedString(body.timeout) ?? "30");
|
|
156
|
+
const timeout = Number.isFinite(parsedTimeout) ? Math.max(0, Math.min(parsedTimeout, 50)) : 30;
|
|
157
|
+
return await waitForUpdate(state, timeout);
|
|
158
|
+
}
|
|
159
|
+
if (method === "sendMessage" || method === "sendPhoto") {
|
|
160
|
+
const chatId = requireParam(body, "chat_id");
|
|
161
|
+
const content = requireParam(body, method === "sendMessage" ? "text" : "photo");
|
|
162
|
+
const error = firstError(chatId, content);
|
|
163
|
+
if (error) {
|
|
164
|
+
return error;
|
|
165
|
+
}
|
|
166
|
+
return zaloOk({ date: Date.now(), message_id: messageId(state) });
|
|
167
|
+
}
|
|
168
|
+
if (method === "sendChatAction") {
|
|
169
|
+
const chatId = requireParam(body, "chat_id");
|
|
170
|
+
const action = requireParam(body, "action");
|
|
171
|
+
const error = firstError(chatId, action);
|
|
172
|
+
if (error) {
|
|
173
|
+
return error;
|
|
174
|
+
}
|
|
175
|
+
if (action !== "typing" && action !== "upload_photo") {
|
|
176
|
+
return zaloError("action must be typing or upload_photo", 400);
|
|
177
|
+
}
|
|
178
|
+
return zaloOk();
|
|
179
|
+
}
|
|
180
|
+
if (method === "setWebhook") {
|
|
181
|
+
const webhookUrl = requireParam(body, "url");
|
|
182
|
+
const secretToken = requireParam(body, "secret_token");
|
|
183
|
+
const error = firstError(webhookUrl, secretToken);
|
|
184
|
+
if (error) {
|
|
185
|
+
return error;
|
|
186
|
+
}
|
|
187
|
+
if (typeof webhookUrl !== "string" || typeof secretToken !== "string") {
|
|
188
|
+
return zaloError("Invalid webhook parameters", 400);
|
|
189
|
+
}
|
|
190
|
+
let parsedUrl;
|
|
191
|
+
try {
|
|
192
|
+
parsedUrl = new URL(webhookUrl);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return zaloError("url must be a valid HTTP or HTTPS URL", 400);
|
|
196
|
+
}
|
|
197
|
+
if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
|
|
198
|
+
return zaloError("url must be a valid HTTP or HTTPS URL", 400);
|
|
199
|
+
}
|
|
200
|
+
state.updates.length = 0;
|
|
201
|
+
const webhook = { secretToken, updatedAt: Date.now(), url: parsedUrl.href };
|
|
202
|
+
state.webhook = webhook;
|
|
203
|
+
return zaloOk({ updated_at: webhook.updatedAt, url: webhook.url });
|
|
204
|
+
}
|
|
205
|
+
if (method === "deleteWebhook") {
|
|
206
|
+
const updatedAt = Date.now();
|
|
207
|
+
state.webhook = undefined;
|
|
208
|
+
return zaloOk({ updated_at: updatedAt, url: "" });
|
|
209
|
+
}
|
|
210
|
+
if (method === "getWebhookInfo") {
|
|
211
|
+
return zaloOk(state.webhook ? { updated_at: state.webhook.updatedAt, url: state.webhook.url } : { url: "" });
|
|
212
|
+
}
|
|
213
|
+
return zaloError("Bad request - invalid API name", 400);
|
|
214
|
+
}
|
|
215
|
+
export async function startZaloServer(params = {}) {
|
|
216
|
+
const host = params.host ?? "127.0.0.1";
|
|
217
|
+
const state = {
|
|
218
|
+
adminToken: params.adminToken ?? randomBytes(24).toString("hex"),
|
|
219
|
+
botId: params.botId ?? "1459232241454765289",
|
|
220
|
+
botName: params.botName ?? "bot.crabline",
|
|
221
|
+
botToken: params.botToken ?? "crabline-zalo-bot-token",
|
|
222
|
+
nextMessage: 1,
|
|
223
|
+
onEvent: params.onEvent,
|
|
224
|
+
pendingRequests: [],
|
|
225
|
+
recorderPath: params.recorderPath ?? path.resolve(".crabline", "servers", "zalo.jsonl"),
|
|
226
|
+
updates: [],
|
|
227
|
+
webhook: undefined,
|
|
228
|
+
};
|
|
229
|
+
const httpServer = await startHttpJsonServer({
|
|
230
|
+
handle: async (request) => {
|
|
231
|
+
const url = new URL(request.url ?? "/", `http://${request.headers.host ?? host}`);
|
|
232
|
+
if (request.method === "POST" && url.pathname === "/crabline/zalo/inbound") {
|
|
233
|
+
return await handleAdminInbound(request, state, url);
|
|
234
|
+
}
|
|
235
|
+
const match = /^\/bot([^/]+)\/([^/]+)$/u.exec(url.pathname);
|
|
236
|
+
if (!match || (request.method !== "GET" && request.method !== "POST")) {
|
|
237
|
+
return zaloError("Not found", 404);
|
|
238
|
+
}
|
|
239
|
+
if (match[1] !== state.botToken) {
|
|
240
|
+
return zaloError("Unauthorized", 401);
|
|
241
|
+
}
|
|
242
|
+
return await handleZaloMethod(request, state, url, match[2] ?? "");
|
|
243
|
+
},
|
|
244
|
+
host,
|
|
245
|
+
port: params.port ?? 0,
|
|
246
|
+
serverName: "Zalo",
|
|
247
|
+
});
|
|
248
|
+
const manifest = {
|
|
249
|
+
adminToken: state.adminToken,
|
|
250
|
+
baseUrl: httpServer.baseUrl,
|
|
251
|
+
botId: state.botId,
|
|
252
|
+
botToken: state.botToken,
|
|
253
|
+
endpoints: {
|
|
254
|
+
adminInboundUrl: `${httpServer.baseUrl}/crabline/zalo/inbound`,
|
|
255
|
+
apiRoot: httpServer.baseUrl,
|
|
256
|
+
},
|
|
257
|
+
env: {
|
|
258
|
+
ZALO_API_URL: httpServer.baseUrl,
|
|
259
|
+
ZALO_BOT_TOKEN: state.botToken,
|
|
260
|
+
},
|
|
261
|
+
provider: "zalo",
|
|
262
|
+
recorderPath: state.recorderPath,
|
|
263
|
+
version: 1,
|
|
264
|
+
};
|
|
265
|
+
return {
|
|
266
|
+
async close() {
|
|
267
|
+
for (const pending of state.pendingRequests.splice(0)) {
|
|
268
|
+
clearTimeout(pending.timeout);
|
|
269
|
+
pending.resolve(zaloError("Server shutting down", 503));
|
|
270
|
+
}
|
|
271
|
+
await httpServer.close();
|
|
272
|
+
},
|
|
273
|
+
manifest,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=zalo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zalo.js","sourceRoot":"","sources":["../../../src/servers/zalo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,cAAc,EACd,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,mBAAmB,GAEpB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAA4B,MAAM,eAAe,CAAC;AAsE5E,KAAK,UAAU,WAAW,CAAC,KAAsB,EAAE,KAAyB;IAC1E,MAAM,iBAAiB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;AAC/F,CAAC;AAED,SAAS,MAAM,CAAC,MAAgB;IAC9B,OAAO,YAAY,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AAClF,CAAC;AAED,SAAS,SAAS,CAAC,WAAmB,EAAE,MAAc;IACpD,OAAO,YAAY,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,SAAS,CAAC,KAAsB;IACvC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAC5F,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,iBAAiB,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACnF,CAAC;AAED,SAAS,aAAa,CAAC,GAAQ,EAAE,IAA6B;IAC5D,OAAO,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC;AACxE,CAAC;AAED,SAAS,YAAY,CAAC,MAA+B;IACnD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;QAC3C,GAAG;QACH,GAAG,KAAK,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK;KAC9C,CAAC,CACH,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,IAA6B,EAAE,IAAY;IAC/D,OAAO,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,SAAS,CAAC,GAAG,IAAI,cAAc,EAAE,GAAG,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,UAAU,CAAC,GAAG,MAAgC;IACrD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAqB,EAAE,CAAC,KAAK,YAAY,QAAQ,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,UAAU,CAAC,KAAsB;IACxC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACrC,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7C,CAAC;AAED,SAAS,aAAa,CAAC,KAAsB,EAAE,cAAsB;IACnE,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,OAAO,GAAyB;YACpC,OAAO;YACP,OAAO,EAAE,UAAU,CAAC,GAAG,EAAE;gBACvB,MAAM,KAAK,GAAG,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBACrD,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;oBACf,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBACzC,CAAC;gBACD,OAAO,CAAC,SAAS,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC,CAAC;YAC7C,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;SAC1B,CAAC;QACF,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAsB,EAAE,MAAkB;IACtE,MAAM,OAAO,GAAG,KAAK,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;IAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3B,OAAO;IACT,CAAC;IACD,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,OAAgD,EAChD,MAAkB;IAElB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;YACxC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;YAClD,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,wBAAwB,EAAE,OAAO,CAAC,WAAW;aAC9C;YACD,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,SAAS,CAAC,qCAAqC,QAAQ,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,SAAS,CACd,4BAA4B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EACpF,GAAG,CACJ,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,OAAwB,EACxB,KAAsB,EACtB,GAAQ;IAER,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9C,OAAO,cAAc,EAAE,CAAC;IAC1B,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxC,IAAI,MAAM,YAAY,QAAQ,IAAI,QAAQ,YAAY,QAAQ,IAAI,IAAI,YAAY,QAAQ,EAAE,CAAC;QAC3F,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,YAAY,QAAQ,CAAa,CAAC;IACzF,CAAC;IACD,MAAM,MAAM,GAAe;QACzB,UAAU,EAAE,uBAAuB;QACnC,OAAO,EAAE;YACP,IAAI,EAAE,EAAE,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE;YAC5D,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;YAChB,IAAI,EAAE;gBACJ,YAAY,EAAE,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,QAAQ;gBAC5D,EAAE,EAAE,QAAQ;gBACZ,MAAM,EAAE,KAAK;aACd;YACD,UAAU,EAAE,SAAS,CAAC,KAAK,CAAC;YAC5B,IAAI;SACL;KACF,CAAC;IACF,MAAM,WAAW,CAAC,KAAK,EAAE;QACvB,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC5B,IAAI;QACJ,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,MAAM;QAChC,IAAI,EAAE,GAAG,CAAC,QAAQ;QAClB,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC;QACvB,IAAI,EAAE,OAAO;KACd,CAAC,CAAC;IACH,IAAI,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAChE,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;SAAM,CAAC;QACN,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;AACxB,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,OAAwB,EACxB,KAAsB,EACtB,GAAQ,EACR,MAAc;IAEd,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,EAAE,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IACjE,MAAM,WAAW,CAAC,KAAK,EAAE;QACvB,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC5B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK;QAC/B,IAAI,EAAE,kBAAkB,MAAM,EAAE;QAChC,KAAK,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,CAA2B;QAC/D,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;IAEH,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,OAAO,MAAM,CAAC;YACZ,YAAY,EAAE,KAAK,CAAC,OAAO;YAC3B,YAAY,EAAE,OAAO;YACrB,eAAe,EAAE,IAAI;YACrB,EAAE,EAAE,KAAK,CAAC,KAAK;SAChB,CAAC,CAAC;IACL,CAAC;IACD,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC;YACvB,OAAO,SAAS,CAAC,0DAA0D,EAAE,GAAG,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;QACtE,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/F,OAAO,MAAM,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,MAAM,KAAK,aAAa,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAChF,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC1C,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,MAAM,KAAK,gBAAgB,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzC,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;YACrD,OAAO,SAAS,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,MAAM,EAAE,CAAC;IAClB,CAAC;IACD,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC7C,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,UAAU,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAClD,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;YACtE,OAAO,SAAS,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,SAAc,CAAC;QACnB,IAAI,CAAC;YACH,SAAS,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;QACjE,CAAC;QACD,IAAI,SAAS,CAAC,QAAQ,KAAK,OAAO,IAAI,SAAS,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACtE,OAAO,SAAS,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;QACjE,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC;QAC5E,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;QACxB,OAAO,MAAM,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,MAAM,KAAK,eAAe,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;QAC1B,OAAO,MAAM,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,MAAM,KAAK,gBAAgB,EAAE,CAAC;QAChC,OAAO,MAAM,CACX,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAC9F,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC,gCAAgC,EAAE,GAAG,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAM,GAA0B,EAAE;IAElC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,WAAW,CAAC;IACxC,MAAM,KAAK,GAAoB;QAC7B,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAChE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,qBAAqB;QAC5C,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,cAAc;QACzC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,yBAAyB;QACtD,WAAW,EAAE,CAAC;QACd,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,eAAe,EAAE,EAAE;QACnB,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,SAAS,EAAE,YAAY,CAAC;QACvF,OAAO,EAAE,EAAE;QACX,OAAO,EAAE,SAAS;KACnB,CAAC;IACF,MAAM,UAAU,GAAG,MAAM,mBAAmB,CAAC;QAC3C,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACxB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;YAClF,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,wBAAwB,EAAE,CAAC;gBAC3E,OAAO,MAAM,kBAAkB,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;YACvD,CAAC;YACD,MAAM,KAAK,GAAG,0BAA0B,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC5D,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;gBACtE,OAAO,SAAS,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;YACrC,CAAC;YACD,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAChC,OAAO,SAAS,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;YACxC,CAAC;YACD,OAAO,MAAM,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,IAAI;QACJ,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;QACtB,UAAU,EAAE,MAAM;KACnB,CAAC,CAAC;IACH,MAAM,QAAQ,GAAuB;QACnC,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE;YACT,eAAe,EAAE,GAAG,UAAU,CAAC,OAAO,wBAAwB;YAC9D,OAAO,EAAE,UAAU,CAAC,OAAO;SAC5B;QACD,GAAG,EAAE;YACH,YAAY,EAAE,UAAU,CAAC,OAAO;YAChC,cAAc,EAAE,KAAK,CAAC,QAAQ;SAC/B;QACD,QAAQ,EAAE,MAAM;QAChB,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,OAAO,EAAE,CAAC;KACX,CAAC;IACF,OAAO;QACL,KAAK,CAAC,KAAK;YACT,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtD,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBAC9B,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC,CAAC;YAC1D,CAAC;YACD,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC;QAC3B,CAAC;QACD,QAAQ;KACT,CAAC;AACJ,CAAC"}
|
package/docs/channel-setup.md
CHANGED
|
@@ -263,6 +263,7 @@ token is generated randomly unless `--admin-token <token>` is provided.
|
|
|
263
263
|
OpenClaw bridge callers should post injected user messages with the
|
|
264
264
|
`providerUrl`, `providerHeaders`, and `providerBody` returned by
|
|
265
265
|
`createOpenClawCrablineInbound()`.
|
|
266
|
+
|
|
266
267
|
The admin ingress accepts JSON like:
|
|
267
268
|
|
|
268
269
|
```json
|
|
@@ -276,6 +277,44 @@ The admin ingress accepts JSON like:
|
|
|
276
277
|
Outbound text sends and composing presence are recorded through the fake
|
|
277
278
|
provider messages and presence endpoints.
|
|
278
279
|
|
|
280
|
+
### Zalo Server
|
|
281
|
+
|
|
282
|
+
Start the server:
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
crabline --json serve zalo --ready-file .crabline/zalo-server.json
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Set trusted `ZALO_API_URL` to `endpoints.apiRoot` and configure the emitted
|
|
289
|
+
`botToken` as `channels.zalo.botToken` or `ZALO_BOT_TOKEN`. The OpenClaw bridge
|
|
290
|
+
does this mapping without adding provider-server-specific behavior to the Zalo
|
|
291
|
+
adapter.
|
|
292
|
+
|
|
293
|
+
The server accepts the provider-native `/bot<TOKEN>/<METHOD>` API shape over
|
|
294
|
+
GET or POST. It implements bot identity, single-update long polling, text and
|
|
295
|
+
photo sends, chat actions, and webhook lifecycle calls. A configured webhook
|
|
296
|
+
receives the native Zalo `{ ok, result }` event envelope with
|
|
297
|
+
`X-Bot-Api-Secret-Token`;
|
|
298
|
+
otherwise injected messages are returned by `getUpdates`. Provider errors use
|
|
299
|
+
Zalo's `{ ok, error_code, description }` shape.
|
|
300
|
+
|
|
301
|
+
The authenticated admin ingress is only a test control plane. Post a message
|
|
302
|
+
such as:
|
|
303
|
+
|
|
304
|
+
```json
|
|
305
|
+
{
|
|
306
|
+
"chatId": "group-1",
|
|
307
|
+
"chatType": "GROUP",
|
|
308
|
+
"senderId": "user-1",
|
|
309
|
+
"senderName": "Alice",
|
|
310
|
+
"text": "user nonce-123"
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Crabline translates that state change into the normal Zalo polling or webhook
|
|
315
|
+
transport. Outbound `sendMessage` and `sendPhoto` calls are written to the
|
|
316
|
+
manifest's `recorderPath` with the bot token redacted.
|
|
317
|
+
|
|
279
318
|
## Webhook Payload
|
|
280
319
|
|
|
281
320
|
Mock webhooks accept provider-native event payloads where Crabline has a built-in
|