refactor: consolidate coercion contracts (#122458)

* refactor: consolidate coercion contracts

Centralize exact string, record, numeric, date, Boolean, argument, and structured-error coercions while preserving call-site semantics.

Migrate canonical-name collisions and deprecated internal SDK bypasses, deleting 55 net production/tooling lines. Expand declaration ownership enforcement to 101 allowed helpers and add a narrow export-completeness audit.

* fix: preserve standalone script coercions

Keep copied Control UI tooling self-contained and retain the trusted release harness module-relative source seam when the harness runs against an old target cwd.
This commit is contained in:
Peter Steinberger
2026-08-11 23:26:37 -07:00
committed by GitHub
parent 66fe424590
commit b080dd1e76
276 changed files with 1685 additions and 1663 deletions
+5 -4
View File
@@ -12,7 +12,10 @@ import {
type ChannelDmPolicy,
} from "openclaw/plugin-sdk/channel-config-helpers";
import { resolveAccountEntry } from "openclaw/plugin-sdk/routing";
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
import {
asOptionalRecord,
normalizeOptionalString,
} from "openclaw/plugin-sdk/string-coerce-runtime";
import type { SlackAccountSurfaceFields } from "./account-surface-fields.js";
import type { SlackAccountConfig } from "./runtime-api.js";
import { resolveSlackAppToken, resolveSlackBotToken, resolveSlackUserToken } from "./token.js";
@@ -123,9 +126,7 @@ type SlackStreamingConfig = NonNullable<SlackAccountConfig["streaming"]>;
type SlackStreamingConfigValue = SlackStreamingConfig | boolean | string;
function asStreamingConfigObject(value: unknown): SlackStreamingConfig | undefined {
return value && typeof value === "object" && !Array.isArray(value)
? (value as SlackStreamingConfig)
: undefined;
return asOptionalRecord(value) as SlackStreamingConfig | undefined;
}
function asLegacyStreamingScalar(value: unknown): boolean | string | undefined {
@@ -11,6 +11,7 @@ import {
timestampMsToIsoString,
} from "openclaw/plugin-sdk/number-runtime";
import {
asOptionalRecord,
normalizeOptionalString,
normalizeUniqueTrimmedStringList,
} from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -189,13 +190,6 @@ function summarizeRichTextPreview(value: unknown): string | undefined {
return joined.length <= max ? joined : truncateSlackText(joined, max);
}
function readInteractionAction(raw: unknown) {
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
return undefined;
}
return raw as Record<string, unknown>;
}
export function summarizeAction(action: Record<string, unknown>): SlackActionSummary {
const typed = action as {
type?: string;
@@ -431,7 +425,7 @@ function parseSlackBlockAction(params: {
log?: (message: string) => void;
}): ParsedSlackBlockAction | null {
const typedBody = params.body as SlackBlockActionBody;
const typedAction = readInteractionAction(params.action);
const typedAction = asOptionalRecord(params.action);
if (!typedAction) {
params.log?.(
`slack:interaction malformed action payload channel=${typedBody.channel?.id ?? typedBody.container?.channel_id ?? "unknown"} user=${
@@ -871,13 +871,14 @@ vi.mock("openclaw/plugin-sdk/security-runtime", () => ({
resolvePinnedMainDmOwnerFromAllowlist: () => mockedPinnedMainDmOwner,
}));
vi.mock("openclaw/plugin-sdk/string-coerce-runtime", () => {
const isMockRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null && !Array.isArray(value);
vi.mock("openclaw/plugin-sdk/string-coerce-runtime", async (importOriginal) => {
const { asOptionalRecord, isRecord } =
await importOriginal<typeof import("openclaw/plugin-sdk/string-coerce-runtime")>();
const normalizeMockLowercaseString = (value?: string) => value?.toLowerCase();
const readMockOptionalString = (value?: string) => value;
return {
isRecord: isMockRecord,
asOptionalRecord,
isRecord,
normalizeOptionalLowercaseString: normalizeMockLowercaseString,
normalizeOptionalString: readMockOptionalString,
};