chore: Run pnpm format:fix.

This commit is contained in:
cpojer
2026-01-31 21:13:13 +09:00
parent dcc2de15a6
commit 8cab78abbc
624 changed files with 10729 additions and 7514 deletions
+12
View File
@@ -3,61 +3,73 @@
## 2026.1.30
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.1.29
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.1.23
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.1.22
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.1.21
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.1.20
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.1.17-1
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.1.17
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.1.16
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.1.15
### Changes
- Version alignment with core OpenClaw release numbers.
## 2026.1.14
### Changes
- Version alignment with core OpenClaw release numbers.
## 0.1.0
### Features
- Zalo Bot API channel plugin with token-based auth (env/config/file).
- Direct message support (DMs only) with pairing/allowlist/open/disabled policies.
- Polling and webhook delivery modes.
+6 -6
View File
@@ -25,9 +25,9 @@ Onboarding: select Zalo and confirm the install prompt to fetch the plugin autom
enabled: true,
botToken: "12345689:abc-xyz",
dmPolicy: "pairing",
proxy: "http://proxy.local:8080"
}
}
proxy: "http://proxy.local:8080",
},
},
}
```
@@ -39,9 +39,9 @@ Onboarding: select Zalo and confirm the install prompt to fetch the plugin autom
zalo: {
webhookUrl: "https://example.com/zalo-webhook",
webhookSecret: "your-secret-8-plus-chars",
webhookPath: "/zalo-webhook"
}
}
webhookPath: "/zalo-webhook",
},
},
}
```
+1 -3
View File
@@ -1,8 +1,6 @@
{
"id": "zalo",
"channels": [
"zalo"
],
"channels": ["zalo"],
"configSchema": {
"type": "object",
"additionalProperties": false,
+5 -5
View File
@@ -1,8 +1,12 @@
{
"name": "@openclaw/zalo",
"version": "2026.1.30",
"type": "module",
"description": "OpenClaw Zalo channel plugin",
"type": "module",
"dependencies": {
"openclaw": "workspace:*",
"undici": "7.19.2"
},
"openclaw": {
"extensions": [
"./index.ts"
@@ -25,9 +29,5 @@
"localPath": "extensions/zalo",
"defaultChoice": "npm"
}
},
"dependencies": {
"openclaw": "workspace:*",
"undici": "7.19.2"
}
}
+14 -4
View File
@@ -19,7 +19,12 @@ describe("zalo directory", () => {
expect(zaloPlugin.directory?.listGroups).toBeTruthy();
await expect(
zaloPlugin.directory!.listPeers({ cfg, accountId: undefined, query: undefined, limit: undefined }),
zaloPlugin.directory!.listPeers({
cfg,
accountId: undefined,
query: undefined,
limit: undefined,
}),
).resolves.toEqual(
expect.arrayContaining([
{ kind: "user", id: "123" },
@@ -28,8 +33,13 @@ describe("zalo directory", () => {
]),
);
await expect(zaloPlugin.directory!.listGroups({ cfg, accountId: undefined, query: undefined, limit: undefined })).resolves.toEqual(
[],
);
await expect(
zaloPlugin.directory!.listGroups({
cfg,
accountId: undefined,
query: undefined,
limit: undefined,
}),
).resolves.toEqual([]);
});
});
+8 -2
View File
@@ -16,7 +16,12 @@ import {
setAccountEnabledInConfigSection,
} from "openclaw/plugin-sdk";
import { listZaloAccountIds, resolveDefaultZaloAccountId, resolveZaloAccount, type ResolvedZaloAccount } from "./accounts.js";
import {
listZaloAccountIds,
resolveDefaultZaloAccountId,
resolveZaloAccount,
type ResolvedZaloAccount,
} from "./accounts.js";
import { zaloMessageActions } from "./actions.js";
import { ZaloConfigSchema } from "./config-schema.js";
import { zaloOnboardingAdapter } from "./onboarding.js";
@@ -88,7 +93,8 @@ export const zaloPlugin: ChannelPlugin<ResolvedZaloAccount> = {
configSchema: buildChannelConfigSchema(ZaloConfigSchema),
config: {
listAccountIds: (cfg) => listZaloAccountIds(cfg as OpenClawConfig),
resolveAccount: (cfg, accountId) => resolveZaloAccount({ cfg: cfg as OpenClawConfig, accountId }),
resolveAccount: (cfg, accountId) =>
resolveZaloAccount({ cfg: cfg as OpenClawConfig, accountId }),
defaultAccountId: (cfg) => resolveDefaultZaloAccountId(cfg as OpenClawConfig),
setAccountEnabled: ({ cfg, accountId, enabled }) =>
setAccountEnabledInConfigSection({
+10 -29
View File
@@ -137,9 +137,7 @@ export function registerZaloWebhookTarget(target: WebhookTarget): () => void {
const next = [...existing, normalizedTarget];
webhookTargets.set(key, next);
return () => {
const updated = (webhookTargets.get(key) ?? []).filter(
(entry) => entry !== normalizedTarget,
);
const updated = (webhookTargets.get(key) ?? []).filter((entry) => entry !== normalizedTarget);
if (updated.length > 0) {
webhookTargets.set(key, updated);
} else {
@@ -181,12 +179,11 @@ export async function handleZaloWebhookRequest(
// Zalo sends updates directly as { event_name, message, ... }, not wrapped in { ok, result }
const raw = body.value;
const record =
raw && typeof raw === "object" ? (raw as Record<string, unknown>) : null;
const record = raw && typeof raw === "object" ? (raw as Record<string, unknown>) : null;
const update: ZaloUpdate | undefined =
record && record.ok === true && record.result
? (record.result as ZaloUpdate)
: (record as ZaloUpdate | null) ?? undefined;
: ((record as ZaloUpdate | null) ?? undefined);
if (!update?.event_name) {
res.statusCode = 400;
@@ -292,16 +289,7 @@ async function processUpdate(
switch (event_name) {
case "message.text.received":
await handleTextMessage(
message,
token,
account,
config,
runtime,
core,
statusSink,
fetcher,
);
await handleTextMessage(message, token, account, config, runtime, core, statusSink, fetcher);
break;
case "message.image.received":
await handleImageMessage(
@@ -439,10 +427,7 @@ async function processMessageWithPipeline(params: {
const dmPolicy = account.config.dmPolicy ?? "pairing";
const configAllowFrom = (account.config.allowFrom ?? []).map((v) => String(v));
const rawBody = text?.trim() || (mediaPath ? "<media:image>" : "");
const shouldComputeAuth = core.channel.commands.shouldComputeCommandAuthorized(
rawBody,
config,
);
const shouldComputeAuth = core.channel.commands.shouldComputeCommandAuthorized(rawBody, config);
const storeAllowFrom =
!isGroup && (dmPolicy !== "open" || shouldComputeAuth)
? await core.channel.pairing.readAllowFromStore("zalo").catch(() => [])
@@ -453,7 +438,9 @@ async function processMessageWithPipeline(params: {
const commandAuthorized = shouldComputeAuth
? core.channel.commands.resolveCommandAuthorizedFromAuthorizers({
useAccessGroups,
authorizers: [{ configured: effectiveAllowFrom.length > 0, allowed: senderAllowedForCommands }],
authorizers: [
{ configured: effectiveAllowFrom.length > 0, allowed: senderAllowedForCommands },
],
})
: undefined;
@@ -649,11 +636,7 @@ async function deliverZaloReply(params: {
if (text) {
const chunkMode = core.channel.text.resolveChunkMode(config, "zalo", accountId);
const chunks = core.channel.text.chunkMarkdownTextWithMode(
text,
ZALO_TEXT_LIMIT,
chunkMode,
);
const chunks = core.channel.text.chunkMarkdownTextWithMode(text, ZALO_TEXT_LIMIT, chunkMode);
for (const chunk of chunks) {
try {
await sendMessage(token, { chat_id: chatId, text: chunk }, fetcher);
@@ -665,9 +648,7 @@ async function deliverZaloReply(params: {
}
}
export async function monitorZaloProvider(
options: ZaloMonitorOptions,
): Promise<ZaloMonitorResult> {
export async function monitorZaloProvider(options: ZaloMonitorOptions): Promise<ZaloMonitorResult> {
const {
token,
account,
+19 -16
View File
@@ -46,23 +46,26 @@ describe("handleZaloWebhookRequest", () => {
});
try {
await withServer(async (req, res) => {
const handled = await handleZaloWebhookRequest(req, res);
if (!handled) {
res.statusCode = 404;
res.end("not found");
}
}, async (baseUrl) => {
const response = await fetch(`${baseUrl}/hook`, {
method: "POST",
headers: {
"x-bot-api-secret-token": "secret",
},
body: "null",
});
await withServer(
async (req, res) => {
const handled = await handleZaloWebhookRequest(req, res);
if (!handled) {
res.statusCode = 404;
res.end("not found");
}
},
async (baseUrl) => {
const response = await fetch(`${baseUrl}/hook`, {
method: "POST",
headers: {
"x-bot-api-secret-token": "secret",
},
body: "null",
});
expect(response.status).toBe(400);
});
expect(response.status).toBe(400);
},
);
} finally {
unregister();
}
+15 -18
View File
@@ -11,11 +11,7 @@ import {
promptAccountId,
} from "openclaw/plugin-sdk";
import {
listZaloAccountIds,
resolveDefaultZaloAccountId,
resolveZaloAccount,
} from "./accounts.js";
import { listZaloAccountIds, resolveDefaultZaloAccountId, resolveZaloAccount } from "./accounts.js";
const channel = "zalo" as const;
@@ -25,7 +21,8 @@ function setZaloDmPolicy(
cfg: OpenClawConfig,
dmPolicy: "pairing" | "allowlist" | "open" | "disabled",
) {
const allowFrom = dmPolicy === "open" ? addWildcardAllowFrom(cfg.channels?.zalo?.allowFrom) : undefined;
const allowFrom =
dmPolicy === "open" ? addWildcardAllowFrom(cfg.channels?.zalo?.allowFrom) : undefined;
return {
...cfg,
channels: {
@@ -69,12 +66,7 @@ function setZaloUpdateMode(
Record<string, unknown>
>;
const existing = accounts[accountId] ?? {};
const {
webhookUrl: _url,
webhookSecret: _secret,
webhookPath: _path,
...rest
} = existing;
const { webhookUrl: _url, webhookSecret: _secret, webhookPath: _path, ...rest } = existing;
accounts[accountId] = rest;
return {
...cfg,
@@ -210,7 +202,7 @@ const dmPolicy: ChannelOnboardingDmPolicy = {
promptAllowFrom: async ({ cfg, prompter, accountId }) => {
const id =
accountId && normalizeAccountId(accountId)
? normalizeAccountId(accountId) ?? DEFAULT_ACCOUNT_ID
? (normalizeAccountId(accountId) ?? DEFAULT_ACCOUNT_ID)
: resolveDefaultZaloAccountId(cfg as OpenClawConfig);
return promptZaloAllowFrom({
cfg: cfg as OpenClawConfig,
@@ -235,12 +227,16 @@ export const zaloOnboardingAdapter: ChannelOnboardingAdapter = {
quickstartScore: configured ? 1 : 10,
};
},
configure: async ({ cfg, prompter, accountOverrides, shouldPromptAccountIds, forceAllowFrom }) => {
configure: async ({
cfg,
prompter,
accountOverrides,
shouldPromptAccountIds,
forceAllowFrom,
}) => {
const zaloOverride = accountOverrides.zalo?.trim();
const defaultZaloAccountId = resolveDefaultZaloAccountId(cfg as OpenClawConfig);
let zaloAccountId = zaloOverride
? normalizeAccountId(zaloOverride)
: defaultZaloAccountId;
let zaloAccountId = zaloOverride ? normalizeAccountId(zaloOverride) : defaultZaloAccountId;
if (shouldPromptAccountIds && !zaloOverride) {
zaloAccountId = await promptAccountId({
cfg: cfg as OpenClawConfig,
@@ -354,7 +350,8 @@ export const zaloOnboardingAdapter: ChannelOnboardingAdapter = {
const webhookUrl = String(
await prompter.text({
message: "Webhook URL (https://...) ",
validate: (value) => (value?.trim()?.startsWith("https://") ? undefined : "HTTPS URL required"),
validate: (value) =>
value?.trim()?.startsWith("https://") ? undefined : "HTTPS URL required",
}),
).trim();
const defaultPath = (() => {
+17 -9
View File
@@ -65,10 +65,14 @@ export async function sendMessageZalo(
}
try {
const response = await sendMessage(token, {
chat_id: chatId.trim(),
text: text.slice(0, 2000),
}, fetcher);
const response = await sendMessage(
token,
{
chat_id: chatId.trim(),
text: text.slice(0, 2000),
},
fetcher,
);
if (response.ok && response.result) {
return { ok: true, messageId: response.result.message_id };
@@ -100,11 +104,15 @@ export async function sendPhotoZalo(
}
try {
const response = await sendPhoto(token, {
chat_id: chatId.trim(),
photo: photoUrl.trim(),
caption: options.caption?.slice(0, 2000),
}, fetcher);
const response = await sendPhoto(
token,
{
chat_id: chatId.trim(),
photo: photoUrl.trim(),
caption: options.caption?.slice(0, 2000),
},
fetcher,
);
if (response.ok && response.result) {
return { ok: true, messageId: response.result.message_id };
+2 -5
View File
@@ -23,9 +23,7 @@ function readZaloAccountStatus(value: ChannelAccountSnapshot): ZaloAccountStatus
};
}
export function collectZaloStatusIssues(
accounts: ChannelAccountSnapshot[],
): ChannelStatusIssue[] {
export function collectZaloStatusIssues(accounts: ChannelAccountSnapshot[]): ChannelStatusIssue[] {
const issues: ChannelStatusIssue[] = [];
for (const entry of accounts) {
const account = readZaloAccountStatus(entry);
@@ -40,8 +38,7 @@ export function collectZaloStatusIssues(
channel: "zalo",
accountId,
kind: "config",
message:
'Zalo dmPolicy is "open", allowing any user to message the bot without pairing.',
message: 'Zalo dmPolicy is "open", allowing any user to message the bot without pairing.',
fix: 'Set channels.zalo.dmPolicy to "pairing" or "allowlist" to restrict access.',
});
}