mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:30:42 +00:00
perf: narrow plugin SDK import surfaces
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
9683f324fae8f455f2b64d7e152a77009941e4c7558521bca2510d8bcf573af9 plugin-sdk-api-baseline.json
|
||||
097bf226e4e857e9296d0851852a2963c6263d176c4c470452d9a8efd36988e5 plugin-sdk-api-baseline.jsonl
|
||||
e3df4c13b4dcdc07809775c56eed15c3ab924db191a08fb5a7b48d6f73001966 plugin-sdk-api-baseline.json
|
||||
2bb30ad45d5b382e92fd6b8a240a47f7679c59f9b524e54420879fadc28264b8 plugin-sdk-api-baseline.jsonl
|
||||
|
||||
@@ -185,7 +185,9 @@ Keep inbound mention handling split in two layers:
|
||||
- plugin-owned evidence gathering
|
||||
- shared policy evaluation
|
||||
|
||||
Use `openclaw/plugin-sdk/channel-inbound` for the shared layer.
|
||||
Use `openclaw/plugin-sdk/channel-mention-gating` for mention-policy decisions.
|
||||
Use `openclaw/plugin-sdk/channel-inbound` only when you need the broader inbound
|
||||
helper barrel.
|
||||
|
||||
Good fit for plugin-local logic:
|
||||
|
||||
@@ -255,6 +257,11 @@ bundled channel plugins that already depend on runtime injection:
|
||||
- `implicitMentionKindWhen`
|
||||
- `resolveInboundMentionDecision`
|
||||
|
||||
If you only need `implicitMentionKindWhen` and
|
||||
`resolveInboundMentionDecision`, import from
|
||||
`openclaw/plugin-sdk/channel-mention-gating` to avoid loading unrelated inbound
|
||||
runtime helpers.
|
||||
|
||||
The older `resolveMentionGating*` helpers remain on
|
||||
`openclaw/plugin-sdk/channel-inbound` as compatibility exports only. New code
|
||||
should use `resolveInboundMentionDecision({ facts, policy })`.
|
||||
|
||||
@@ -88,6 +88,7 @@ explicitly promotes one as public.
|
||||
| `plugin-sdk/channel-config-helpers` | `createHybridChannelConfigAdapter` |
|
||||
| `plugin-sdk/channel-config-schema` | Channel config schema types |
|
||||
| `plugin-sdk/telegram-command-config` | Telegram custom-command normalization/validation helpers with bundled-contract fallback |
|
||||
| `plugin-sdk/command-gating` | Narrow command authorization gate helpers |
|
||||
| `plugin-sdk/channel-policy` | `resolveChannelGroupRequireMention` |
|
||||
| `plugin-sdk/channel-lifecycle` | `createAccountStatusSink` |
|
||||
| `plugin-sdk/inbound-envelope` | Shared inbound route + envelope builder helpers |
|
||||
@@ -95,6 +96,7 @@ explicitly promotes one as public.
|
||||
| `plugin-sdk/messaging-targets` | Target parsing/matching helpers |
|
||||
| `plugin-sdk/outbound-media` | Shared outbound media loading helpers |
|
||||
| `plugin-sdk/outbound-runtime` | Outbound identity/send delegate helpers |
|
||||
| `plugin-sdk/poll-runtime` | Narrow poll normalization helpers |
|
||||
| `plugin-sdk/thread-bindings-runtime` | Thread-binding lifecycle and adapter helpers |
|
||||
| `plugin-sdk/agent-media-payload` | Legacy agent media payload builder |
|
||||
| `plugin-sdk/conversation-runtime` | Conversation/thread binding, pairing, and configured-binding helpers |
|
||||
@@ -108,7 +110,10 @@ explicitly promotes one as public.
|
||||
| `plugin-sdk/group-access` | Shared group-access decision helpers |
|
||||
| `plugin-sdk/direct-dm` | Shared direct-DM auth/guard helpers |
|
||||
| `plugin-sdk/interactive-runtime` | Interactive reply payload normalization/reduction helpers |
|
||||
| `plugin-sdk/channel-inbound` | Inbound debounce, mention matching, mention-policy helpers, and envelope helpers |
|
||||
| `plugin-sdk/channel-inbound` | Compatibility barrel for inbound debounce, mention matching, mention-policy helpers, and envelope helpers |
|
||||
| `plugin-sdk/channel-mention-gating` | Narrow mention-policy helpers without the broader inbound runtime surface |
|
||||
| `plugin-sdk/channel-location` | Channel location context and formatting helpers |
|
||||
| `plugin-sdk/channel-logging` | Channel logging helpers for inbound drops and typing/ack failures |
|
||||
| `plugin-sdk/channel-send-result` | Reply result types |
|
||||
| `plugin-sdk/channel-actions` | `createMessageToolButtonsSchema`, `createMessageToolCardSchema` |
|
||||
| `plugin-sdk/channel-targets` | Target parsing/matching helpers |
|
||||
@@ -166,6 +171,7 @@ explicitly promotes one as public.
|
||||
| `plugin-sdk/secret-ref-runtime` | Narrow `coerceSecretRef` and SecretRef typing helpers for secret-contract/config parsing |
|
||||
| `plugin-sdk/security-runtime` | Shared trust, DM gating, external-content, and secret-collection helpers |
|
||||
| `plugin-sdk/ssrf-policy` | Host allowlist and private-network SSRF policy helpers |
|
||||
| `plugin-sdk/ssrf-dispatcher` | Narrow pinned-dispatcher helpers without the broad infra runtime surface |
|
||||
| `plugin-sdk/ssrf-runtime` | Pinned-dispatcher, SSRF-guarded fetch, and SSRF policy helpers |
|
||||
| `plugin-sdk/secret-input` | Secret input parsing helpers |
|
||||
| `plugin-sdk/webhook-ingress` | Webhook request/target helpers |
|
||||
@@ -187,6 +193,7 @@ explicitly promotes one as public.
|
||||
| `plugin-sdk/gateway-runtime` | Gateway client and channel-status patch helpers |
|
||||
| `plugin-sdk/config-runtime` | Config load/write helpers |
|
||||
| `plugin-sdk/telegram-command-config` | Telegram command-name/description normalization and duplicate/conflict checks, even when the bundled Telegram contract surface is unavailable |
|
||||
| `plugin-sdk/text-autolink-runtime` | File-reference autolink detection without the broad text-runtime barrel |
|
||||
| `plugin-sdk/approval-runtime` | Exec/plugin approval helpers, approval-capability builders, auth/profile helpers, native routing/runtime helpers |
|
||||
| `plugin-sdk/reply-runtime` | Shared inbound/reply runtime helpers, chunking, dispatch, heartbeat, reply planner |
|
||||
| `plugin-sdk/reply-dispatch-runtime` | Narrow reply dispatch/finalize helpers |
|
||||
@@ -211,6 +218,7 @@ explicitly promotes one as public.
|
||||
| `plugin-sdk/file-lock` | Re-entrant file-lock helpers |
|
||||
| `plugin-sdk/persistent-dedupe` | Disk-backed dedupe cache helpers |
|
||||
| `plugin-sdk/acp-runtime` | ACP runtime/session and reply-dispatch helpers |
|
||||
| `plugin-sdk/acp-binding-resolve-runtime` | Read-only ACP binding resolution without lifecycle startup imports |
|
||||
| `plugin-sdk/agent-config-primitives` | Narrow agent runtime config-schema primitives |
|
||||
| `plugin-sdk/boolean-param` | Loose boolean param reader |
|
||||
| `plugin-sdk/dangerous-name-runtime` | Dangerous-name matching resolution helpers |
|
||||
@@ -226,6 +234,12 @@ explicitly promotes one as public.
|
||||
| `plugin-sdk/diagnostic-runtime` | Diagnostic flag and event helpers |
|
||||
| `plugin-sdk/error-runtime` | Error graph, formatting, shared error classification helpers, `isApprovalNotFoundError` |
|
||||
| `plugin-sdk/fetch-runtime` | Wrapped fetch, proxy, and pinned lookup helpers |
|
||||
| `plugin-sdk/runtime-fetch` | Dispatcher-aware runtime fetch without proxy/guarded-fetch imports |
|
||||
| `plugin-sdk/response-limit-runtime` | Bounded response-body reader without the broad media runtime surface |
|
||||
| `plugin-sdk/session-binding-runtime` | Current conversation binding state without configured binding routing or pairing stores |
|
||||
| `plugin-sdk/session-store-runtime` | Session-store read helpers without broad config writes/maintenance imports |
|
||||
| `plugin-sdk/context-visibility-runtime` | Context visibility resolution and supplemental context filtering without broad config/security imports |
|
||||
| `plugin-sdk/string-coerce-runtime` | Narrow primitive record/string coercion and normalization helpers without markdown/logging imports |
|
||||
| `plugin-sdk/host-runtime` | Hostname and SCP host normalization helpers |
|
||||
| `plugin-sdk/retry-runtime` | Retry config and retry runner helpers |
|
||||
| `plugin-sdk/agent-runtime` | Agent dir/identity/workspace helpers |
|
||||
|
||||
72
package.json
72
package.json
@@ -228,6 +228,10 @@
|
||||
"types": "./dist/plugin-sdk/outbound-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/outbound-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/poll-runtime": {
|
||||
"types": "./dist/plugin-sdk/poll-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/poll-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/infra-runtime": {
|
||||
"types": "./dist/plugin-sdk/infra-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/infra-runtime.js"
|
||||
@@ -320,6 +324,10 @@
|
||||
"types": "./dist/plugin-sdk/secret-ref-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/secret-ref-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/secret-file-runtime": {
|
||||
"types": "./dist/plugin-sdk/secret-file-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/secret-file-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/security-runtime": {
|
||||
"types": "./dist/plugin-sdk/security-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/security-runtime.js"
|
||||
@@ -372,6 +380,10 @@
|
||||
"types": "./dist/plugin-sdk/acp-binding-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/acp-binding-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/acp-binding-resolve-runtime": {
|
||||
"types": "./dist/plugin-sdk/acp-binding-resolve-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/acp-binding-resolve-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/lazy-runtime": {
|
||||
"types": "./dist/plugin-sdk/lazy-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/lazy-runtime.js"
|
||||
@@ -484,6 +496,10 @@
|
||||
"types": "./dist/plugin-sdk/command-auth-native.d.ts",
|
||||
"default": "./dist/plugin-sdk/command-auth-native.js"
|
||||
},
|
||||
"./plugin-sdk/command-gating": {
|
||||
"types": "./dist/plugin-sdk/command-gating.d.ts",
|
||||
"default": "./dist/plugin-sdk/command-gating.js"
|
||||
},
|
||||
"./plugin-sdk/command-status": {
|
||||
"types": "./dist/plugin-sdk/command-status.d.ts",
|
||||
"default": "./dist/plugin-sdk/command-status.js"
|
||||
@@ -512,6 +528,14 @@
|
||||
"types": "./dist/plugin-sdk/direct-dm.d.ts",
|
||||
"default": "./dist/plugin-sdk/direct-dm.js"
|
||||
},
|
||||
"./plugin-sdk/direct-dm-access": {
|
||||
"types": "./dist/plugin-sdk/direct-dm-access.d.ts",
|
||||
"default": "./dist/plugin-sdk/direct-dm-access.js"
|
||||
},
|
||||
"./plugin-sdk/direct-dm-guard-policy": {
|
||||
"types": "./dist/plugin-sdk/direct-dm-guard-policy.d.ts",
|
||||
"default": "./dist/plugin-sdk/direct-dm-guard-policy.js"
|
||||
},
|
||||
"./plugin-sdk/device-bootstrap": {
|
||||
"types": "./dist/plugin-sdk/device-bootstrap.d.ts",
|
||||
"default": "./dist/plugin-sdk/device-bootstrap.js"
|
||||
@@ -584,6 +608,18 @@
|
||||
"types": "./dist/plugin-sdk/channel-inbound-roots.d.ts",
|
||||
"default": "./dist/plugin-sdk/channel-inbound-roots.js"
|
||||
},
|
||||
"./plugin-sdk/channel-logging": {
|
||||
"types": "./dist/plugin-sdk/channel-logging.d.ts",
|
||||
"default": "./dist/plugin-sdk/channel-logging.js"
|
||||
},
|
||||
"./plugin-sdk/channel-location": {
|
||||
"types": "./dist/plugin-sdk/channel-location.d.ts",
|
||||
"default": "./dist/plugin-sdk/channel-location.js"
|
||||
},
|
||||
"./plugin-sdk/channel-mention-gating": {
|
||||
"types": "./dist/plugin-sdk/channel-mention-gating.d.ts",
|
||||
"default": "./dist/plugin-sdk/channel-mention-gating.js"
|
||||
},
|
||||
"./plugin-sdk/channel-lifecycle": {
|
||||
"types": "./dist/plugin-sdk/channel-lifecycle.d.ts",
|
||||
"default": "./dist/plugin-sdk/channel-lifecycle.js"
|
||||
@@ -604,6 +640,10 @@
|
||||
"types": "./dist/plugin-sdk/channel-targets.d.ts",
|
||||
"default": "./dist/plugin-sdk/channel-targets.js"
|
||||
},
|
||||
"./plugin-sdk/context-visibility-runtime": {
|
||||
"types": "./dist/plugin-sdk/context-visibility-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/context-visibility-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/feishu": {
|
||||
"types": "./dist/plugin-sdk/feishu.d.ts",
|
||||
"default": "./dist/plugin-sdk/feishu.js"
|
||||
@@ -624,6 +664,30 @@
|
||||
"types": "./dist/plugin-sdk/fetch-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/fetch-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/runtime-fetch": {
|
||||
"types": "./dist/plugin-sdk/runtime-fetch.d.ts",
|
||||
"default": "./dist/plugin-sdk/runtime-fetch.js"
|
||||
},
|
||||
"./plugin-sdk/response-limit-runtime": {
|
||||
"types": "./dist/plugin-sdk/response-limit-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/response-limit-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/session-binding-runtime": {
|
||||
"types": "./dist/plugin-sdk/session-binding-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/session-binding-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/session-store-runtime": {
|
||||
"types": "./dist/plugin-sdk/session-store-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/session-store-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/ssrf-dispatcher": {
|
||||
"types": "./dist/plugin-sdk/ssrf-dispatcher.d.ts",
|
||||
"default": "./dist/plugin-sdk/ssrf-dispatcher.js"
|
||||
},
|
||||
"./plugin-sdk/string-coerce-runtime": {
|
||||
"types": "./dist/plugin-sdk/string-coerce-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/string-coerce-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/group-access": {
|
||||
"types": "./dist/plugin-sdk/group-access.d.ts",
|
||||
"default": "./dist/plugin-sdk/group-access.js"
|
||||
@@ -1032,10 +1096,6 @@
|
||||
"types": "./dist/plugin-sdk/speech.d.ts",
|
||||
"default": "./dist/plugin-sdk/speech.js"
|
||||
},
|
||||
"./plugin-sdk/session-store-runtime": {
|
||||
"types": "./dist/plugin-sdk/session-store-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/session-store-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/string-normalization-runtime": {
|
||||
"types": "./dist/plugin-sdk/string-normalization-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/string-normalization-runtime.js"
|
||||
@@ -1052,6 +1112,10 @@
|
||||
"types": "./dist/plugin-sdk/telegram-command-config.d.ts",
|
||||
"default": "./dist/plugin-sdk/telegram-command-config.js"
|
||||
},
|
||||
"./plugin-sdk/text-autolink-runtime": {
|
||||
"types": "./dist/plugin-sdk/text-autolink-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/text-autolink-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/thread-ownership": {
|
||||
"types": "./dist/plugin-sdk/thread-ownership.d.ts",
|
||||
"default": "./dist/plugin-sdk/thread-ownership.js"
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
"interactive-runtime",
|
||||
"outbound-media",
|
||||
"outbound-runtime",
|
||||
"poll-runtime",
|
||||
"infra-runtime",
|
||||
"runtime-config-snapshot",
|
||||
"runtime-group-policy",
|
||||
@@ -66,6 +67,7 @@
|
||||
"channel-secret-runtime",
|
||||
"channel-secret-tts-runtime",
|
||||
"secret-ref-runtime",
|
||||
"secret-file-runtime",
|
||||
"security-runtime",
|
||||
"gateway-runtime",
|
||||
"github-copilot-login",
|
||||
@@ -79,6 +81,7 @@
|
||||
"windows-spawn",
|
||||
"acp-runtime",
|
||||
"acp-binding-runtime",
|
||||
"acp-binding-resolve-runtime",
|
||||
"lazy-runtime",
|
||||
"testing",
|
||||
"temp-path",
|
||||
@@ -107,6 +110,7 @@
|
||||
"dangerous-name-runtime",
|
||||
"command-auth",
|
||||
"command-auth-native",
|
||||
"command-gating",
|
||||
"command-status",
|
||||
"command-status-runtime",
|
||||
"command-detection",
|
||||
@@ -114,6 +118,8 @@
|
||||
"collection-runtime",
|
||||
"compat",
|
||||
"direct-dm",
|
||||
"direct-dm-access",
|
||||
"direct-dm-guard-policy",
|
||||
"device-bootstrap",
|
||||
"diagnostic-runtime",
|
||||
"diagnostics-otel",
|
||||
@@ -132,16 +138,26 @@
|
||||
"channel-feedback",
|
||||
"channel-inbound",
|
||||
"channel-inbound-roots",
|
||||
"channel-logging",
|
||||
"channel-location",
|
||||
"channel-mention-gating",
|
||||
"channel-lifecycle",
|
||||
"channel-pairing",
|
||||
"channel-policy",
|
||||
"channel-send-result",
|
||||
"channel-targets",
|
||||
"context-visibility-runtime",
|
||||
"feishu",
|
||||
"feishu-conversation",
|
||||
"feishu-setup",
|
||||
"file-lock",
|
||||
"fetch-runtime",
|
||||
"runtime-fetch",
|
||||
"response-limit-runtime",
|
||||
"session-binding-runtime",
|
||||
"session-store-runtime",
|
||||
"ssrf-dispatcher",
|
||||
"string-coerce-runtime",
|
||||
"group-access",
|
||||
"global-singleton",
|
||||
"directory-runtime",
|
||||
@@ -244,11 +260,11 @@
|
||||
"channel-status",
|
||||
"status-helpers",
|
||||
"speech",
|
||||
"session-store-runtime",
|
||||
"string-normalization-runtime",
|
||||
"state-paths",
|
||||
"target-resolver-runtime",
|
||||
"telegram-command-config",
|
||||
"text-autolink-runtime",
|
||||
"thread-ownership",
|
||||
"tlon",
|
||||
"tool-payload",
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
[
|
||||
"qa-lab",
|
||||
"qa-runtime"
|
||||
]
|
||||
["qa-lab", "qa-runtime"]
|
||||
|
||||
2
src/plugin-sdk/acp-binding-resolve-runtime.ts
Normal file
2
src/plugin-sdk/acp-binding-resolve-runtime.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
// Read-only ACP binding resolution without the lifecycle runtime import graph.
|
||||
export { resolveConfiguredAcpBindingRecord } from "../acp/persistent-bindings.resolve.js";
|
||||
2
src/plugin-sdk/channel-location.ts
Normal file
2
src/plugin-sdk/channel-location.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export type { LocationSource, NormalizedLocation } from "../channels/location.js";
|
||||
export { formatLocationText, toLocationContext } from "../channels/location.js";
|
||||
2
src/plugin-sdk/channel-logging.ts
Normal file
2
src/plugin-sdk/channel-logging.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export type { LogFn } from "../channels/logging.js";
|
||||
export { logAckFailure, logInboundDrop, logTypingFailure } from "../channels/logging.js";
|
||||
21
src/plugin-sdk/channel-mention-gating.ts
Normal file
21
src/plugin-sdk/channel-mention-gating.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export type {
|
||||
InboundImplicitMentionKind,
|
||||
InboundMentionDecision,
|
||||
InboundMentionFacts,
|
||||
InboundMentionPolicy,
|
||||
MentionGateParams,
|
||||
MentionGateResult,
|
||||
MentionGateWithBypassParams,
|
||||
MentionGateWithBypassResult,
|
||||
ResolveInboundMentionDecisionFlatParams,
|
||||
ResolveInboundMentionDecisionNestedParams,
|
||||
ResolveInboundMentionDecisionParams,
|
||||
} from "../channels/mention-gating.js";
|
||||
export {
|
||||
implicitMentionKindWhen,
|
||||
resolveInboundMentionDecision,
|
||||
// @deprecated Prefer `resolveInboundMentionDecision({ facts, policy })`.
|
||||
resolveMentionGating,
|
||||
// @deprecated Prefer `resolveInboundMentionDecision({ facts, policy })`.
|
||||
resolveMentionGatingWithBypass,
|
||||
} from "../channels/mention-gating.js";
|
||||
@@ -16,6 +16,7 @@ export {
|
||||
} from "../channels/plugins/setup-helpers.js";
|
||||
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||
export {
|
||||
clearAccountEntryFields,
|
||||
deleteAccountFromConfigSection,
|
||||
setAccountEnabledInConfigSection,
|
||||
} from "../channels/plugins/config-helpers.js";
|
||||
|
||||
9
src/plugin-sdk/command-gating.ts
Normal file
9
src/plugin-sdk/command-gating.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export type {
|
||||
CommandAuthorizer,
|
||||
CommandGatingModeWhenAccessGroupsOff,
|
||||
} from "../channels/command-gating.js";
|
||||
export {
|
||||
resolveCommandAuthorizedFromAuthorizers,
|
||||
resolveControlCommandGate,
|
||||
resolveDualTextControlCommandGate,
|
||||
} from "../channels/command-gating.js";
|
||||
14
src/plugin-sdk/context-visibility-runtime.ts
Normal file
14
src/plugin-sdk/context-visibility-runtime.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
// Narrow context visibility helpers without broad config-runtime imports.
|
||||
|
||||
export {
|
||||
resolveChannelContextVisibilityMode,
|
||||
resolveDefaultContextVisibility,
|
||||
} from "../config/context-visibility.js";
|
||||
export {
|
||||
evaluateSupplementalContextVisibility,
|
||||
filterSupplementalContextItems,
|
||||
shouldIncludeSupplementalContext,
|
||||
type ContextVisibilityDecision,
|
||||
type ContextVisibilityDecisionReason,
|
||||
type ContextVisibilityKind,
|
||||
} from "../security/context-visibility.js";
|
||||
140
src/plugin-sdk/direct-dm-access.ts
Normal file
140
src/plugin-sdk/direct-dm-access.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import type { ChannelId } from "../channels/plugins/types.public.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import {
|
||||
readStoreAllowFromForDmPolicy,
|
||||
resolveDmGroupAccessWithLists,
|
||||
type DmGroupAccessReasonCode,
|
||||
} from "../security/dm-policy-shared.js";
|
||||
|
||||
export type DirectDmCommandAuthorizationRuntime = {
|
||||
shouldComputeCommandAuthorized: (rawBody: string, cfg: OpenClawConfig) => boolean;
|
||||
resolveCommandAuthorizedFromAuthorizers: (params: {
|
||||
useAccessGroups: boolean;
|
||||
authorizers: Array<{ configured: boolean; allowed: boolean }>;
|
||||
modeWhenAccessGroupsOff?: "allow" | "deny" | "configured";
|
||||
}) => boolean;
|
||||
};
|
||||
|
||||
export type ResolvedInboundDirectDmAccess = {
|
||||
access: {
|
||||
decision: "allow" | "block" | "pairing";
|
||||
reasonCode: DmGroupAccessReasonCode;
|
||||
reason: string;
|
||||
effectiveAllowFrom: string[];
|
||||
};
|
||||
shouldComputeAuth: boolean;
|
||||
senderAllowedForCommands: boolean;
|
||||
commandAuthorized: boolean | undefined;
|
||||
};
|
||||
|
||||
/** Resolve direct-DM policy, effective allowlists, and optional command auth in one place. */
|
||||
export async function resolveInboundDirectDmAccessWithRuntime(params: {
|
||||
cfg: OpenClawConfig;
|
||||
channel: ChannelId;
|
||||
accountId: string;
|
||||
dmPolicy?: string | null;
|
||||
allowFrom?: Array<string | number> | null;
|
||||
senderId: string;
|
||||
rawBody: string;
|
||||
isSenderAllowed: (senderId: string, allowFrom: string[]) => boolean;
|
||||
runtime: DirectDmCommandAuthorizationRuntime;
|
||||
modeWhenAccessGroupsOff?: "allow" | "deny" | "configured";
|
||||
readStoreAllowFrom?: (provider: ChannelId, accountId: string) => Promise<string[]>;
|
||||
}): Promise<ResolvedInboundDirectDmAccess> {
|
||||
const dmPolicy = params.dmPolicy ?? "pairing";
|
||||
const storeAllowFrom =
|
||||
dmPolicy === "pairing"
|
||||
? await readStoreAllowFromForDmPolicy({
|
||||
provider: params.channel,
|
||||
accountId: params.accountId,
|
||||
dmPolicy,
|
||||
readStore: params.readStoreAllowFrom,
|
||||
})
|
||||
: [];
|
||||
|
||||
const access = resolveDmGroupAccessWithLists({
|
||||
isGroup: false,
|
||||
dmPolicy,
|
||||
allowFrom: params.allowFrom,
|
||||
storeAllowFrom,
|
||||
groupAllowFromFallbackToAllowFrom: false,
|
||||
isSenderAllowed: (allowEntries) => params.isSenderAllowed(params.senderId, allowEntries),
|
||||
});
|
||||
|
||||
const shouldComputeAuth = params.runtime.shouldComputeCommandAuthorized(
|
||||
params.rawBody,
|
||||
params.cfg,
|
||||
);
|
||||
const senderAllowedForCommands = params.isSenderAllowed(
|
||||
params.senderId,
|
||||
access.effectiveAllowFrom,
|
||||
);
|
||||
const commandAuthorized = shouldComputeAuth
|
||||
? dmPolicy === "open"
|
||||
? true
|
||||
: params.runtime.resolveCommandAuthorizedFromAuthorizers({
|
||||
useAccessGroups: params.cfg.commands?.useAccessGroups !== false,
|
||||
authorizers: [
|
||||
{
|
||||
configured: access.effectiveAllowFrom.length > 0,
|
||||
allowed: senderAllowedForCommands,
|
||||
},
|
||||
],
|
||||
modeWhenAccessGroupsOff: params.modeWhenAccessGroupsOff,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
access: {
|
||||
decision: access.decision,
|
||||
reasonCode: access.reasonCode,
|
||||
reason: access.reason,
|
||||
effectiveAllowFrom: access.effectiveAllowFrom,
|
||||
},
|
||||
shouldComputeAuth,
|
||||
senderAllowedForCommands,
|
||||
commandAuthorized,
|
||||
};
|
||||
}
|
||||
|
||||
/** Convert resolved DM policy into a pre-crypto allow/block/pairing callback. */
|
||||
export function createPreCryptoDirectDmAuthorizer(params: {
|
||||
resolveAccess: (
|
||||
senderId: string,
|
||||
) => Promise<Pick<ResolvedInboundDirectDmAccess, "access"> | ResolvedInboundDirectDmAccess>;
|
||||
issuePairingChallenge?: (params: {
|
||||
senderId: string;
|
||||
reply: (text: string) => Promise<void>;
|
||||
}) => Promise<void>;
|
||||
onBlocked?: (params: {
|
||||
senderId: string;
|
||||
reason: string;
|
||||
reasonCode: DmGroupAccessReasonCode;
|
||||
}) => void;
|
||||
}) {
|
||||
return async (input: {
|
||||
senderId: string;
|
||||
reply: (text: string) => Promise<void>;
|
||||
}): Promise<"allow" | "block" | "pairing"> => {
|
||||
const resolved = await params.resolveAccess(input.senderId);
|
||||
const access = "access" in resolved ? resolved.access : resolved;
|
||||
if (access.decision === "allow") {
|
||||
return "allow";
|
||||
}
|
||||
if (access.decision === "pairing") {
|
||||
if (params.issuePairingChallenge) {
|
||||
await params.issuePairingChallenge({
|
||||
senderId: input.senderId,
|
||||
reply: input.reply,
|
||||
});
|
||||
}
|
||||
return "pairing";
|
||||
}
|
||||
params.onBlocked?.({
|
||||
senderId: input.senderId,
|
||||
reason: access.reason,
|
||||
reasonCode: access.reasonCode,
|
||||
});
|
||||
return "block";
|
||||
};
|
||||
}
|
||||
36
src/plugin-sdk/direct-dm-guard-policy.ts
Normal file
36
src/plugin-sdk/direct-dm-guard-policy.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
export type DirectDmPreCryptoGuardPolicy = {
|
||||
allowedKinds: readonly number[];
|
||||
maxFutureSkewSec: number;
|
||||
maxCiphertextBytes: number;
|
||||
maxPlaintextBytes: number;
|
||||
rateLimit: {
|
||||
windowMs: number;
|
||||
maxPerSenderPerWindow: number;
|
||||
maxGlobalPerWindow: number;
|
||||
maxTrackedSenderKeys: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type DirectDmPreCryptoGuardPolicyOverrides = Partial<
|
||||
Omit<DirectDmPreCryptoGuardPolicy, "rateLimit">
|
||||
> & {
|
||||
rateLimit?: Partial<DirectDmPreCryptoGuardPolicy["rateLimit"]>;
|
||||
};
|
||||
|
||||
/** Shared policy object for DM-style pre-crypto guardrails. */
|
||||
export function createDirectDmPreCryptoGuardPolicy(
|
||||
overrides: DirectDmPreCryptoGuardPolicyOverrides = {},
|
||||
): DirectDmPreCryptoGuardPolicy {
|
||||
return {
|
||||
allowedKinds: overrides.allowedKinds ?? [4],
|
||||
maxFutureSkewSec: overrides.maxFutureSkewSec ?? 120,
|
||||
maxCiphertextBytes: overrides.maxCiphertextBytes ?? 16 * 1024,
|
||||
maxPlaintextBytes: overrides.maxPlaintextBytes ?? 8 * 1024,
|
||||
rateLimit: {
|
||||
windowMs: overrides.rateLimit?.windowMs ?? 60_000,
|
||||
maxPerSenderPerWindow: overrides.rateLimit?.maxPerSenderPerWindow ?? 20,
|
||||
maxGlobalPerWindow: overrides.rateLimit?.maxGlobalPerWindow ?? 200,
|
||||
maxTrackedSenderKeys: overrides.rateLimit?.maxTrackedSenderKeys ?? 4096,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,185 +1,20 @@
|
||||
import type { DispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.types.js";
|
||||
import type { FinalizedMsgContext } from "../auto-reply/templating.js";
|
||||
import type { ChannelId } from "../channels/plugins/types.public.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import {
|
||||
readStoreAllowFromForDmPolicy,
|
||||
resolveDmGroupAccessWithLists,
|
||||
type DmGroupAccessReasonCode,
|
||||
} from "../security/dm-policy-shared.js";
|
||||
import { resolveInboundRouteEnvelopeBuilderWithRuntime } from "./inbound-envelope.js";
|
||||
import { recordInboundSessionAndDispatchReply } from "./inbound-reply-dispatch.js";
|
||||
import type { OutboundReplyPayload } from "./reply-payload.js";
|
||||
|
||||
export type DirectDmCommandAuthorizationRuntime = {
|
||||
shouldComputeCommandAuthorized: (rawBody: string, cfg: OpenClawConfig) => boolean;
|
||||
resolveCommandAuthorizedFromAuthorizers: (params: {
|
||||
useAccessGroups: boolean;
|
||||
authorizers: Array<{ configured: boolean; allowed: boolean }>;
|
||||
modeWhenAccessGroupsOff?: "allow" | "deny" | "configured";
|
||||
}) => boolean;
|
||||
};
|
||||
|
||||
export type ResolvedInboundDirectDmAccess = {
|
||||
access: {
|
||||
decision: "allow" | "block" | "pairing";
|
||||
reasonCode: DmGroupAccessReasonCode;
|
||||
reason: string;
|
||||
effectiveAllowFrom: string[];
|
||||
};
|
||||
shouldComputeAuth: boolean;
|
||||
senderAllowedForCommands: boolean;
|
||||
commandAuthorized: boolean | undefined;
|
||||
};
|
||||
|
||||
/** Resolve direct-DM policy, effective allowlists, and optional command auth in one place. */
|
||||
export async function resolveInboundDirectDmAccessWithRuntime(params: {
|
||||
cfg: OpenClawConfig;
|
||||
channel: ChannelId;
|
||||
accountId: string;
|
||||
dmPolicy?: string | null;
|
||||
allowFrom?: Array<string | number> | null;
|
||||
senderId: string;
|
||||
rawBody: string;
|
||||
isSenderAllowed: (senderId: string, allowFrom: string[]) => boolean;
|
||||
runtime: DirectDmCommandAuthorizationRuntime;
|
||||
modeWhenAccessGroupsOff?: "allow" | "deny" | "configured";
|
||||
readStoreAllowFrom?: (provider: ChannelId, accountId: string) => Promise<string[]>;
|
||||
}): Promise<ResolvedInboundDirectDmAccess> {
|
||||
const dmPolicy = params.dmPolicy ?? "pairing";
|
||||
const storeAllowFrom =
|
||||
dmPolicy === "pairing"
|
||||
? await readStoreAllowFromForDmPolicy({
|
||||
provider: params.channel,
|
||||
accountId: params.accountId,
|
||||
dmPolicy,
|
||||
readStore: params.readStoreAllowFrom,
|
||||
})
|
||||
: [];
|
||||
|
||||
const access = resolveDmGroupAccessWithLists({
|
||||
isGroup: false,
|
||||
dmPolicy,
|
||||
allowFrom: params.allowFrom,
|
||||
storeAllowFrom,
|
||||
groupAllowFromFallbackToAllowFrom: false,
|
||||
isSenderAllowed: (allowEntries) => params.isSenderAllowed(params.senderId, allowEntries),
|
||||
});
|
||||
|
||||
const shouldComputeAuth = params.runtime.shouldComputeCommandAuthorized(
|
||||
params.rawBody,
|
||||
params.cfg,
|
||||
);
|
||||
const senderAllowedForCommands = params.isSenderAllowed(
|
||||
params.senderId,
|
||||
access.effectiveAllowFrom,
|
||||
);
|
||||
const commandAuthorized = shouldComputeAuth
|
||||
? dmPolicy === "open"
|
||||
? true
|
||||
: params.runtime.resolveCommandAuthorizedFromAuthorizers({
|
||||
useAccessGroups: params.cfg.commands?.useAccessGroups !== false,
|
||||
authorizers: [
|
||||
{
|
||||
configured: access.effectiveAllowFrom.length > 0,
|
||||
allowed: senderAllowedForCommands,
|
||||
},
|
||||
],
|
||||
modeWhenAccessGroupsOff: params.modeWhenAccessGroupsOff,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
access: {
|
||||
decision: access.decision,
|
||||
reasonCode: access.reasonCode,
|
||||
reason: access.reason,
|
||||
effectiveAllowFrom: access.effectiveAllowFrom,
|
||||
},
|
||||
shouldComputeAuth,
|
||||
senderAllowedForCommands,
|
||||
commandAuthorized,
|
||||
};
|
||||
}
|
||||
|
||||
/** Convert resolved DM policy into a pre-crypto allow/block/pairing callback. */
|
||||
export function createPreCryptoDirectDmAuthorizer(params: {
|
||||
resolveAccess: (
|
||||
senderId: string,
|
||||
) => Promise<Pick<ResolvedInboundDirectDmAccess, "access"> | ResolvedInboundDirectDmAccess>;
|
||||
issuePairingChallenge?: (params: {
|
||||
senderId: string;
|
||||
reply: (text: string) => Promise<void>;
|
||||
}) => Promise<void>;
|
||||
onBlocked?: (params: {
|
||||
senderId: string;
|
||||
reason: string;
|
||||
reasonCode: DmGroupAccessReasonCode;
|
||||
}) => void;
|
||||
}) {
|
||||
return async (input: {
|
||||
senderId: string;
|
||||
reply: (text: string) => Promise<void>;
|
||||
}): Promise<"allow" | "block" | "pairing"> => {
|
||||
const resolved = await params.resolveAccess(input.senderId);
|
||||
const access = "access" in resolved ? resolved.access : resolved;
|
||||
if (access.decision === "allow") {
|
||||
return "allow";
|
||||
}
|
||||
if (access.decision === "pairing") {
|
||||
if (params.issuePairingChallenge) {
|
||||
await params.issuePairingChallenge({
|
||||
senderId: input.senderId,
|
||||
reply: input.reply,
|
||||
});
|
||||
}
|
||||
return "pairing";
|
||||
}
|
||||
params.onBlocked?.({
|
||||
senderId: input.senderId,
|
||||
reason: access.reason,
|
||||
reasonCode: access.reasonCode,
|
||||
});
|
||||
return "block";
|
||||
};
|
||||
}
|
||||
|
||||
export type DirectDmPreCryptoGuardPolicy = {
|
||||
allowedKinds: readonly number[];
|
||||
maxFutureSkewSec: number;
|
||||
maxCiphertextBytes: number;
|
||||
maxPlaintextBytes: number;
|
||||
rateLimit: {
|
||||
windowMs: number;
|
||||
maxPerSenderPerWindow: number;
|
||||
maxGlobalPerWindow: number;
|
||||
maxTrackedSenderKeys: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type DirectDmPreCryptoGuardPolicyOverrides = Partial<
|
||||
Omit<DirectDmPreCryptoGuardPolicy, "rateLimit">
|
||||
> & {
|
||||
rateLimit?: Partial<DirectDmPreCryptoGuardPolicy["rateLimit"]>;
|
||||
};
|
||||
|
||||
/** Shared policy object for DM-style pre-crypto guardrails. */
|
||||
export function createDirectDmPreCryptoGuardPolicy(
|
||||
overrides: DirectDmPreCryptoGuardPolicyOverrides = {},
|
||||
): DirectDmPreCryptoGuardPolicy {
|
||||
return {
|
||||
allowedKinds: overrides.allowedKinds ?? [4],
|
||||
maxFutureSkewSec: overrides.maxFutureSkewSec ?? 120,
|
||||
maxCiphertextBytes: overrides.maxCiphertextBytes ?? 16 * 1024,
|
||||
maxPlaintextBytes: overrides.maxPlaintextBytes ?? 8 * 1024,
|
||||
rateLimit: {
|
||||
windowMs: overrides.rateLimit?.windowMs ?? 60_000,
|
||||
maxPerSenderPerWindow: overrides.rateLimit?.maxPerSenderPerWindow ?? 20,
|
||||
maxGlobalPerWindow: overrides.rateLimit?.maxGlobalPerWindow ?? 200,
|
||||
maxTrackedSenderKeys: overrides.rateLimit?.maxTrackedSenderKeys ?? 4096,
|
||||
},
|
||||
};
|
||||
}
|
||||
export {
|
||||
createPreCryptoDirectDmAuthorizer,
|
||||
resolveInboundDirectDmAccessWithRuntime,
|
||||
type DirectDmCommandAuthorizationRuntime,
|
||||
type ResolvedInboundDirectDmAccess,
|
||||
} from "./direct-dm-access.js";
|
||||
export {
|
||||
createDirectDmPreCryptoGuardPolicy,
|
||||
type DirectDmPreCryptoGuardPolicy,
|
||||
type DirectDmPreCryptoGuardPolicyOverrides,
|
||||
} from "./direct-dm-guard-policy.js";
|
||||
|
||||
type DirectDmRoutePeer = {
|
||||
kind: "direct";
|
||||
|
||||
6
src/plugin-sdk/poll-runtime.ts
Normal file
6
src/plugin-sdk/poll-runtime.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export type { NormalizedPollInput, PollInput } from "../polls.js";
|
||||
export {
|
||||
normalizePollDurationHours,
|
||||
normalizePollInput,
|
||||
resolvePollMaxSelections,
|
||||
} from "../polls.js";
|
||||
3
src/plugin-sdk/response-limit-runtime.ts
Normal file
3
src/plugin-sdk/response-limit-runtime.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// Narrow response-size reader for plugins that download bounded HTTP bodies.
|
||||
|
||||
export { readResponseWithLimit } from "../media/read-response-with-limit.js";
|
||||
7
src/plugin-sdk/runtime-fetch.ts
Normal file
7
src/plugin-sdk/runtime-fetch.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// Narrow runtime fetch helpers for plugins that need dispatcher-aware fetch
|
||||
// without importing the broad infra-runtime compatibility barrel.
|
||||
|
||||
export {
|
||||
fetchWithRuntimeDispatcher,
|
||||
type DispatcherAwareRequestInit,
|
||||
} from "../infra/net/runtime-fetch.js";
|
||||
7
src/plugin-sdk/secret-file-runtime.ts
Normal file
7
src/plugin-sdk/secret-file-runtime.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export {
|
||||
DEFAULT_SECRET_FILE_MAX_BYTES,
|
||||
loadSecretFileSync,
|
||||
readSecretFileSync,
|
||||
tryReadSecretFileSync,
|
||||
} from "../infra/secret-file.js";
|
||||
export type { SecretFileReadOptions, SecretFileReadResult } from "../infra/secret-file.js";
|
||||
@@ -2,6 +2,7 @@ import { z } from "zod";
|
||||
import {
|
||||
hasConfiguredSecretInput,
|
||||
isSecretRef,
|
||||
coerceSecretRef,
|
||||
resolveSecretInputString,
|
||||
normalizeResolvedSecretInputString,
|
||||
normalizeSecretInputString,
|
||||
@@ -16,6 +17,7 @@ export type {
|
||||
} from "../config/types.secrets.js";
|
||||
export {
|
||||
buildSecretInputSchema,
|
||||
coerceSecretRef,
|
||||
hasConfiguredSecretInput,
|
||||
isSecretRef,
|
||||
resolveSecretInputString,
|
||||
|
||||
7
src/plugin-sdk/session-binding-runtime.ts
Normal file
7
src/plugin-sdk/session-binding-runtime.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// Narrow session-binding runtime surface for channels that only need current
|
||||
// conversation binding state, not configured binding routing or pairing stores.
|
||||
export {
|
||||
getSessionBindingService,
|
||||
type SessionBindingRecord,
|
||||
type SessionBindingService,
|
||||
} from "../infra/outbound/session-binding-service.js";
|
||||
@@ -1 +1,4 @@
|
||||
export { readSessionUpdatedAt, resolveStorePath } from "../config/sessions.js";
|
||||
// Narrow session-store read helpers for channel hot paths.
|
||||
|
||||
export { loadSessionStore } from "../config/sessions/store-load.js";
|
||||
export { resolveSessionStoreEntry } from "../config/sessions/store-entry.js";
|
||||
|
||||
9
src/plugin-sdk/ssrf-dispatcher.ts
Normal file
9
src/plugin-sdk/ssrf-dispatcher.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
// Narrow SSRF dispatcher helpers for plugins that pin DNS resolution before fetch.
|
||||
|
||||
export {
|
||||
closeDispatcher,
|
||||
createPinnedDispatcher,
|
||||
resolvePinnedHostnameWithPolicy,
|
||||
type PinnedDispatcherPolicy,
|
||||
type SsrFPolicy,
|
||||
} from "../infra/net/ssrf.js";
|
||||
@@ -1,3 +1,4 @@
|
||||
// Public state/config path helpers for plugins that persist small caches.
|
||||
|
||||
export { resolveOAuthDir, resolveStateDir, STATE_DIR } from "../config/paths.js";
|
||||
export { resolveRequiredHomeDir } from "../infra/home-dir.js";
|
||||
|
||||
15
src/plugin-sdk/string-coerce-runtime.ts
Normal file
15
src/plugin-sdk/string-coerce-runtime.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
// Narrow primitive coercion helpers for plugins that do not need the full text-runtime barrel.
|
||||
|
||||
export {
|
||||
hasNonEmptyString,
|
||||
localeLowercasePreservingWhitespace,
|
||||
lowercasePreservingWhitespace,
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeNullableString,
|
||||
normalizeOptionalLowercaseString,
|
||||
normalizeOptionalString,
|
||||
normalizeOptionalStringifiedId,
|
||||
normalizeStringifiedOptionalString,
|
||||
readStringValue,
|
||||
} from "../shared/string-coerce.js";
|
||||
export { isRecord } from "../utils.js";
|
||||
2
src/plugin-sdk/text-autolink-runtime.ts
Normal file
2
src/plugin-sdk/text-autolink-runtime.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
// Narrow text helper for renderers that only need file-ref autolink detection.
|
||||
export { isAutoLinkedFileRef } from "../shared/text/auto-linked-file-ref.js";
|
||||
@@ -41,4 +41,6 @@ export {
|
||||
} from "./webhook-targets.js";
|
||||
export { normalizeWebhookPath, resolveWebhookPath } from "./webhook-path.js";
|
||||
export { resolveRequestClientIp } from "../gateway/net.js";
|
||||
export { createAuthRateLimiter } from "../gateway/auth-rate-limit.js";
|
||||
export type { AuthRateLimiter, RateLimitConfig } from "../gateway/auth-rate-limit.js";
|
||||
export { normalizePluginHttpPath } from "../plugins/http-path.js";
|
||||
|
||||
Reference in New Issue
Block a user