sales-frontend-server-side-helper 0.0.19 → 0.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -82,7 +82,7 @@ var refreshTokens = async (request, refreshTokensOptions) => {
82
82
  }
83
83
  try {
84
84
  const tokenResponse = await fetch(
85
- `https://${salesFrontendUtils.getApiHostNameFromEnvironment(new URL(request.url).hostname, refreshTokensOptions?.forceApiHostName)}/api/dat/v1/post/token/refresh`,
85
+ `${salesFrontendUtils.getApiHostNameFromEnvironment(new URL(request.url).hostname, refreshTokensOptions?.forceApiHostName)}/api/dat/v1/post/token/refresh`,
86
86
  {
87
87
  method: "POST",
88
88
  headers: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config/cookie-config.ts","../../src/utils/cookie-utils.ts","../../src/api-route/refresh-token.ts","../../src/api-route/server-time.ts"],"names":["getEnvironmentFromHostname","NextResponse","getApiHostNameFromEnvironment"],"mappings":"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","file":"index.cjs","sourcesContent":["export const COOKIE_DEFAULT_CONFIG = {\n httpOnly: true,\n maxAge: 60 * 60 * 24,\n sameSite: 'strict' as const,\n secure: true\n};\n","import { NextRequest, NextResponse } from 'next/server';\n\nimport { getEnvironmentFromHostname } from 'sales-frontend-utils';\n\nimport { COOKIE_DEFAULT_CONFIG } from '../config/cookie-config';\nimport { CookieData } from '../server-side-helper.types';\n\n/**\n * 쿠키 생성\n * @param response\n * @param cookieData\n * @returns\n */\nexport const createResponseWithCookies = (\n response: NextResponse,\n request: NextRequest,\n cookieData?: CookieData\n): NextResponse => {\n const { hostname } = new URL(request.url);\n\n // 토큰타입\n if (cookieData?.tokens?.tokenType) {\n response.cookies.set({\n name: 'tokenType',\n value: cookieData.tokens.tokenType,\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // expiresIn\n if (cookieData?.tokens?.expiresIn) {\n response.cookies.set({\n name: 'expiresIn',\n value: String(cookieData.tokens.expiresIn),\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // 액세스 토큰 쿠키\n if (cookieData?.tokens?.accessToken) {\n response.cookies.set({\n name: 'accessToken',\n value: cookieData.tokens.accessToken,\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // 리프레시 토큰 쿠키\n if (cookieData?.tokens?.refreshToken) {\n response.cookies.set({\n name: 'refreshToken',\n value: cookieData.tokens.refreshToken,\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // FormFactor 쿠키\n if (cookieData?.formFactor) {\n response.cookies.set({\n name: 'formFactor',\n value: cookieData.formFactor,\n ...getDefaultCookieConfig(hostname),\n maxAge: 0\n });\n }\n\n return response;\n};\n\n/**\n * 환경에 따른 기본 쿠키 설정값 반환\n * @param hostname\n * @returns\n */\nconst getDefaultCookieConfig = (hostname: string) => {\n const environment = getEnvironmentFromHostname(hostname);\n\n if (environment === 'local' || environment === 'dev') {\n return {\n ...COOKIE_DEFAULT_CONFIG,\n httpOnly: false,\n secure: false\n };\n }\n\n return COOKIE_DEFAULT_CONFIG;\n};\n","import { NextRequest, NextResponse } from 'next/server';\n\nimport { getApiHostNameFromEnvironment } from 'sales-frontend-utils';\n\nimport { DspResponseDspTokenResponseDto, ApiErrorResponse, RefreshTokensOptions } from '../server-side-helper.types';\nimport { createResponseWithCookies } from '../utils/cookie-utils';\n\n/**\n * 리프레시 토큰을 사용하여 새로운 액세스 토큰과 리프레시 토큰을 쿠키로 발급 받습니다.\n * API Route에서 사용될 수 있습니다.\n * 권장경로: /app/internal/api/auth/refresh/route.ts\n * Method: POST\n * @returns 새로운 AT, RT 발급 후 새 AT 반환\n */\nexport const refreshTokens = async (request: NextRequest, refreshTokensOptions?: RefreshTokensOptions) => {\n const refreshToken = request.cookies.get('refreshToken')?.value;\n\n // 기본 밸리데이션\n if (!refreshToken) {\n return NextResponse.json(\n {\n isSuccess: false,\n code: 'REFRESH_TOKEN_MISSING',\n message: '[ServerSideHelper-Api-Route] Refresh Token이 존재하지 않습니다.)',\n data: null\n } as ApiErrorResponse,\n { status: 401 }\n );\n }\n\n try {\n // TODO: 실제 토큰 재발급 API 주소로 변경 필요\n const tokenResponse = await fetch(\n `https://${getApiHostNameFromEnvironment(new URL(request.url).hostname, refreshTokensOptions?.forceApiHostName)}/api/dat/v1/post/token/refresh`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...Object.fromEntries(\n Array.from(request.headers.entries()).filter(([key]) => key.toLowerCase().startsWith('x-channel'))\n )\n },\n body: JSON.stringify({\n refreshToken\n })\n }\n );\n\n const tokenData: DspResponseDspTokenResponseDto = await tokenResponse.json();\n console.log('[ServerSideHelper-Api-Route] tokenData', tokenData);\n\n if (!tokenResponse.ok || !tokenData.isSuccess === false) {\n return NextResponse.json(\n {\n isSuccess: false,\n code: tokenData.code || 'TOKEN_REFRESH_FAILED',\n message: `[ServerSideHelper-Api-Route] ${tokenData.message || '토큰 갱신에 실패했습니다.'}`,\n data: null\n } as ApiErrorResponse,\n { status: 401 }\n );\n }\n\n // 응답 유효성 체크\n if (!tokenData.data?.accessToken || !tokenData.data?.refreshToken) {\n throw new Error('[ServerSideHelper-Api-Route] Invalid token data structure');\n }\n\n const { accessToken: newAccessToken, refreshToken: newRefreshToken, expiresIn, tokenType } = tokenData.data;\n\n // 응답 생성\n const response = NextResponse.json(\n {\n isSuccess: true,\n code: '',\n message: '[ServerSideHelper-Api-Route] Token 갱신 성공',\n data: { accessToken: newAccessToken, refreshToken: newRefreshToken, expiresIn, tokenType }\n },\n { status: 200 }\n );\n\n // 새 토큰들을 쿠키에 저장\n createResponseWithCookies(response, request, {\n tokens: { accessToken: newAccessToken, refreshToken: newRefreshToken, expiresIn, tokenType }\n });\n\n return response;\n } catch (error) {\n console.error('Token refresh error:', error);\n\n return NextResponse.json(\n {\n isSuccess: false,\n code: 'REFRESH_TOKEN_MISSING',\n message: '[ServerSideHelper-Api-Route] 토큰 재발급 중 오류가 발생했습니다.',\n data: null\n } as ApiErrorResponse,\n { status: 401 }\n );\n }\n};\n","import { NextResponse } from 'next/server';\n\n/**\n * 서버의 현재 시간을 밀리초 단위로 반환합니다.\n * API Route에서 사용될 수 있습니다.\n * 권장경로: /app/internal/api/time/route.ts\n * Method: GET\n * @returns\n */\nexport const getServerTime = () => {\n const now = new Date();\n const serverTime = now.getTime();\n\n return NextResponse.json({\n isSuccess: true,\n code: '',\n message: 'Current server time fetched successfully',\n data: { serverTime }\n });\n};\n"]}
1
+ {"version":3,"sources":["../../src/config/cookie-config.ts","../../src/utils/cookie-utils.ts","../../src/api-route/refresh-token.ts","../../src/api-route/server-time.ts"],"names":["getEnvironmentFromHostname","NextResponse","getApiHostNameFromEnvironment"],"mappings":"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","file":"index.cjs","sourcesContent":["export const COOKIE_DEFAULT_CONFIG = {\n httpOnly: true,\n maxAge: 60 * 60 * 24,\n sameSite: 'strict' as const,\n secure: true\n};\n","import { NextRequest, NextResponse } from 'next/server';\n\nimport { getEnvironmentFromHostname } from 'sales-frontend-utils';\n\nimport { COOKIE_DEFAULT_CONFIG } from '../config/cookie-config';\nimport { CookieData } from '../server-side-helper.types';\n\n/**\n * 쿠키 생성\n * @param response\n * @param cookieData\n * @returns\n */\nexport const createResponseWithCookies = (\n response: NextResponse,\n request: NextRequest,\n cookieData?: CookieData\n): NextResponse => {\n const { hostname } = new URL(request.url);\n\n // 토큰타입\n if (cookieData?.tokens?.tokenType) {\n response.cookies.set({\n name: 'tokenType',\n value: cookieData.tokens.tokenType,\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // expiresIn\n if (cookieData?.tokens?.expiresIn) {\n response.cookies.set({\n name: 'expiresIn',\n value: String(cookieData.tokens.expiresIn),\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // 액세스 토큰 쿠키\n if (cookieData?.tokens?.accessToken) {\n response.cookies.set({\n name: 'accessToken',\n value: cookieData.tokens.accessToken,\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // 리프레시 토큰 쿠키\n if (cookieData?.tokens?.refreshToken) {\n response.cookies.set({\n name: 'refreshToken',\n value: cookieData.tokens.refreshToken,\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // FormFactor 쿠키\n if (cookieData?.formFactor) {\n response.cookies.set({\n name: 'formFactor',\n value: cookieData.formFactor,\n ...getDefaultCookieConfig(hostname),\n maxAge: 0\n });\n }\n\n return response;\n};\n\n/**\n * 환경에 따른 기본 쿠키 설정값 반환\n * @param hostname\n * @returns\n */\nconst getDefaultCookieConfig = (hostname: string) => {\n const environment = getEnvironmentFromHostname(hostname);\n\n if (environment === 'local' || environment === 'dev') {\n return {\n ...COOKIE_DEFAULT_CONFIG,\n httpOnly: false,\n secure: false\n };\n }\n\n return COOKIE_DEFAULT_CONFIG;\n};\n","import { NextRequest, NextResponse } from 'next/server';\n\nimport { getApiHostNameFromEnvironment } from 'sales-frontend-utils';\n\nimport { DspResponseDspTokenResponseDto, ApiErrorResponse, RefreshTokensOptions } from '../server-side-helper.types';\nimport { createResponseWithCookies } from '../utils/cookie-utils';\n\n/**\n * 리프레시 토큰을 사용하여 새로운 액세스 토큰과 리프레시 토큰을 쿠키로 발급 받습니다.\n * API Route에서 사용될 수 있습니다.\n * 권장경로: /app/internal/api/auth/refresh/route.ts\n * Method: POST\n * @returns 새로운 AT, RT 발급 후 새 AT 반환\n */\nexport const refreshTokens = async (request: NextRequest, refreshTokensOptions?: RefreshTokensOptions) => {\n const refreshToken = request.cookies.get('refreshToken')?.value;\n\n // 기본 밸리데이션\n if (!refreshToken) {\n return NextResponse.json(\n {\n isSuccess: false,\n code: 'REFRESH_TOKEN_MISSING',\n message: '[ServerSideHelper-Api-Route] Refresh Token이 존재하지 않습니다.)',\n data: null\n } as ApiErrorResponse,\n { status: 401 }\n );\n }\n\n try {\n // TODO: 실제 토큰 재발급 API 주소로 변경 필요\n const tokenResponse = await fetch(\n `${getApiHostNameFromEnvironment(new URL(request.url).hostname, refreshTokensOptions?.forceApiHostName)}/api/dat/v1/post/token/refresh`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...Object.fromEntries(\n Array.from(request.headers.entries()).filter(([key]) => key.toLowerCase().startsWith('x-channel'))\n )\n },\n body: JSON.stringify({\n refreshToken\n })\n }\n );\n\n const tokenData: DspResponseDspTokenResponseDto = await tokenResponse.json();\n console.log('[ServerSideHelper-Api-Route] tokenData', tokenData);\n\n if (!tokenResponse.ok || !tokenData.isSuccess === false) {\n return NextResponse.json(\n {\n isSuccess: false,\n code: tokenData.code || 'TOKEN_REFRESH_FAILED',\n message: `[ServerSideHelper-Api-Route] ${tokenData.message || '토큰 갱신에 실패했습니다.'}`,\n data: null\n } as ApiErrorResponse,\n { status: 401 }\n );\n }\n\n // 응답 유효성 체크\n if (!tokenData.data?.accessToken || !tokenData.data?.refreshToken) {\n throw new Error('[ServerSideHelper-Api-Route] Invalid token data structure');\n }\n\n const { accessToken: newAccessToken, refreshToken: newRefreshToken, expiresIn, tokenType } = tokenData.data;\n\n // 응답 생성\n const response = NextResponse.json(\n {\n isSuccess: true,\n code: '',\n message: '[ServerSideHelper-Api-Route] Token 갱신 성공',\n data: { accessToken: newAccessToken, refreshToken: newRefreshToken, expiresIn, tokenType }\n },\n { status: 200 }\n );\n\n // 새 토큰들을 쿠키에 저장\n createResponseWithCookies(response, request, {\n tokens: { accessToken: newAccessToken, refreshToken: newRefreshToken, expiresIn, tokenType }\n });\n\n return response;\n } catch (error) {\n console.error('Token refresh error:', error);\n\n return NextResponse.json(\n {\n isSuccess: false,\n code: 'REFRESH_TOKEN_MISSING',\n message: '[ServerSideHelper-Api-Route] 토큰 재발급 중 오류가 발생했습니다.',\n data: null\n } as ApiErrorResponse,\n { status: 401 }\n );\n }\n};\n","import { NextResponse } from 'next/server';\n\n/**\n * 서버의 현재 시간을 밀리초 단위로 반환합니다.\n * API Route에서 사용될 수 있습니다.\n * 권장경로: /app/internal/api/time/route.ts\n * Method: GET\n * @returns\n */\nexport const getServerTime = () => {\n const now = new Date();\n const serverTime = now.getTime();\n\n return NextResponse.json({\n isSuccess: true,\n code: '',\n message: 'Current server time fetched successfully',\n data: { serverTime }\n });\n};\n"]}
@@ -80,7 +80,7 @@ var refreshTokens = async (request, refreshTokensOptions) => {
80
80
  }
81
81
  try {
82
82
  const tokenResponse = await fetch(
83
- `https://${getApiHostNameFromEnvironment(new URL(request.url).hostname, refreshTokensOptions?.forceApiHostName)}/api/dat/v1/post/token/refresh`,
83
+ `${getApiHostNameFromEnvironment(new URL(request.url).hostname, refreshTokensOptions?.forceApiHostName)}/api/dat/v1/post/token/refresh`,
84
84
  {
85
85
  method: "POST",
86
86
  headers: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config/cookie-config.ts","../../src/utils/cookie-utils.ts","../../src/api-route/refresh-token.ts","../../src/api-route/server-time.ts"],"names":["NextResponse"],"mappings":"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","file":"index.js","sourcesContent":["export const COOKIE_DEFAULT_CONFIG = {\n httpOnly: true,\n maxAge: 60 * 60 * 24,\n sameSite: 'strict' as const,\n secure: true\n};\n","import { NextRequest, NextResponse } from 'next/server';\n\nimport { getEnvironmentFromHostname } from 'sales-frontend-utils';\n\nimport { COOKIE_DEFAULT_CONFIG } from '../config/cookie-config';\nimport { CookieData } from '../server-side-helper.types';\n\n/**\n * 쿠키 생성\n * @param response\n * @param cookieData\n * @returns\n */\nexport const createResponseWithCookies = (\n response: NextResponse,\n request: NextRequest,\n cookieData?: CookieData\n): NextResponse => {\n const { hostname } = new URL(request.url);\n\n // 토큰타입\n if (cookieData?.tokens?.tokenType) {\n response.cookies.set({\n name: 'tokenType',\n value: cookieData.tokens.tokenType,\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // expiresIn\n if (cookieData?.tokens?.expiresIn) {\n response.cookies.set({\n name: 'expiresIn',\n value: String(cookieData.tokens.expiresIn),\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // 액세스 토큰 쿠키\n if (cookieData?.tokens?.accessToken) {\n response.cookies.set({\n name: 'accessToken',\n value: cookieData.tokens.accessToken,\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // 리프레시 토큰 쿠키\n if (cookieData?.tokens?.refreshToken) {\n response.cookies.set({\n name: 'refreshToken',\n value: cookieData.tokens.refreshToken,\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // FormFactor 쿠키\n if (cookieData?.formFactor) {\n response.cookies.set({\n name: 'formFactor',\n value: cookieData.formFactor,\n ...getDefaultCookieConfig(hostname),\n maxAge: 0\n });\n }\n\n return response;\n};\n\n/**\n * 환경에 따른 기본 쿠키 설정값 반환\n * @param hostname\n * @returns\n */\nconst getDefaultCookieConfig = (hostname: string) => {\n const environment = getEnvironmentFromHostname(hostname);\n\n if (environment === 'local' || environment === 'dev') {\n return {\n ...COOKIE_DEFAULT_CONFIG,\n httpOnly: false,\n secure: false\n };\n }\n\n return COOKIE_DEFAULT_CONFIG;\n};\n","import { NextRequest, NextResponse } from 'next/server';\n\nimport { getApiHostNameFromEnvironment } from 'sales-frontend-utils';\n\nimport { DspResponseDspTokenResponseDto, ApiErrorResponse, RefreshTokensOptions } from '../server-side-helper.types';\nimport { createResponseWithCookies } from '../utils/cookie-utils';\n\n/**\n * 리프레시 토큰을 사용하여 새로운 액세스 토큰과 리프레시 토큰을 쿠키로 발급 받습니다.\n * API Route에서 사용될 수 있습니다.\n * 권장경로: /app/internal/api/auth/refresh/route.ts\n * Method: POST\n * @returns 새로운 AT, RT 발급 후 새 AT 반환\n */\nexport const refreshTokens = async (request: NextRequest, refreshTokensOptions?: RefreshTokensOptions) => {\n const refreshToken = request.cookies.get('refreshToken')?.value;\n\n // 기본 밸리데이션\n if (!refreshToken) {\n return NextResponse.json(\n {\n isSuccess: false,\n code: 'REFRESH_TOKEN_MISSING',\n message: '[ServerSideHelper-Api-Route] Refresh Token이 존재하지 않습니다.)',\n data: null\n } as ApiErrorResponse,\n { status: 401 }\n );\n }\n\n try {\n // TODO: 실제 토큰 재발급 API 주소로 변경 필요\n const tokenResponse = await fetch(\n `https://${getApiHostNameFromEnvironment(new URL(request.url).hostname, refreshTokensOptions?.forceApiHostName)}/api/dat/v1/post/token/refresh`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...Object.fromEntries(\n Array.from(request.headers.entries()).filter(([key]) => key.toLowerCase().startsWith('x-channel'))\n )\n },\n body: JSON.stringify({\n refreshToken\n })\n }\n );\n\n const tokenData: DspResponseDspTokenResponseDto = await tokenResponse.json();\n console.log('[ServerSideHelper-Api-Route] tokenData', tokenData);\n\n if (!tokenResponse.ok || !tokenData.isSuccess === false) {\n return NextResponse.json(\n {\n isSuccess: false,\n code: tokenData.code || 'TOKEN_REFRESH_FAILED',\n message: `[ServerSideHelper-Api-Route] ${tokenData.message || '토큰 갱신에 실패했습니다.'}`,\n data: null\n } as ApiErrorResponse,\n { status: 401 }\n );\n }\n\n // 응답 유효성 체크\n if (!tokenData.data?.accessToken || !tokenData.data?.refreshToken) {\n throw new Error('[ServerSideHelper-Api-Route] Invalid token data structure');\n }\n\n const { accessToken: newAccessToken, refreshToken: newRefreshToken, expiresIn, tokenType } = tokenData.data;\n\n // 응답 생성\n const response = NextResponse.json(\n {\n isSuccess: true,\n code: '',\n message: '[ServerSideHelper-Api-Route] Token 갱신 성공',\n data: { accessToken: newAccessToken, refreshToken: newRefreshToken, expiresIn, tokenType }\n },\n { status: 200 }\n );\n\n // 새 토큰들을 쿠키에 저장\n createResponseWithCookies(response, request, {\n tokens: { accessToken: newAccessToken, refreshToken: newRefreshToken, expiresIn, tokenType }\n });\n\n return response;\n } catch (error) {\n console.error('Token refresh error:', error);\n\n return NextResponse.json(\n {\n isSuccess: false,\n code: 'REFRESH_TOKEN_MISSING',\n message: '[ServerSideHelper-Api-Route] 토큰 재발급 중 오류가 발생했습니다.',\n data: null\n } as ApiErrorResponse,\n { status: 401 }\n );\n }\n};\n","import { NextResponse } from 'next/server';\n\n/**\n * 서버의 현재 시간을 밀리초 단위로 반환합니다.\n * API Route에서 사용될 수 있습니다.\n * 권장경로: /app/internal/api/time/route.ts\n * Method: GET\n * @returns\n */\nexport const getServerTime = () => {\n const now = new Date();\n const serverTime = now.getTime();\n\n return NextResponse.json({\n isSuccess: true,\n code: '',\n message: 'Current server time fetched successfully',\n data: { serverTime }\n });\n};\n"]}
1
+ {"version":3,"sources":["../../src/config/cookie-config.ts","../../src/utils/cookie-utils.ts","../../src/api-route/refresh-token.ts","../../src/api-route/server-time.ts"],"names":["NextResponse"],"mappings":"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","file":"index.js","sourcesContent":["export const COOKIE_DEFAULT_CONFIG = {\n httpOnly: true,\n maxAge: 60 * 60 * 24,\n sameSite: 'strict' as const,\n secure: true\n};\n","import { NextRequest, NextResponse } from 'next/server';\n\nimport { getEnvironmentFromHostname } from 'sales-frontend-utils';\n\nimport { COOKIE_DEFAULT_CONFIG } from '../config/cookie-config';\nimport { CookieData } from '../server-side-helper.types';\n\n/**\n * 쿠키 생성\n * @param response\n * @param cookieData\n * @returns\n */\nexport const createResponseWithCookies = (\n response: NextResponse,\n request: NextRequest,\n cookieData?: CookieData\n): NextResponse => {\n const { hostname } = new URL(request.url);\n\n // 토큰타입\n if (cookieData?.tokens?.tokenType) {\n response.cookies.set({\n name: 'tokenType',\n value: cookieData.tokens.tokenType,\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // expiresIn\n if (cookieData?.tokens?.expiresIn) {\n response.cookies.set({\n name: 'expiresIn',\n value: String(cookieData.tokens.expiresIn),\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // 액세스 토큰 쿠키\n if (cookieData?.tokens?.accessToken) {\n response.cookies.set({\n name: 'accessToken',\n value: cookieData.tokens.accessToken,\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // 리프레시 토큰 쿠키\n if (cookieData?.tokens?.refreshToken) {\n response.cookies.set({\n name: 'refreshToken',\n value: cookieData.tokens.refreshToken,\n ...getDefaultCookieConfig(hostname)\n });\n }\n\n // FormFactor 쿠키\n if (cookieData?.formFactor) {\n response.cookies.set({\n name: 'formFactor',\n value: cookieData.formFactor,\n ...getDefaultCookieConfig(hostname),\n maxAge: 0\n });\n }\n\n return response;\n};\n\n/**\n * 환경에 따른 기본 쿠키 설정값 반환\n * @param hostname\n * @returns\n */\nconst getDefaultCookieConfig = (hostname: string) => {\n const environment = getEnvironmentFromHostname(hostname);\n\n if (environment === 'local' || environment === 'dev') {\n return {\n ...COOKIE_DEFAULT_CONFIG,\n httpOnly: false,\n secure: false\n };\n }\n\n return COOKIE_DEFAULT_CONFIG;\n};\n","import { NextRequest, NextResponse } from 'next/server';\n\nimport { getApiHostNameFromEnvironment } from 'sales-frontend-utils';\n\nimport { DspResponseDspTokenResponseDto, ApiErrorResponse, RefreshTokensOptions } from '../server-side-helper.types';\nimport { createResponseWithCookies } from '../utils/cookie-utils';\n\n/**\n * 리프레시 토큰을 사용하여 새로운 액세스 토큰과 리프레시 토큰을 쿠키로 발급 받습니다.\n * API Route에서 사용될 수 있습니다.\n * 권장경로: /app/internal/api/auth/refresh/route.ts\n * Method: POST\n * @returns 새로운 AT, RT 발급 후 새 AT 반환\n */\nexport const refreshTokens = async (request: NextRequest, refreshTokensOptions?: RefreshTokensOptions) => {\n const refreshToken = request.cookies.get('refreshToken')?.value;\n\n // 기본 밸리데이션\n if (!refreshToken) {\n return NextResponse.json(\n {\n isSuccess: false,\n code: 'REFRESH_TOKEN_MISSING',\n message: '[ServerSideHelper-Api-Route] Refresh Token이 존재하지 않습니다.)',\n data: null\n } as ApiErrorResponse,\n { status: 401 }\n );\n }\n\n try {\n // TODO: 실제 토큰 재발급 API 주소로 변경 필요\n const tokenResponse = await fetch(\n `${getApiHostNameFromEnvironment(new URL(request.url).hostname, refreshTokensOptions?.forceApiHostName)}/api/dat/v1/post/token/refresh`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...Object.fromEntries(\n Array.from(request.headers.entries()).filter(([key]) => key.toLowerCase().startsWith('x-channel'))\n )\n },\n body: JSON.stringify({\n refreshToken\n })\n }\n );\n\n const tokenData: DspResponseDspTokenResponseDto = await tokenResponse.json();\n console.log('[ServerSideHelper-Api-Route] tokenData', tokenData);\n\n if (!tokenResponse.ok || !tokenData.isSuccess === false) {\n return NextResponse.json(\n {\n isSuccess: false,\n code: tokenData.code || 'TOKEN_REFRESH_FAILED',\n message: `[ServerSideHelper-Api-Route] ${tokenData.message || '토큰 갱신에 실패했습니다.'}`,\n data: null\n } as ApiErrorResponse,\n { status: 401 }\n );\n }\n\n // 응답 유효성 체크\n if (!tokenData.data?.accessToken || !tokenData.data?.refreshToken) {\n throw new Error('[ServerSideHelper-Api-Route] Invalid token data structure');\n }\n\n const { accessToken: newAccessToken, refreshToken: newRefreshToken, expiresIn, tokenType } = tokenData.data;\n\n // 응답 생성\n const response = NextResponse.json(\n {\n isSuccess: true,\n code: '',\n message: '[ServerSideHelper-Api-Route] Token 갱신 성공',\n data: { accessToken: newAccessToken, refreshToken: newRefreshToken, expiresIn, tokenType }\n },\n { status: 200 }\n );\n\n // 새 토큰들을 쿠키에 저장\n createResponseWithCookies(response, request, {\n tokens: { accessToken: newAccessToken, refreshToken: newRefreshToken, expiresIn, tokenType }\n });\n\n return response;\n } catch (error) {\n console.error('Token refresh error:', error);\n\n return NextResponse.json(\n {\n isSuccess: false,\n code: 'REFRESH_TOKEN_MISSING',\n message: '[ServerSideHelper-Api-Route] 토큰 재발급 중 오류가 발생했습니다.',\n data: null\n } as ApiErrorResponse,\n { status: 401 }\n );\n }\n};\n","import { NextResponse } from 'next/server';\n\n/**\n * 서버의 현재 시간을 밀리초 단위로 반환합니다.\n * API Route에서 사용될 수 있습니다.\n * 권장경로: /app/internal/api/time/route.ts\n * Method: GET\n * @returns\n */\nexport const getServerTime = () => {\n const now = new Date();\n const serverTime = now.getTime();\n\n return NextResponse.json({\n isSuccess: true,\n code: '',\n message: 'Current server time fetched successfully',\n data: { serverTime }\n });\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sales-frontend-server-side-helper",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "files": [
@@ -60,8 +60,8 @@
60
60
  "next": ">=15.3.0"
61
61
  },
62
62
  "dependencies": {
63
- "sales-frontend-api": "0.0.36",
64
- "sales-frontend-utils": "0.0.9"
63
+ "sales-frontend-utils": "0.0.10",
64
+ "sales-frontend-api": "0.0.38"
65
65
  },
66
66
  "scripts": {
67
67
  "lint": "eslint . --max-warnings 0",