Gateway/CLI: add paired-device remove and clear flows (#20057)

Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 26523f8a38
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
This commit is contained in:
Mariano
2026-02-18 13:27:31 +00:00
committed by GitHub
parent fc65f70a9b
commit 1437ed76a0
13 changed files with 239 additions and 2 deletions

View File

@@ -95,6 +95,8 @@ import {
DevicePairApproveParamsSchema,
type DevicePairListParams,
DevicePairListParamsSchema,
type DevicePairRemoveParams,
DevicePairRemoveParamsSchema,
type DevicePairRejectParams,
DevicePairRejectParamsSchema,
type DeviceTokenRevokeParams,
@@ -333,6 +335,9 @@ export const validateDevicePairApproveParams = ajv.compile<DevicePairApprovePara
export const validateDevicePairRejectParams = ajv.compile<DevicePairRejectParams>(
DevicePairRejectParamsSchema,
);
export const validateDevicePairRemoveParams = ajv.compile<DevicePairRemoveParams>(
DevicePairRemoveParamsSchema,
);
export const validateDeviceTokenRotateParams = ajv.compile<DeviceTokenRotateParams>(
DeviceTokenRotateParamsSchema,
);

View File

@@ -13,6 +13,11 @@ export const DevicePairRejectParamsSchema = Type.Object(
{ additionalProperties: false },
);
export const DevicePairRemoveParamsSchema = Type.Object(
{ deviceId: NonEmptyString },
{ additionalProperties: false },
);
export const DeviceTokenRotateParamsSchema = Type.Object(
{
deviceId: NonEmptyString,

View File

@@ -68,6 +68,7 @@ import {
import {
DevicePairApproveParamsSchema,
DevicePairListParamsSchema,
DevicePairRemoveParamsSchema,
DevicePairRejectParamsSchema,
DevicePairRequestedEventSchema,
DevicePairResolvedEventSchema,
@@ -245,6 +246,7 @@ export const ProtocolSchemas: Record<string, TSchema> = {
DevicePairListParams: DevicePairListParamsSchema,
DevicePairApproveParams: DevicePairApproveParamsSchema,
DevicePairRejectParams: DevicePairRejectParamsSchema,
DevicePairRemoveParams: DevicePairRemoveParamsSchema,
DeviceTokenRotateParams: DeviceTokenRotateParamsSchema,
DeviceTokenRevokeParams: DeviceTokenRevokeParamsSchema,
DevicePairRequestedEvent: DevicePairRequestedEventSchema,

View File

@@ -66,6 +66,7 @@ import type {
import type {
DevicePairApproveParamsSchema,
DevicePairListParamsSchema,
DevicePairRemoveParamsSchema,
DevicePairRejectParamsSchema,
DeviceTokenRevokeParamsSchema,
DeviceTokenRotateParamsSchema,
@@ -234,6 +235,7 @@ export type ExecApprovalResolveParams = Static<typeof ExecApprovalResolveParamsS
export type DevicePairListParams = Static<typeof DevicePairListParamsSchema>;
export type DevicePairApproveParams = Static<typeof DevicePairApproveParamsSchema>;
export type DevicePairRejectParams = Static<typeof DevicePairRejectParamsSchema>;
export type DevicePairRemoveParams = Static<typeof DevicePairRemoveParamsSchema>;
export type DeviceTokenRotateParams = Static<typeof DeviceTokenRotateParamsSchema>;
export type DeviceTokenRevokeParams = Static<typeof DeviceTokenRevokeParamsSchema>;
export type ChatAbortParams = Static<typeof ChatAbortParamsSchema>;

View File

@@ -64,6 +64,7 @@ const BASE_METHODS = [
"device.pair.list",
"device.pair.approve",
"device.pair.reject",
"device.pair.remove",
"device.token.rotate",
"device.token.revoke",
"node.rename",

View File

@@ -47,6 +47,7 @@ const PAIRING_METHODS = new Set([
"device.pair.list",
"device.pair.approve",
"device.pair.reject",
"device.pair.remove",
"device.token.rotate",
"device.token.revoke",
"node.rename",

View File

@@ -1,6 +1,7 @@
import {
approveDevicePairing,
listDevicePairing,
removePairedDevice,
type DeviceAuthToken,
rejectDevicePairing,
revokeDeviceToken,
@@ -13,6 +14,7 @@ import {
formatValidationErrors,
validateDevicePairApproveParams,
validateDevicePairListParams,
validateDevicePairRemoveParams,
validateDevicePairRejectParams,
validateDeviceTokenRevokeParams,
validateDeviceTokenRotateParams,
@@ -121,6 +123,29 @@ export const deviceHandlers: GatewayRequestHandlers = {
);
respond(true, rejected, undefined);
},
"device.pair.remove": async ({ params, respond, context }) => {
if (!validateDevicePairRemoveParams(params)) {
respond(
false,
undefined,
errorShape(
ErrorCodes.INVALID_REQUEST,
`invalid device.pair.remove params: ${formatValidationErrors(
validateDevicePairRemoveParams.errors,
)}`,
),
);
return;
}
const { deviceId } = params as { deviceId: string };
const removed = await removePairedDevice(deviceId);
if (!removed) {
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "unknown deviceId"));
return;
}
context.logGateway.info(`device pairing removed device=${removed.deviceId}`);
respond(true, removed, undefined);
},
"device.token.rotate": async ({ params, respond, context }) => {
if (!validateDeviceTokenRotateParams(params)) {
respond(