refactor: share zalo status issue helpers

This commit is contained in:
Peter Steinberger 2026-03-14 01:12:57 +00:00
parent 7285e04ead
commit 1ec6b012f8
4 changed files with 61 additions and 54 deletions

View File

@ -0,0 +1,18 @@
export function readStatusIssueFields<TField extends string>(
value: unknown,
fields: readonly TField[],
): Record<TField, unknown> | null {
if (!value || typeof value !== "object") {
return null;
}
const record = value as Record<string, unknown>;
const result = {} as Record<TField, unknown>;
for (const field of fields) {
result[field] = record[field];
}
return result;
}
export function coerceStatusIssueAccountId(value: unknown): string | undefined {
return typeof value === "string" ? value : typeof value === "number" ? String(value) : undefined;
}

View File

@ -0,0 +1,29 @@
import { describe, expect, it } from "vitest";
import { collectZaloStatusIssues } from "./status-issues.js";
describe("collectZaloStatusIssues", () => {
it("warns when dmPolicy is open", () => {
const issues = collectZaloStatusIssues([
{
accountId: "default",
enabled: true,
configured: true,
dmPolicy: "open",
},
]);
expect(issues).toHaveLength(1);
expect(issues[0]?.kind).toBe("config");
});
it("skips unconfigured accounts", () => {
const issues = collectZaloStatusIssues([
{
accountId: "default",
enabled: true,
configured: false,
dmPolicy: "open",
},
]);
expect(issues).toHaveLength(0);
});
});

View File

@ -1,38 +1,16 @@
import type { ChannelAccountSnapshot, ChannelStatusIssue } from "openclaw/plugin-sdk/zalo"; import type { ChannelAccountSnapshot, ChannelStatusIssue } from "openclaw/plugin-sdk/zalo";
import { coerceStatusIssueAccountId, readStatusIssueFields } from "../../shared/status-issues.js";
type ZaloAccountStatus = { const ZALO_STATUS_FIELDS = ["accountId", "enabled", "configured", "dmPolicy"] as const;
accountId?: unknown;
enabled?: unknown;
configured?: unknown;
dmPolicy?: unknown;
};
const isRecord = (value: unknown): value is Record<string, unknown> =>
Boolean(value && typeof value === "object");
const asString = (value: unknown): string | undefined =>
typeof value === "string" ? value : typeof value === "number" ? String(value) : undefined;
function readZaloAccountStatus(value: ChannelAccountSnapshot): ZaloAccountStatus | null {
if (!isRecord(value)) {
return null;
}
return {
accountId: value.accountId,
enabled: value.enabled,
configured: value.configured,
dmPolicy: value.dmPolicy,
};
}
export function collectZaloStatusIssues(accounts: ChannelAccountSnapshot[]): ChannelStatusIssue[] { export function collectZaloStatusIssues(accounts: ChannelAccountSnapshot[]): ChannelStatusIssue[] {
const issues: ChannelStatusIssue[] = []; const issues: ChannelStatusIssue[] = [];
for (const entry of accounts) { for (const entry of accounts) {
const account = readZaloAccountStatus(entry); const account = readStatusIssueFields(entry, ZALO_STATUS_FIELDS);
if (!account) { if (!account) {
continue; continue;
} }
const accountId = asString(account.accountId) ?? "default"; const accountId = coerceStatusIssueAccountId(account.accountId) ?? "default";
const enabled = account.enabled !== false; const enabled = account.enabled !== false;
const configured = account.configured === true; const configured = account.configured === true;
if (!enabled || !configured) { if (!enabled || !configured) {

View File

@ -1,42 +1,24 @@
import type { ChannelAccountSnapshot, ChannelStatusIssue } from "openclaw/plugin-sdk/zalouser"; import type { ChannelAccountSnapshot, ChannelStatusIssue } from "openclaw/plugin-sdk/zalouser";
import { coerceStatusIssueAccountId, readStatusIssueFields } from "../../shared/status-issues.js";
type ZalouserAccountStatus = { const ZALOUSER_STATUS_FIELDS = [
accountId?: unknown; "accountId",
enabled?: unknown; "enabled",
configured?: unknown; "configured",
dmPolicy?: unknown; "dmPolicy",
lastError?: unknown; "lastError",
}; ] as const;
const isRecord = (value: unknown): value is Record<string, unknown> =>
Boolean(value && typeof value === "object");
const asString = (value: unknown): string | undefined =>
typeof value === "string" ? value : typeof value === "number" ? String(value) : undefined;
function readZalouserAccountStatus(value: ChannelAccountSnapshot): ZalouserAccountStatus | null {
if (!isRecord(value)) {
return null;
}
return {
accountId: value.accountId,
enabled: value.enabled,
configured: value.configured,
dmPolicy: value.dmPolicy,
lastError: value.lastError,
};
}
export function collectZalouserStatusIssues( export function collectZalouserStatusIssues(
accounts: ChannelAccountSnapshot[], accounts: ChannelAccountSnapshot[],
): ChannelStatusIssue[] { ): ChannelStatusIssue[] {
const issues: ChannelStatusIssue[] = []; const issues: ChannelStatusIssue[] = [];
for (const entry of accounts) { for (const entry of accounts) {
const account = readZalouserAccountStatus(entry); const account = readStatusIssueFields(entry, ZALOUSER_STATUS_FIELDS);
if (!account) { if (!account) {
continue; continue;
} }
const accountId = asString(account.accountId) ?? "default"; const accountId = coerceStatusIssueAccountId(account.accountId) ?? "default";
const enabled = account.enabled !== false; const enabled = account.enabled !== false;
if (!enabled) { if (!enabled) {
continue; continue;