From 30ee35b25c982091bcdf893c24ca8071177a1f36 Mon Sep 17 00:00:00 2001 From: RevIQ Date: Fri, 9 Jan 2026 12:38:07 +0800 Subject: [PATCH] Restructure passkey routes to me.passkeys namespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove createPasskey since verifyRegistration handles adding passkeys - Move listPasskeys → me.passkeys.list - Move renamePasskey → me.passkeys.rename - Move deletePasskey → me.passkeys.delete Co-Authored-By: Claude Opus 4.5 --- apps/api-server/src/router.ts | 31 +++++++-------------------- apps/api-server/src/utils/webauthn.ts | 2 +- packages/api-contract/src/contract.ts | 22 ++++++++----------- 3 files changed, 18 insertions(+), 37 deletions(-) diff --git a/apps/api-server/src/router.ts b/apps/api-server/src/router.ts index e76c93a..1c56c35 100644 --- a/apps/api-server/src/router.ts +++ b/apps/api-server/src/router.ts @@ -137,7 +137,7 @@ const setPassword = os.me.setPassword.handler(async () => { throw new Error("Not implemented"); }); -const listPasskeys = os.me.listPasskeys.handler(async ({ context }) => { +const passkeysList = os.me.passkeys.list.handler(async ({ context }) => { const ctx = context as AuthenticatedContext; const passkeys = await getUserPasskeys(ctx.db, ctx.user.id); @@ -150,23 +150,7 @@ const listPasskeys = os.me.listPasskeys.handler(async ({ context }) => { })); }); -const createPasskey = os.me.createPasskey.handler( - async ({ input, context }) => { - const ctx = context as AuthenticatedContext; - const { name: _name } = input; - - const rpInfo = getRPInfo(ctx.origin, ctx.allowedOrigins, ctx.rpName); - const result = await createRegOptions(ctx.db, rpInfo, { - id: ctx.user.id, - email: ctx.user.email, - displayName: ctx.user.displayName, - }); - - return result; - }, -); - -const renamePasskey = os.me.renamePasskey.handler( +const passkeysRename = os.me.passkeys.rename.handler( async ({ input, context }) => { const ctx = context as AuthenticatedContext; const { passkeyId, name } = input; @@ -180,7 +164,7 @@ const renamePasskey = os.me.renamePasskey.handler( }, ); -const deletePasskey = os.me.deletePasskey.handler( +const passkeysDelete = os.me.passkeys.delete.handler( async ({ input, context }) => { const ctx = context as AuthenticatedContext; const { passkeyId } = input; @@ -391,10 +375,11 @@ export const router = os.router({ updateProfile, delete: meDelete, setPassword, - listPasskeys, - createPasskey, - renamePasskey, - deletePasskey, + passkeys: { + list: passkeysList, + rename: passkeysRename, + delete: passkeysDelete, + }, listSessions, revokeSession, revokeAllSessions, diff --git a/apps/api-server/src/utils/webauthn.ts b/apps/api-server/src/utils/webauthn.ts index 1731fbe..e605b2a 100644 --- a/apps/api-server/src/utils/webauthn.ts +++ b/apps/api-server/src/utils/webauthn.ts @@ -3,6 +3,7 @@ */ import type { Database } from "@reviq/db-schema"; +import type { VerifiedRegistrationResponse } from "@simplewebauthn/server"; import type { AuthenticationResponseJSON, PublicKeyCredentialCreationOptionsJSON, @@ -11,7 +12,6 @@ import type { } from "@simplewebauthn/types"; import type { Kysely } from "kysely"; import type { ParsedPasskey, PasskeyRow } from "./passkey-helpers.js"; -import type { VerifiedRegistrationResponse } from "@simplewebauthn/server"; import { generateAuthenticationOptions, generateRegistrationOptions, diff --git a/packages/api-contract/src/contract.ts b/packages/api-contract/src/contract.ts index 11362fc..a1db90a 100644 --- a/packages/api-contract/src/contract.ts +++ b/packages/api-contract/src/contract.ts @@ -115,19 +115,15 @@ export const contract = oc.router({ // Authentication settings setPassword: oc.input(setPasswordInputSchema).output(z.void()), - listPasskeys: oc.output(z.array(passkeyOutputSchema)), - createPasskey: oc.input(z.object({ name: z.string() })).output( - z.object({ - challengeId: z.number(), - options: z.custom(), - }), - ), - renamePasskey: oc - .input(z.object({ passkeyId: z.number(), name: z.string() })) - .output(z.void()), - deletePasskey: oc - .input(z.object({ passkeyId: z.number() })) - .output(z.void()), + + // Passkeys + passkeys: oc.router({ + list: oc.output(z.array(passkeyOutputSchema)), + rename: oc + .input(z.object({ passkeyId: z.number(), name: z.string() })) + .output(z.void()), + delete: oc.input(z.object({ passkeyId: z.number() })).output(z.void()), + }), // Sessions & devices listSessions: oc.output(z.array(sessionOutputSchema)),