Files
openclaw/src/plugin-sdk/channel-pairing.ts
clawSean d84aabf642 feat: add channel pairing request hook (#97733)
* feat: add channel pairing request hook

* fix(plugin-sdk): keep pairing hook types internal

* docs: regenerate docs map

* docs: regenerate docs map

* docs: regenerate docs map

* fix(plugin-sdk): keep pairing hook types internal

* fix(plugin-sdk): keep pairing hook types internal

* docs: refresh plugin hook docs

* docs: refresh plugin hook docs

* docs: refresh plugin hook docs

---------

Co-authored-by: clawSean <260045960+clawSean@users.noreply.github.com>
Co-authored-by: Omar Shahine <omarshahine@users.noreply.github.com>
2026-07-05 19:11:58 -07:00

73 lines
2.8 KiB
TypeScript

// Channel pairing contracts describe account/device pairing state shared by channel plugins.
import type { ChannelId } from "../channels/plugins/types.public.js";
export {
createLoggedPairingApprovalNotifier,
createPairingPrefixStripper,
createTextPairingAdapter,
} from "../channels/plugins/pairing-adapters.js";
export {
readChannelAllowFromStore,
readChannelAllowFromStoreSync,
} from "../pairing/pairing-store.js";
export { resolveChannelAllowFromPath } from "../pairing/pairing-store.js";
import { issuePairingChallenge } from "../pairing/pairing-challenge.js";
import type { PluginRuntime } from "../plugins/runtime/types.js";
import { createScopedPairingAccess } from "./pairing-access.js";
type ScopedPairingAccess = ReturnType<typeof createScopedPairingAccess>;
/** Pairing helpers scoped to one channel account. */
export type ChannelPairingController = ScopedPairingAccess & {
/** Issue a pairing challenge using the controller's channel and scoped store writer. */
issueChallenge: (
params: Omit<
Parameters<typeof issuePairingChallenge>[0],
"channel" | "accountId" | "upsertPairingRequest"
>,
) => ReturnType<typeof issuePairingChallenge>;
};
/** Pre-bind the channel id and storage sink for pairing challenges. */
export function createChannelPairingChallengeIssuer(params: {
/** Channel id attached to every challenge issued by the returned helper. */
channel: ChannelId;
/** Optional channel account id attached to pairing-request hook payloads. */
accountId?: string;
/** Store writer that persists pending pairing requests for the bound channel. */
upsertPairingRequest: Parameters<typeof issuePairingChallenge>[0]["upsertPairingRequest"];
}) {
return (
/** Challenge details supplied at message handling time. */
challenge: Omit<
Parameters<typeof issuePairingChallenge>[0],
"channel" | "accountId" | "upsertPairingRequest"
>,
) =>
issuePairingChallenge({
channel: params.channel,
accountId: params.accountId,
upsertPairingRequest: params.upsertPairingRequest,
...challenge,
});
}
/** Build the full scoped pairing controller used by channel runtime code. */
export function createChannelPairingController(params: {
/** Plugin runtime that provides pairing store operations. */
core: PluginRuntime;
/** Channel id scoped into reads, writes, and issued challenges. */
channel: ChannelId;
/** Channel account id normalized before pairing store access. */
accountId: string;
}): ChannelPairingController {
const access = createScopedPairingAccess(params);
return {
...access,
issueChallenge: createChannelPairingChallengeIssuer({
channel: params.channel,
accountId: access.accountId,
upsertPairingRequest: access.upsertPairingRequest,
}),
};
}