mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-13 15:47:28 +00:00
fix(cycles): split small runtime seams
This commit is contained in:
@@ -6,6 +6,8 @@ import { buildFileInfoCard, parseFileConsentInvoke, uploadToConsentUrl } from ".
|
|||||||
import { extractMSTeamsConversationMessageId, normalizeMSTeamsConversationId } from "./inbound.js";
|
import { extractMSTeamsConversationMessageId, normalizeMSTeamsConversationId } from "./inbound.js";
|
||||||
import { resolveMSTeamsSenderAccess } from "./monitor-handler/access.js";
|
import { resolveMSTeamsSenderAccess } from "./monitor-handler/access.js";
|
||||||
import { createMSTeamsMessageHandler } from "./monitor-handler/message-handler.js";
|
import { createMSTeamsMessageHandler } from "./monitor-handler/message-handler.js";
|
||||||
|
export type { MSTeamsAccessTokenProvider } from "./attachments/types.js";
|
||||||
|
import type { MSTeamsAccessTokenProvider } from "./attachments/types.js";
|
||||||
import type { MSTeamsMonitorLogger } from "./monitor-types.js";
|
import type { MSTeamsMonitorLogger } from "./monitor-types.js";
|
||||||
import { getPendingUpload, removePendingUpload } from "./pending-uploads.js";
|
import { getPendingUpload, removePendingUpload } from "./pending-uploads.js";
|
||||||
import { withRevokedProxyFallback } from "./revoked-context.js";
|
import { withRevokedProxyFallback } from "./revoked-context.js";
|
||||||
@@ -14,7 +16,6 @@ import type { MSTeamsTurnContext } from "./sdk-types.js";
|
|||||||
import {
|
import {
|
||||||
handleSigninTokenExchangeInvoke,
|
handleSigninTokenExchangeInvoke,
|
||||||
handleSigninVerifyStateInvoke,
|
handleSigninVerifyStateInvoke,
|
||||||
type MSTeamsSsoDeps,
|
|
||||||
parseSigninTokenExchangeValue,
|
parseSigninTokenExchangeValue,
|
||||||
parseSigninVerifyStateValue,
|
parseSigninVerifyStateValue,
|
||||||
} from "./sso.js";
|
} from "./sso.js";
|
||||||
@@ -22,10 +23,6 @@ import { buildGroupWelcomeText, buildWelcomeCard } from "./welcome-card.js";
|
|||||||
export type { MSTeamsMessageHandlerDeps } from "./monitor-handler.types.js";
|
export type { MSTeamsMessageHandlerDeps } from "./monitor-handler.types.js";
|
||||||
import type { MSTeamsMessageHandlerDeps } from "./monitor-handler.types.js";
|
import type { MSTeamsMessageHandlerDeps } from "./monitor-handler.types.js";
|
||||||
|
|
||||||
export type MSTeamsAccessTokenProvider = {
|
|
||||||
getAccessToken: (scope: string) => Promise<string>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MSTeamsActivityHandler = {
|
export type MSTeamsActivityHandler = {
|
||||||
onMessage: (
|
onMessage: (
|
||||||
handler: (context: unknown, next: () => Promise<void>) => Promise<void>,
|
handler: (context: unknown, next: () => Promise<void>) => Promise<void>,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
* that ack; these helpers encapsulate token exchange and persistence.
|
* that ack; these helpers encapsulate token exchange and persistence.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { MSTeamsAccessTokenProvider } from "./monitor-handler.js";
|
import type { MSTeamsAccessTokenProvider } from "./attachments/types.js";
|
||||||
import type { MSTeamsSsoTokenStore } from "./sso-token-store.js";
|
import type { MSTeamsSsoTokenStore } from "./sso-token-store.js";
|
||||||
import { buildUserAgent } from "./user-agent.js";
|
import { buildUserAgent } from "./user-agent.js";
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
startBackgroundTokenRefresh,
|
startBackgroundTokenRefresh,
|
||||||
stopBackgroundTokenRefresh,
|
stopBackgroundTokenRefresh,
|
||||||
} from "./api.js";
|
} from "./api.js";
|
||||||
import { qqbotPlugin } from "./channel.js";
|
import { formatQQBotAllowFrom } from "./channel-config-shared.js";
|
||||||
import { formatVoiceText, processAttachments } from "./inbound-attachments.js";
|
import { formatVoiceText, processAttachments } from "./inbound-attachments.js";
|
||||||
import { flushKnownUsers, recordKnownUser } from "./known-users.js";
|
import { flushKnownUsers, recordKnownUser } from "./known-users.js";
|
||||||
import { createMessageQueue, type QueuedMessage } from "./message-queue.js";
|
import { createMessageQueue, type QueuedMessage } from "./message-queue.js";
|
||||||
@@ -748,13 +748,9 @@ export async function startGateway(ctx: GatewayContext): Promise<void> {
|
|||||||
const toAddress = fromAddress;
|
const toAddress = fromAddress;
|
||||||
|
|
||||||
const rawAllowFrom = account.config?.allowFrom ?? [];
|
const rawAllowFrom = account.config?.allowFrom ?? [];
|
||||||
const normalizedAllowFrom = qqbotPlugin.config?.formatAllowFrom
|
const normalizedAllowFrom = formatQQBotAllowFrom({
|
||||||
? qqbotPlugin.config.formatAllowFrom({
|
allowFrom: rawAllowFrom,
|
||||||
cfg: cfg,
|
});
|
||||||
accountId: account.accountId,
|
|
||||||
allowFrom: rawAllowFrom,
|
|
||||||
})
|
|
||||||
: rawAllowFrom.map((e: string) => e.replace(/^qqbot:/i, "").toUpperCase());
|
|
||||||
const normalizedSenderId = event.senderId.replace(/^qqbot:/i, "").toUpperCase();
|
const normalizedSenderId = event.senderId.replace(/^qqbot:/i, "").toUpperCase();
|
||||||
const allowAll =
|
const allowAll =
|
||||||
normalizedAllowFrom.length === 0 || normalizedAllowFrom.some((e) => e === "*");
|
normalizedAllowFrom.length === 0 || normalizedAllowFrom.some((e) => e === "*");
|
||||||
|
|||||||
@@ -36,11 +36,8 @@ import {
|
|||||||
warnMissingProviderGroupPolicyFallbackOnce,
|
warnMissingProviderGroupPolicyFallbackOnce,
|
||||||
} from "./runtime-api.js";
|
} from "./runtime-api.js";
|
||||||
import { getZaloRuntime } from "./runtime.js";
|
import { getZaloRuntime } from "./runtime.js";
|
||||||
|
export type { ZaloRuntimeEnv } from "./monitor.types.js";
|
||||||
export type ZaloRuntimeEnv = {
|
import type { ZaloRuntimeEnv } from "./monitor.types.js";
|
||||||
log?: (message: string) => void;
|
|
||||||
error?: (message: string) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ZaloMonitorOptions = {
|
export type ZaloMonitorOptions = {
|
||||||
token: string;
|
token: string;
|
||||||
|
|||||||
4
extensions/zalo/src/monitor.types.ts
Normal file
4
extensions/zalo/src/monitor.types.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export type ZaloRuntimeEnv = {
|
||||||
|
log?: (message: string) => void;
|
||||||
|
error?: (message: string) => void;
|
||||||
|
};
|
||||||
@@ -2,7 +2,7 @@ import type { IncomingMessage, ServerResponse } from "node:http";
|
|||||||
import { safeEqualSecret } from "openclaw/plugin-sdk/browser-security-runtime";
|
import { safeEqualSecret } from "openclaw/plugin-sdk/browser-security-runtime";
|
||||||
import type { ResolvedZaloAccount } from "./accounts.js";
|
import type { ResolvedZaloAccount } from "./accounts.js";
|
||||||
import type { ZaloFetch, ZaloUpdate } from "./api.js";
|
import type { ZaloFetch, ZaloUpdate } from "./api.js";
|
||||||
import type { ZaloRuntimeEnv } from "./monitor.js";
|
import type { ZaloRuntimeEnv } from "./monitor.types.js";
|
||||||
import {
|
import {
|
||||||
createDedupeCache,
|
createDedupeCache,
|
||||||
createFixedWindowRateLimiter,
|
createFixedWindowRateLimiter,
|
||||||
|
|||||||
93
extensions/zalo/src/setup-allow-from.ts
Normal file
93
extensions/zalo/src/setup-allow-from.ts
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import {
|
||||||
|
DEFAULT_ACCOUNT_ID,
|
||||||
|
formatDocsLink,
|
||||||
|
mergeAllowFromEntries,
|
||||||
|
type ChannelSetupDmPolicy,
|
||||||
|
type ChannelSetupWizard,
|
||||||
|
type OpenClawConfig,
|
||||||
|
} from "openclaw/plugin-sdk/setup";
|
||||||
|
import { resolveZaloAccount } from "./accounts.js";
|
||||||
|
|
||||||
|
type ZaloAccountSetupConfig = {
|
||||||
|
enabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function noteZaloTokenHelp(
|
||||||
|
prompter: Parameters<NonNullable<ChannelSetupWizard["finalize"]>>[0]["prompter"],
|
||||||
|
): Promise<void> {
|
||||||
|
await prompter.note(
|
||||||
|
[
|
||||||
|
"1) Open Zalo Bot Platform: https://bot.zaloplatforms.com",
|
||||||
|
"2) Create a bot and get the token",
|
||||||
|
"3) Token looks like 12345689:abc-xyz",
|
||||||
|
"Tip: you can also set ZALO_BOT_TOKEN in your env.",
|
||||||
|
`Docs: ${formatDocsLink("/channels/zalo", "zalo")}`,
|
||||||
|
].join("\n"),
|
||||||
|
"Zalo bot token",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function promptZaloAllowFrom(params: {
|
||||||
|
cfg: OpenClawConfig;
|
||||||
|
prompter: Parameters<NonNullable<ChannelSetupDmPolicy["promptAllowFrom"]>>[0]["prompter"];
|
||||||
|
accountId: string;
|
||||||
|
}): Promise<OpenClawConfig> {
|
||||||
|
const { cfg, prompter, accountId } = params;
|
||||||
|
const resolved = resolveZaloAccount({ cfg, accountId });
|
||||||
|
const existingAllowFrom = resolved.config.allowFrom ?? [];
|
||||||
|
const entry = await prompter.text({
|
||||||
|
message: "Zalo allowFrom (user id)",
|
||||||
|
placeholder: "123456789",
|
||||||
|
initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,
|
||||||
|
validate: (value) => {
|
||||||
|
const raw = String(value ?? "").trim();
|
||||||
|
if (!raw) {
|
||||||
|
return "Required";
|
||||||
|
}
|
||||||
|
if (!/^\d+$/.test(raw)) {
|
||||||
|
return "Use a numeric Zalo user id";
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const normalized = String(entry).trim();
|
||||||
|
const unique = mergeAllowFromEntries(existingAllowFrom, [normalized]);
|
||||||
|
|
||||||
|
if (accountId === DEFAULT_ACCOUNT_ID) {
|
||||||
|
return {
|
||||||
|
...cfg,
|
||||||
|
channels: {
|
||||||
|
...cfg.channels,
|
||||||
|
zalo: {
|
||||||
|
...cfg.channels?.zalo,
|
||||||
|
enabled: true,
|
||||||
|
dmPolicy: "allowlist",
|
||||||
|
allowFrom: unique,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as OpenClawConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentAccount = cfg.channels?.zalo?.accounts?.[accountId] as
|
||||||
|
| ZaloAccountSetupConfig
|
||||||
|
| undefined;
|
||||||
|
return {
|
||||||
|
...cfg,
|
||||||
|
channels: {
|
||||||
|
...cfg.channels,
|
||||||
|
zalo: {
|
||||||
|
...cfg.channels?.zalo,
|
||||||
|
enabled: true,
|
||||||
|
accounts: {
|
||||||
|
...cfg.channels?.zalo?.accounts,
|
||||||
|
[accountId]: {
|
||||||
|
...currentAccount,
|
||||||
|
enabled: currentAccount?.enabled ?? true,
|
||||||
|
dmPolicy: "allowlist",
|
||||||
|
allowFrom: unique,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as OpenClawConfig;
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
type ChannelSetupWizard,
|
type ChannelSetupWizard,
|
||||||
} from "openclaw/plugin-sdk/setup";
|
} from "openclaw/plugin-sdk/setup";
|
||||||
import { resolveDefaultZaloAccountId, resolveZaloAccount } from "./accounts.js";
|
import { resolveDefaultZaloAccountId, resolveZaloAccount } from "./accounts.js";
|
||||||
|
import { promptZaloAllowFrom } from "./setup-allow-from.js";
|
||||||
|
|
||||||
const channel = "zalo" as const;
|
const channel = "zalo" as const;
|
||||||
|
|
||||||
@@ -109,14 +110,9 @@ export const zaloDmPolicy: ChannelSetupDmPolicy = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
promptAllowFrom: async (params) =>
|
promptAllowFrom: promptZaloAllowFrom,
|
||||||
(await loadZaloSetupWizard()).dmPolicy?.promptAllowFrom?.(params) ?? params.cfg,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
async function loadZaloSetupWizard(): Promise<ChannelSetupWizard> {
|
|
||||||
return (await import("./setup-surface.js")).zaloSetupWizard;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createZaloSetupWizardProxy(
|
export function createZaloSetupWizardProxy(
|
||||||
loadWizard: () => Promise<ChannelSetupWizard>,
|
loadWizard: () => Promise<ChannelSetupWizard>,
|
||||||
): ChannelSetupWizard {
|
): ChannelSetupWizard {
|
||||||
|
|||||||
@@ -2,27 +2,21 @@ import {
|
|||||||
buildSingleChannelSecretPromptState,
|
buildSingleChannelSecretPromptState,
|
||||||
createStandardChannelSetupStatus,
|
createStandardChannelSetupStatus,
|
||||||
DEFAULT_ACCOUNT_ID,
|
DEFAULT_ACCOUNT_ID,
|
||||||
formatDocsLink,
|
|
||||||
hasConfiguredSecretInput,
|
hasConfiguredSecretInput,
|
||||||
mergeAllowFromEntries,
|
|
||||||
promptSingleChannelSecretInput,
|
promptSingleChannelSecretInput,
|
||||||
runSingleChannelSecretStep,
|
runSingleChannelSecretStep,
|
||||||
type ChannelSetupDmPolicy,
|
|
||||||
type ChannelSetupWizard,
|
type ChannelSetupWizard,
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
type SecretInput,
|
type SecretInput,
|
||||||
} from "openclaw/plugin-sdk/setup";
|
} from "openclaw/plugin-sdk/setup";
|
||||||
import { resolveZaloAccount } from "./accounts.js";
|
import { resolveZaloAccount } from "./accounts.js";
|
||||||
|
import { noteZaloTokenHelp } from "./setup-allow-from.js";
|
||||||
import { zaloDmPolicy } from "./setup-core.js";
|
import { zaloDmPolicy } from "./setup-core.js";
|
||||||
|
|
||||||
const channel = "zalo" as const;
|
const channel = "zalo" as const;
|
||||||
|
|
||||||
type UpdateMode = "polling" | "webhook";
|
type UpdateMode = "polling" | "webhook";
|
||||||
|
|
||||||
type ZaloAccountSetupConfig = {
|
|
||||||
enabled?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
function setZaloUpdateMode(
|
function setZaloUpdateMode(
|
||||||
cfg: OpenClawConfig,
|
cfg: OpenClawConfig,
|
||||||
accountId: string,
|
accountId: string,
|
||||||
@@ -98,86 +92,6 @@ function setZaloUpdateMode(
|
|||||||
} as OpenClawConfig;
|
} as OpenClawConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function noteZaloTokenHelp(
|
|
||||||
prompter: Parameters<NonNullable<ChannelSetupWizard["finalize"]>>[0]["prompter"],
|
|
||||||
): Promise<void> {
|
|
||||||
await prompter.note(
|
|
||||||
[
|
|
||||||
"1) Open Zalo Bot Platform: https://bot.zaloplatforms.com",
|
|
||||||
"2) Create a bot and get the token",
|
|
||||||
"3) Token looks like 12345689:abc-xyz",
|
|
||||||
"Tip: you can also set ZALO_BOT_TOKEN in your env.",
|
|
||||||
`Docs: ${formatDocsLink("/channels/zalo", "zalo")}`,
|
|
||||||
].join("\n"),
|
|
||||||
"Zalo bot token",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function promptZaloAllowFrom(params: {
|
|
||||||
cfg: OpenClawConfig;
|
|
||||||
prompter: Parameters<NonNullable<ChannelSetupDmPolicy["promptAllowFrom"]>>[0]["prompter"];
|
|
||||||
accountId: string;
|
|
||||||
}): Promise<OpenClawConfig> {
|
|
||||||
const { cfg, prompter, accountId } = params;
|
|
||||||
const resolved = resolveZaloAccount({ cfg, accountId });
|
|
||||||
const existingAllowFrom = resolved.config.allowFrom ?? [];
|
|
||||||
const entry = await prompter.text({
|
|
||||||
message: "Zalo allowFrom (user id)",
|
|
||||||
placeholder: "123456789",
|
|
||||||
initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,
|
|
||||||
validate: (value) => {
|
|
||||||
const raw = String(value ?? "").trim();
|
|
||||||
if (!raw) {
|
|
||||||
return "Required";
|
|
||||||
}
|
|
||||||
if (!/^\d+$/.test(raw)) {
|
|
||||||
return "Use a numeric Zalo user id";
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const normalized = String(entry).trim();
|
|
||||||
const unique = mergeAllowFromEntries(existingAllowFrom, [normalized]);
|
|
||||||
|
|
||||||
if (accountId === DEFAULT_ACCOUNT_ID) {
|
|
||||||
return {
|
|
||||||
...cfg,
|
|
||||||
channels: {
|
|
||||||
...cfg.channels,
|
|
||||||
zalo: {
|
|
||||||
...cfg.channels?.zalo,
|
|
||||||
enabled: true,
|
|
||||||
dmPolicy: "allowlist",
|
|
||||||
allowFrom: unique,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as OpenClawConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentAccount = cfg.channels?.zalo?.accounts?.[accountId] as
|
|
||||||
| ZaloAccountSetupConfig
|
|
||||||
| undefined;
|
|
||||||
return {
|
|
||||||
...cfg,
|
|
||||||
channels: {
|
|
||||||
...cfg.channels,
|
|
||||||
zalo: {
|
|
||||||
...cfg.channels?.zalo,
|
|
||||||
enabled: true,
|
|
||||||
accounts: {
|
|
||||||
...cfg.channels?.zalo?.accounts,
|
|
||||||
[accountId]: {
|
|
||||||
...currentAccount,
|
|
||||||
enabled: currentAccount?.enabled ?? true,
|
|
||||||
dmPolicy: "allowlist",
|
|
||||||
allowFrom: unique,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as OpenClawConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export { zaloSetupAdapter } from "./setup-core.js";
|
export { zaloSetupAdapter } from "./setup-core.js";
|
||||||
|
|
||||||
export const zaloSetupWizard: ChannelSetupWizard = {
|
export const zaloSetupWizard: ChannelSetupWizard = {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { callGateway } from "../gateway/call.js";
|
import { callGateway } from "../gateway/call.js";
|
||||||
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
|
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
|
||||||
import type { GatewayRpcOpts } from "./gateway-rpc.js";
|
import type { GatewayRpcOpts } from "./gateway-rpc.types.js";
|
||||||
import { withProgress } from "./progress.js";
|
import { withProgress } from "./progress.js";
|
||||||
|
|
||||||
export async function callGatewayFromCliRuntime(
|
export async function callGatewayFromCliRuntime(
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
import type { Command } from "commander";
|
import type { Command } from "commander";
|
||||||
|
export type { GatewayRpcOpts } from "./gateway-rpc.types.js";
|
||||||
export type GatewayRpcOpts = {
|
import type { GatewayRpcOpts } from "./gateway-rpc.types.js";
|
||||||
url?: string;
|
|
||||||
token?: string;
|
|
||||||
timeout?: string;
|
|
||||||
expectFinal?: boolean;
|
|
||||||
json?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type GatewayRpcRuntimeModule = typeof import("./gateway-rpc.runtime.js");
|
type GatewayRpcRuntimeModule = typeof import("./gateway-rpc.runtime.js");
|
||||||
|
|
||||||
|
|||||||
7
src/cli/gateway-rpc.types.ts
Normal file
7
src/cli/gateway-rpc.types.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export type GatewayRpcOpts = {
|
||||||
|
url?: string;
|
||||||
|
token?: string;
|
||||||
|
timeout?: string;
|
||||||
|
expectFinal?: boolean;
|
||||||
|
json?: boolean;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user