From b91dcbcaaac5acd4c7349cd3ed0996c547f58756 Mon Sep 17 00:00:00 2001 From: hided62 Date: Thu, 3 Sep 2026 07:29:35 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=9C=A0=EC=82=B0=20=EA=B0=95=ED=99=94?= =?UTF-8?q?=20=EB=B2=94=EC=9C=84=20=EC=98=A4=EB=A5=98=EB=A5=BC=20=ED=95=9C?= =?UTF-8?q?=EA=B5=AD=EC=96=B4=EB=A1=9C=20=EC=95=88=EB=82=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/game-api/src/router/inherit/index.ts | 10 +++++++++- app/game-api/test/inheritRouter.test.ts | 15 +++++++++++++++ .../inheritance-management.spec.ts | 16 ++++++++++++++-- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/app/game-api/src/router/inherit/index.ts b/app/game-api/src/router/inherit/index.ts index 76a1e3ae..2bb0886e 100644 --- a/app/game-api/src/router/inherit/index.ts +++ b/app/game-api/src/router/inherit/index.ts @@ -38,6 +38,8 @@ const BUFF_KEYS: InheritBuffType[] = [ const UNIQUE_ITEM_SLOT_ORDER: readonly ItemSlot[] = ['horse', 'weapon', 'book', 'item']; const POSTGRES_INTEGER_MAX = 2_147_483_647; +const MIN_INHERIT_BUFF_LEVEL = 1; +const MAX_INHERIT_BUFF_LEVEL = 5; const parseBuffRecord = (raw: unknown): Record => { if (typeof raw === 'string') { @@ -302,7 +304,7 @@ export const inheritRouter = router({ .input( z.object({ type: z.enum(BUFF_KEYS), - level: z.number().int().min(1).max(5), + level: z.number().int(), }) ) .mutation(async ({ ctx, input }) => { @@ -310,6 +312,12 @@ export const inheritRouter = router({ if (!userId) { throw new TRPCError({ code: 'UNAUTHORIZED' }); } + if (input.level < MIN_INHERIT_BUFF_LEVEL || input.level > MAX_INHERIT_BUFF_LEVEL) { + throw new TRPCError({ + code: 'BAD_REQUEST', + message: '유산 강화는 1단계부터 5단계까지만 구입할 수 있습니다.', + }); + } const result = await requestInheritanceAction(ctx, userId, { action: 'buyHiddenBuff', diff --git a/app/game-api/test/inheritRouter.test.ts b/app/game-api/test/inheritRouter.test.ts index ae9af24c..34a4e00c 100644 --- a/app/game-api/test/inheritRouter.test.ts +++ b/app/game-api/test/inheritRouter.test.ts @@ -285,6 +285,21 @@ describe('inherit router actor and permission boundaries', () => { }); }); + it('rejects an out-of-range inheritance buff level with a user-facing message', async () => { + const fixture = buildContext({}); + + await expect( + appRouter.createCaller(fixture.context).inherit.buyHiddenBuff({ + type: 'warAvoidRatio', + level: 6, + }) + ).rejects.toMatchObject({ + code: 'BAD_REQUEST', + message: '유산 강화는 1단계부터 5단계까지만 구입할 수 있습니다.', + }); + expect(fixture.requestCommand).not.toHaveBeenCalled(); + }); + it('reports the Ref S100 stat-reset ban and maps the authoritative daemon rejection', async () => { const fixture = buildContext({ configMap: { targetGeneralPool: 'SPoolUnderU100' }, diff --git a/tools/frontend-legacy-parity/inheritance-management.spec.ts b/tools/frontend-legacy-parity/inheritance-management.spec.ts index 185ade7c..32d99348 100644 --- a/tools/frontend-legacy-parity/inheritance-management.spec.ts +++ b/tools/frontend-legacy-parity/inheritance-management.spec.ts @@ -9,6 +9,13 @@ const artifactRoot = process.env.FRONTEND_PARITY_ARTIFACT_DIR; const gameUrl = `http://127.0.0.1:${process.env.FRONTEND_PARITY_GAME_PORT ?? '15102'}/che/inherit`; const response = (data: unknown) => ({ result: { data } }); +const errorResponse = (path: string, message: string) => ({ + error: { + message, + code: -32000, + data: { code: 'BAD_REQUEST', httpStatus: 400, path }, + }, +}); const operations = (route: Route): string[] => { const pathname = new URL(route.request().url()).pathname; @@ -149,9 +156,11 @@ const installFixture = async ( const requestBody: unknown = route.request().postData() ? route.request().postDataJSON() : null; if (options.failBuff && names.includes('inherit.buyHiddenBuff')) { await route.fulfill({ - status: 500, + status: 400, contentType: 'application/json', - body: JSON.stringify({ error: { message: '의도한 유산 구입 오류' } }), + body: JSON.stringify([ + errorResponse('inherit.buyHiddenBuff', '유산 강화는 1단계부터 5단계까지만 구입할 수 있습니다.'), + ]), }); return; } @@ -451,6 +460,9 @@ test.describe('inheritance management legacy parity', () => { await page.locator('#buff-warAvoidRatio').fill('1'); await page.locator('#buff-warAvoidRatio').locator('xpath=../..').getByRole('button', { name: '구입' }).click(); await expect(page.locator('[role="alert"]')).toBeVisible(); + await expect(page.locator('[role="alert"]')).toContainText( + '유산 강화는 1단계부터 5단계까지만 구입할 수 있습니다.' + ); await expect(page.locator('#buff-warAvoidRatio')).toHaveValue('1'); await expect(page.locator('#buff-warAvoidRatio')).toBeEnabled(); });