mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
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:
committed by
GitHub
parent
66fe424590
commit
b080dd1e76
@@ -6,7 +6,10 @@ import { normalizeAccountId, type OpenClawConfig } from "openclaw/plugin-sdk/acc
|
||||
// Imessage plugin module implements accounts behavior.
|
||||
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
||||
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 { IMessageAccountConfig } from "./account-types.js";
|
||||
import {
|
||||
expandIMessageUserPath,
|
||||
@@ -45,9 +48,7 @@ function resolveIMessageAccountConfig(
|
||||
type IMessageStreamingConfig = NonNullable<IMessageAccountConfig["streaming"]>;
|
||||
|
||||
function asStreamingConfigObject(value: unknown): IMessageStreamingConfig | undefined {
|
||||
return value && typeof value === "object" && !Array.isArray(value)
|
||||
? (value as IMessageStreamingConfig)
|
||||
: undefined;
|
||||
return asOptionalRecord(value) as IMessageStreamingConfig | undefined;
|
||||
}
|
||||
|
||||
function mergeIMessageStreamingConfig(
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
parseStrictInteger,
|
||||
resolveExpiresAtMsFromDurationMs,
|
||||
} from "openclaw/plugin-sdk/number-runtime";
|
||||
import { normalizeOptionalString as stringFromUnknown } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import type { IMessageActionTransportOptions } from "./actions-rpc.js";
|
||||
import { normalizeDirectChatIdentifier } from "./chat-context.js";
|
||||
import { createIMessageRpcClient } from "./client.js";
|
||||
@@ -41,10 +42,6 @@ function numberFromUnknown(value: unknown): number | undefined {
|
||||
return typeof value === "number" && Number.isFinite(value) ? value : parseStrictInteger(value);
|
||||
}
|
||||
|
||||
function stringFromUnknown(value: unknown): string | undefined {
|
||||
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
||||
}
|
||||
|
||||
function chatListCacheKey(options: IMessageActionTransportOptions): string {
|
||||
return `${options.cliPath}\0${options.dbPath ?? ""}\0${options.remoteHost ?? ""}`;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import {
|
||||
asDateTimestampMs,
|
||||
asPositiveFiniteNumber,
|
||||
resolveExpiresAtMsFromDurationMs,
|
||||
} from "openclaw/plugin-sdk/number-runtime";
|
||||
import type { IMessageApprovalGatewayRuntime } from "./approval-gateway-types.js";
|
||||
@@ -38,7 +39,7 @@ type HistoryMessage = IMessagePayload & {
|
||||
};
|
||||
|
||||
function normalizeChatId(value: unknown): number | null {
|
||||
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
|
||||
return asPositiveFiniteNumber(value) ?? null;
|
||||
}
|
||||
|
||||
function listTargetChatIds(
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
formatInboundEnvelope,
|
||||
type resolveEnvelopeFormatOptions,
|
||||
} from "openclaw/plugin-sdk/channel-inbound";
|
||||
import { parseDateStringTimestampMs } from "openclaw/plugin-sdk/number-runtime";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import type { IMessageRpcClient } from "../client.js";
|
||||
import { normalizeIMessageHandle } from "../targets.js";
|
||||
@@ -87,8 +88,7 @@ function historyEntryFromMessage(message: IMessagePayload, fallbackSender: strin
|
||||
if (!body) {
|
||||
return null;
|
||||
}
|
||||
const timestamp =
|
||||
typeof message.created_at === "string" ? Date.parse(message.created_at) : Number.NaN;
|
||||
const timestamp = parseDateStringTimestampMs(message.created_at);
|
||||
return {
|
||||
sender:
|
||||
message.is_from_me === true
|
||||
@@ -96,7 +96,7 @@ function historyEntryFromMessage(message: IMessagePayload, fallbackSender: strin
|
||||
: normalizeIMessageHandle(normalizeOptionalString(message.sender) ?? fallbackSender) ||
|
||||
fallbackSender,
|
||||
body,
|
||||
...(Number.isFinite(timestamp) ? { timestamp } : {}),
|
||||
...(timestamp !== undefined ? { timestamp } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { isRecord } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
||||
import { collectErrorGraphCandidates, formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
|
||||
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { asSafeIntegerInRange } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { getIMessageRuntime } from "../runtime.js";
|
||||
import { parseIMessageNotification } from "./parse-notification.js";
|
||||
import type { IMessagePayload } from "./types.js";
|
||||
@@ -62,8 +63,7 @@ function rawMessageRecord(raw: unknown): Record<string, unknown> | null {
|
||||
}
|
||||
|
||||
function rawRowid(raw: unknown): number | null {
|
||||
const rowid = rawMessageRecord(raw)?.id;
|
||||
return typeof rowid === "number" && Number.isSafeInteger(rowid) && rowid >= 0 ? rowid : null;
|
||||
return asSafeIntegerInRange(rawMessageRecord(raw)?.id, { min: 0 }) ?? null;
|
||||
}
|
||||
|
||||
/** Read only stable transport metadata; payload normalization waits for dispatch. */
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
|
||||
import { sleep as delay } from "openclaw/plugin-sdk/runtime-env";
|
||||
import { openNodeSqliteDatabase } from "openclaw/plugin-sdk/sqlite-runtime";
|
||||
import { normalizeOptionalString as stringValue } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
|
||||
import { convertMarkdownTables } from "openclaw/plugin-sdk/text-chunking";
|
||||
import { stripInlineDirectiveTagsForDelivery } from "openclaw/plugin-sdk/text-chunking";
|
||||
@@ -518,10 +519,6 @@ async function runIMessageCliJson(
|
||||
});
|
||||
}
|
||||
|
||||
function stringValue(value: unknown): string | undefined {
|
||||
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
||||
}
|
||||
|
||||
function resultService(value: unknown): Exclude<IMessageService, "auto"> | undefined {
|
||||
const normalized = stringValue(value)?.toLowerCase();
|
||||
return normalized === "imessage" || normalized === "sms" ? normalized : undefined;
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { ChannelLegacyStateMigrationPlan } from "openclaw/plugin-sdk/channe
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import { fileExists } from "openclaw/plugin-sdk/security-runtime";
|
||||
import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
|
||||
import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { asFiniteNumber, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import {
|
||||
listIMessageAccountIds,
|
||||
resolveDefaultIMessageAccountId,
|
||||
@@ -131,7 +131,7 @@ function readReplyCounterValue(value: unknown): number | null {
|
||||
return null;
|
||||
}
|
||||
const counter = (value as { counter?: unknown }).counter;
|
||||
return typeof counter === "number" && Number.isFinite(counter) ? counter : null;
|
||||
return asFiniteNumber(counter) ?? null;
|
||||
}
|
||||
|
||||
function shouldReplaceReplyCounter(existingValue: unknown, incomingValue: unknown): boolean {
|
||||
|
||||
Reference in New Issue
Block a user