@spfn/cms 0.1.0-alpha.74 → 0.1.0-alpha.76
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.
- package/dist/api.d.ts +44 -8
- package/dist/api.js +45 -8
- package/dist/api.js.map +1 -1
- package/dist/client.js +44 -7
- package/dist/client.js.map +1 -1
- package/dist/lib/contracts/labels.d.ts +33 -1
- package/dist/lib/contracts/labels.js +33 -0
- package/dist/lib/contracts/labels.js.map +1 -1
- package/dist/server/generators/index.js +5 -3
- package/dist/server/generators/index.js.map +1 -1
- package/dist/server/repositories/index.js +5 -3
- package/dist/server/repositories/index.js.map +1 -1
- package/dist/server/routes/labels/[id]/index.js +39 -3
- package/dist/server/routes/labels/[id]/index.js.map +1 -1
- package/dist/server/routes/labels/[labelId]/admin/index.js +38 -3
- package/dist/server/routes/labels/[labelId]/admin/index.js.map +1 -1
- package/dist/server/routes/labels/[labelId]/publish/index.js +37 -3
- package/dist/server/routes/labels/[labelId]/publish/index.js.map +1 -1
- package/dist/server/routes/labels/[labelId]/versions/index.js +660 -0
- package/dist/server/routes/labels/[labelId]/versions/index.js.map +1 -0
- package/dist/server/routes/labels/_labelId_/versions/index.d.ts +11 -0
- package/dist/server/routes/labels/by-key/[key]/index.js +38 -3
- package/dist/server/routes/labels/by-key/[key]/index.js.map +1 -1
- package/dist/server/routes/labels/index.js +38 -3
- package/dist/server/routes/labels/index.js.map +1 -1
- package/dist/server/routes/published-cache/index.js +1 -1
- package/dist/server/routes/published-cache/index.js.map +1 -1
- package/dist/server/routes/values/[labelId]/[version]/index.js +5 -3
- package/dist/server/routes/values/[labelId]/[version]/index.js.map +1 -1
- package/dist/server/routes/values/[labelId]/index.js +5 -3
- package/dist/server/routes/values/[labelId]/index.js.map +1 -1
- package/dist/server.js +5 -3
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/hooks/useSection.ts","../src/client/store/cms.store.ts","../src/api/index.ts","../src/api/cms-labels.ts","../src/lib/contracts/labels.ts","../src/api/cms-labels-by-key.ts","../src/api/cms-labels-publish.ts","../src/api/cms-labels-admin.ts","../src/api/cms-published-cache.ts","../src/lib/contracts/published-cache.ts","../src/api/cms-values.ts","../src/lib/contracts/values.ts","../src/client/hooks/useSections.ts","../src/client/components/InitCms.tsx","../src/server/helpers/locale.actions.ts","../src/server/config/cms.config.ts","../src/lib/constants/locale.constants.ts"],"sourcesContent":["/**\n * useSection Hook\n *\n * 클라이언트 컴포넌트에서 섹션 데이터 사용\n */\n\n'use client';\n\nimport React from 'react';\nimport { useCmsStore } from '../store/cms.store';\n\n/**\n * 변수 치환 헬퍼 (서버와 동일)\n */\nfunction replaceVariables(text: string, replace: Record<string, string | number>): string\n{\n return text.replace(/\\{(\\w+)}/g, (match, key) =>\n {\n const value = replace[key];\n return value !== undefined ? String(value) : match;\n });\n}\n\n/**\n * 섹션 Hook (서버 API와 동일한 패턴)\n *\n * @param section - 섹션 이름\n * @param options - 옵션 (autoLoad: 자동 로드 여부)\n * @returns { t, data, loading }\n *\n * @example\n * ```tsx\n * 'use client';\n * import { useSection } from '@spfn/cms/client';\n *\n * export function ClientComponent()\n * {\n * const { t } = useSection('home', { autoLoad: true });\n * return <h1>{t('hero.title')}</h1>;\n * }\n * ```\n */\nexport function useSection(\n section: string,\n options: { autoLoad?: boolean; locale?: string } = {}\n)\n{\n const { autoLoad = false, locale = 'ko' } = options;\n\n const sectionData = useCmsStore((state) => state.sections[section]);\n const loading = useCmsStore((state) => state.loading[section] ?? false);\n const loadSection = useCmsStore((state) => state.loadSection);\n\n // 자동 로드 옵션이 켜져있고 데이터가 없으면 로드\n React.useEffect(() =>\n {\n if (autoLoad && !sectionData && !loading)\n {\n loadSection(section, locale);\n }\n }, [autoLoad, section, locale, sectionData, loading, loadSection]);\n\n // Translation function (서버와 동일)\n const t = React.useCallback(\n (key: string, defaultValue?: any, replace?: Record<string, string | number>) =>\n {\n if (!sectionData)\n {\n return defaultValue;\n }\n\n const fullKey = `${section}.${key}`;\n let value = sectionData.content[fullKey];\n\n if (value === undefined)\n {\n value = defaultValue;\n }\n\n // 문자열이고 치환 맵이 있으면 변수 치환\n if (typeof value === 'string' && replace)\n {\n value = replaceVariables(value, replace);\n }\n\n return value;\n },\n [section, sectionData]\n );\n\n return {\n t,\n data: sectionData,\n loading,\n };\n}","/**\n * CMS Zustand Store\n *\n * 클라이언트 컴포넌트에서 CMS 사용을 위한 상태 관리\n * - 서버에서 초기화된 데이터를 클라이언트로 전달\n * - 클라이언트에서 비동기로 로드 가능\n */\n\n'use client';\n\nimport { create } from 'zustand';\nimport { cmsApi } from '@/api';\nimport type { SectionData } from '@/server';\n\ninterface CmsState\n{\n /**\n * 섹션별 데이터\n * { 'home': { section: 'home', content: {...}, version: 1, ... }, ... }\n */\n sections: Record<string, SectionData>;\n\n /**\n * 로딩 상태\n */\n loading: Record<string, boolean>;\n\n /**\n * 섹션 데이터 설정 (서버에서 초기화용)\n */\n setSection: (section: string, data: SectionData) => void;\n\n /**\n * 여러 섹션 한번에 설정\n */\n setSections: (sections: Record<string, SectionData>) => void;\n\n /**\n * 섹션 비동기 로드\n */\n loadSection: (section: string, locale?: string) => Promise<void>;\n\n /**\n * 라벨 업데이트 (Draft Mode용)\n */\n updateLabel: (section: string, key: string, value: any) => void;\n\n /**\n * 초기화\n */\n reset: () => void;\n}\n\nexport const useCmsStore = create<CmsState>((set, get) => ({\n sections: {},\n loading: {},\n\n setSection: (section, data) =>\n {\n set((state) => ({\n sections: {\n ...state.sections,\n [section]: data,\n },\n }));\n },\n\n setSections: (sections) =>\n {\n set((state) => ({\n sections: {\n ...state.sections,\n ...sections,\n },\n }));\n },\n\n loadSection: async (section, locale = 'ko') =>\n {\n const state = get();\n\n // 이미 로드 중이면 스킵\n if (state.loading[section])\n {\n return;\n }\n\n // 이미 로드되어 있으면 스킵\n if (state.sections[section])\n {\n return;\n }\n\n set((state) => ({\n loading: { ...state.loading, [section]: true },\n }));\n\n try\n {\n const response = await cmsApi.getPublishedCache({\n query: { sections: section, locale },\n });\n\n // Check for error response\n if ('error' in response)\n {\n console.error(`Failed to load section ${section}:`, response.error);\n return;\n }\n\n // Response is array, get first element\n const data = response[0];\n\n if (!data)\n {\n console.warn(`Section ${section} not found`);\n return;\n }\n\n const sectionData: SectionData = {\n section: data.section,\n locale: data.locale,\n content: (data.content as Record<string, any>) || {},\n version: data.version || 0,\n publishedAt: data.publishedAt || null,\n };\n\n set((state) => ({\n sections: {\n ...state.sections,\n [section]: sectionData,\n },\n loading: { ...state.loading, [section]: false },\n }));\n }\n catch (error)\n {\n console.error(`Error loading CMS section ${section}:`, error);\n set((state) => ({\n loading: { ...state.loading, [section]: false },\n }));\n }\n },\n\n updateLabel: (section, key, value) =>\n {\n set((state) => ({\n sections: {\n ...state.sections,\n [section]: {\n ...state.sections[section],\n content: {\n ...state.sections[section]?.content,\n [`${section}.${key}`]: value,\n },\n },\n },\n }));\n },\n\n reset: () =>\n {\n set({\n sections: {},\n loading: {},\n });\n },\n}));","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T05:36:08.366Z\n */\n\nexport { client } from '@spfn/core/client';\n\nexport type { GetLabelsResponse, GetLabelsQuery, CreateLabelResponse, CreateLabelBody, GetLabelResponse, GetLabelParams, UpdateLabelResponse, UpdateLabelParams, UpdateLabelBody, DeleteLabelResponse, DeleteLabelParams } from './cms-labels.js';\nexport type { GetLabelByKeyResponse, GetLabelByKeyParams } from './cms-labels-by-key.js';\nexport type { PublishLabelResponse, PublishLabelParams, PublishLabelBody } from './cms-labels-publish.js';\nexport type { GetAdminLabelResponse, GetAdminLabelParams } from './cms-labels-admin.js';\nexport type { GetPublishedCacheResponse, GetPublishedCacheQuery, UpsertPublishedCacheResponse, UpsertPublishedCacheBody } from './cms-published-cache.js';\nexport type { SaveValuesResponse, SaveValuesParams, SaveValuesBody, GetValuesResponse, GetValuesQuery, GetValuesParams } from './cms-values.js';\n\nimport { getLabels, createLabel, getLabel, updateLabel, deleteLabel } from './cms-labels.js';\nimport { getLabelByKey } from './cms-labels-by-key.js';\nimport { publishLabel } from './cms-labels-publish.js';\nimport { getAdminLabel } from './cms-labels-admin.js';\nimport { getPublishedCache, upsertPublishedCache } from './cms-published-cache.js';\nimport { saveValues, getValues } from './cms-values.js';\n\n/**\n * Type-safe API client\n */\nexport const cmsApi = {\n getLabels,\n createLabel,\n getLabel,\n updateLabel,\n deleteLabel,\n getLabelByKey,\n publishLabel,\n getAdminLabel,\n getPublishedCache,\n upsertPublishedCache,\n saveValues,\n getValues\n} as const;\n","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T05:36:08.363Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { getLabelsContract, createLabelContract, getLabelContract, updateLabelContract, deleteLabelContract } from '@/lib/contracts/labels';\n\n// ============================================\n// Types\n// ============================================\n\nexport type GetLabelsResponse = InferContract<typeof getLabelsContract>['response'];\nexport type GetLabelsQuery = InferContract<typeof getLabelsContract>['query'];\n\nexport type CreateLabelResponse = InferContract<typeof createLabelContract>['response'];\nexport type CreateLabelBody = InferContract<typeof createLabelContract>['body'];\n\nexport type GetLabelResponse = InferContract<typeof getLabelContract>['response'];\nexport type GetLabelParams = InferContract<typeof getLabelContract>['params'];\n\nexport type UpdateLabelResponse = InferContract<typeof updateLabelContract>['response'];\nexport type UpdateLabelParams = InferContract<typeof updateLabelContract>['params'];\nexport type UpdateLabelBody = InferContract<typeof updateLabelContract>['body'];\n\nexport type DeleteLabelResponse = InferContract<typeof deleteLabelContract>['response'];\nexport type DeleteLabelParams = InferContract<typeof deleteLabelContract>['params'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * GET /_cms/labels\n */\nexport const getLabels = (options: { query?: GetLabelsQuery }) => client.call(getLabelsContract, options);\n\n/**\n * POST /_cms/labels\n */\nexport const createLabel = (options: { body: CreateLabelBody }) => client.call(createLabelContract, options);\n\n/**\n * GET /_cms/labels/:id\n */\nexport const getLabel = (options: { params: GetLabelParams }) => client.call(getLabelContract, options);\n\n/**\n * PATCH /_cms/labels/:id\n */\nexport const updateLabel = (options: { params: UpdateLabelParams, body: UpdateLabelBody }) => client.call(updateLabelContract, options);\n\n/**\n * DELETE /_cms/labels/:id\n */\nexport const deleteLabel = (options: { params: DeleteLabelParams }) => client.call(deleteLabelContract, options);\n\n","import { Type } from '@sinclair/typebox';\nimport type { RouteContract } from '@spfn/core/route';\n\n/**\n * CMS Labels Contracts\n *\n * 라벨 메타데이터 관리 API\n */\n\n/**\n * GET /_cms/labels - 라벨 목록 조회\n */\nexport const getLabelsContract = {\n method: 'GET' as const,\n path: '/_cms/labels',\n query: Type.Object({\n section: Type.Optional(Type.String({ description: '섹션으로 필터링 (예: home, why-futureplay)' })),\n limit: Type.Optional(Type.Number({ minimum: 1, maximum: 100, default: 20, description: '페이지당 항목 수' })),\n offset: Type.Optional(Type.Number({ minimum: 0, default: 0, description: '시작 오프셋' })),\n includeDefaultValues: Type.Optional(Type.Boolean({ description: '기본값 포함 여부', default: false }))\n }),\n response: Type.Object({\n labels: Type.Array(Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String(),\n defaultValue: Type.Optional(Type.Any({ description: '라벨 정의 파일의 기본값' }))\n })),\n total: Type.Number(),\n limit: Type.Number(),\n offset: Type.Number()\n })\n} as const satisfies RouteContract;\n\n/**\n * POST /_cms/labels - 새 라벨 생성\n */\nexport const createLabelContract = {\n method: 'POST' as const,\n path: '/_cms/labels',\n body: Type.Object({\n key: Type.String({\n description: '고유 키 (예: home.hero.title)',\n pattern: '^[a-z0-9-]+\\\\.[a-z0-9-]+\\\\.[a-z0-9-]+$'\n }),\n section: Type.String({\n description: '섹션 이름 (예: home, why-futureplay)',\n pattern: '^[a-z0-9-]+$'\n }),\n type: Type.Union([\n Type.Literal('text'),\n Type.Literal('image'),\n Type.Literal('video'),\n Type.Literal('file'),\n Type.Literal('object')\n ], { description: '값 타입' }),\n createdBy: Type.Optional(Type.String({ description: '생성자 ID' }))\n }),\n response: Type.Union([\n Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n Type.Object({\n error: Type.String(),\n key: Type.Optional(Type.String())\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * GET /_cms/labels/:id - 라벨 단건 조회\n */\nexport const getLabelContract = {\n method: 'GET' as const,\n path: '/_cms/labels/:id',\n params: Type.Object({\n id: Type.String({ description: '라벨 ID' })\n }),\n response: Type.Union([\n Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * PATCH /_cms/labels/:id - 라벨 메타데이터 수정\n */\nexport const updateLabelContract = {\n method: 'PATCH' as const,\n path: '/_cms/labels/:id',\n params: Type.Object({\n id: Type.String({ description: '라벨 ID' })\n }),\n body: Type.Object({\n section: Type.Optional(Type.String({ description: '섹션 변경' })),\n type: Type.Optional(Type.Union([\n Type.Literal('text'),\n Type.Literal('image'),\n Type.Literal('video'),\n Type.Literal('file'),\n Type.Literal('object')\n ]))\n }),\n response: Type.Union([\n Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * DELETE /_cms/labels/:id - 라벨 삭제\n */\nexport const deleteLabelContract = {\n method: 'DELETE' as const,\n path: '/_cms/labels/:id',\n params: Type.Object({\n id: Type.String({ description: '라벨 ID' })\n }),\n response: Type.Union([\n Type.Object({\n success: Type.Boolean(),\n id: Type.Number()\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * GET /_cms/labels/by-key/:key - Key로 라벨 조회\n */\nexport const getLabelByKeyContract = {\n method: 'GET' as const,\n path: '/_cms/labels/by-key/:key',\n params: Type.Object({\n key: Type.String({ description: '라벨 Key (예: home.hero.title)' })\n }),\n response: Type.Union([\n Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n Type.Object({\n error: Type.String(),\n key: Type.Optional(Type.String())\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * POST /_cms/labels/:labelId/publish - 라벨 발행 (Draft → Published)\n */\nexport const publishLabelContract = {\n method: 'POST' as const,\n path: '/_cms/labels/:labelId/publish',\n params: Type.Object({\n labelId: Type.String({ description: '라벨 ID' })\n }),\n body: Type.Object({\n notes: Type.Optional(Type.String({ description: '발행 노트 (버전 설명)' })),\n publishedBy: Type.Optional(Type.String({ description: '발행자 ID' }))\n }),\n response: Type.Union([\n Type.Object({\n success: Type.Boolean(),\n labelId: Type.Number(),\n version: Type.Number(),\n message: Type.String()\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * GET /_cms/labels/:labelId/admin - 관리자용 라벨 조회 (Draft + Published + Status)\n */\nexport const getAdminLabelContract = {\n method: 'GET' as const,\n path: '/_cms/labels/:labelId/admin',\n params: Type.Object({\n labelId: Type.String({ description: '라벨 ID' })\n }),\n response: Type.Union([\n Type.Object({\n label: Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n draft: Type.Array(Type.Object({\n id: Type.Number(),\n labelId: Type.Number(),\n version: Type.Null(),\n locale: Type.String(),\n breakpoint: Type.Union([Type.String(), Type.Null()]),\n value: Type.Any(),\n createdAt: Type.String()\n })),\n published: Type.Array(Type.Object({\n id: Type.Number(),\n labelId: Type.Number(),\n version: Type.Number(),\n locale: Type.String(),\n breakpoint: Type.Union([Type.String(), Type.Null()]),\n value: Type.Any(),\n createdAt: Type.String()\n })),\n status: Type.Union([\n Type.Literal('default-only'),\n Type.Literal('unpublished'),\n Type.Literal('published'),\n Type.Literal('modified')\n ])\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T05:36:08.364Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { getLabelByKeyContract } from '@/lib/contracts/labels';\n\n// ============================================\n// Types\n// ============================================\n\nexport type GetLabelByKeyResponse = InferContract<typeof getLabelByKeyContract>['response'];\nexport type GetLabelByKeyParams = InferContract<typeof getLabelByKeyContract>['params'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * GET /_cms/labels/by-key/:key\n */\nexport const getLabelByKey = (options: { params: GetLabelByKeyParams }) => client.call(getLabelByKeyContract, options);\n\n","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T05:36:08.364Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { publishLabelContract } from '@/lib/contracts/labels';\n\n// ============================================\n// Types\n// ============================================\n\nexport type PublishLabelResponse = InferContract<typeof publishLabelContract>['response'];\nexport type PublishLabelParams = InferContract<typeof publishLabelContract>['params'];\nexport type PublishLabelBody = InferContract<typeof publishLabelContract>['body'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * POST /_cms/labels/:labelId/publish\n */\nexport const publishLabel = (options: { params: PublishLabelParams, body: PublishLabelBody }) => client.call(publishLabelContract, options);\n\n","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T05:36:08.365Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { getAdminLabelContract } from '@/lib/contracts/labels';\n\n// ============================================\n// Types\n// ============================================\n\nexport type GetAdminLabelResponse = InferContract<typeof getAdminLabelContract>['response'];\nexport type GetAdminLabelParams = InferContract<typeof getAdminLabelContract>['params'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * GET /_cms/labels/:labelId/admin\n */\nexport const getAdminLabel = (options: { params: GetAdminLabelParams }) => client.call(getAdminLabelContract, options);\n\n","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T05:36:08.365Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { getPublishedCacheContract, upsertPublishedCacheContract } from '@/lib/contracts/published-cache';\n\n// ============================================\n// Types\n// ============================================\n\nexport type GetPublishedCacheResponse = InferContract<typeof getPublishedCacheContract>['response'];\nexport type GetPublishedCacheQuery = InferContract<typeof getPublishedCacheContract>['query'];\n\nexport type UpsertPublishedCacheResponse = InferContract<typeof upsertPublishedCacheContract>['response'];\nexport type UpsertPublishedCacheBody = InferContract<typeof upsertPublishedCacheContract>['body'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * GET /_cms/published-cache\n */\nexport const getPublishedCache = (options: { query?: GetPublishedCacheQuery }) => client.call(getPublishedCacheContract, options);\n\n/**\n * POST /_cms/published-cache\n */\nexport const upsertPublishedCache = (options: { body: UpsertPublishedCacheBody }) => client.call(upsertPublishedCacheContract, options);\n\n","import { Type } from '@sinclair/typebox';\nimport type { RouteContract } from '@spfn/core/route';\n\nconst SectionData = Type.Object({\n section: Type.String(),\n locale: Type.String(),\n content: Type.Record(Type.String(), Type.Any()),\n version: Type.Number(),\n publishedAt: Type.Union([Type.String(), Type.Null()]),\n});\n\n/**\n * GET /_cms/published-cache\n * 발행된 콘텐츠 캐시 조회 (단일 또는 여러 섹션)\n */\nexport const getPublishedCacheContract = {\n method: 'GET' as const,\n path: '/_cms/published-cache',\n query: Type.Object({\n sections: Type.Union([\n Type.String({ description: '단일 섹션 이름 (예: home)' }),\n Type.Array(Type.String(), { description: '여러 섹션 이름 (예: [\"home\", \"footer\"])' })\n ]),\n locale: Type.Optional(Type.String({ default: 'ko', description: '언어 코드' })),\n }),\n response: Type.Union([\n // 성공: 항상 배열로 반환\n Type.Array(SectionData),\n // 에러\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * POST /_cms/published-cache\n * 발행된 콘텐츠 캐시 업데이트/생성 (upsert)\n */\nexport const upsertPublishedCacheContract = {\n method: 'POST' as const,\n path: '/_cms/published-cache',\n body: Type.Object({\n section: Type.String({ description: '섹션 이름 (예: home)' }),\n locale: Type.String({ description: '언어 코드 (예: ko, en, ja)' }),\n content: Type.Record(Type.String(), Type.Any(), { description: '발행할 콘텐츠 (key-value 형태)' }),\n version: Type.Number({ description: '버전 번호' })\n }),\n response: Type.Union([\n SectionData,\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T05:36:08.366Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { saveValuesContract, getValuesContract } from '@/lib/contracts/values';\n\n// ============================================\n// Types\n// ============================================\n\nexport type SaveValuesResponse = InferContract<typeof saveValuesContract>['response'];\nexport type SaveValuesParams = InferContract<typeof saveValuesContract>['params'];\nexport type SaveValuesBody = InferContract<typeof saveValuesContract>['body'];\n\nexport type GetValuesResponse = InferContract<typeof getValuesContract>['response'];\nexport type GetValuesQuery = InferContract<typeof getValuesContract>['query'];\nexport type GetValuesParams = InferContract<typeof getValuesContract>['params'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * POST /_cms/values/:labelId\n */\nexport const saveValues = (options: { params: SaveValuesParams, body: SaveValuesBody }) => client.call(saveValuesContract, options);\n\n/**\n * GET /_cms/values/:labelId/:version\n */\nexport const getValues = (options: { params: GetValuesParams, query?: GetValuesQuery }) => client.call(getValuesContract, options);\n\n","import { Type } from '@sinclair/typebox';\nimport type { RouteContract } from '@spfn/core/route';\n\n/**\n * Label Value 타입 정의\n */\nconst LabelValueSchema = Type.Object({\n type: Type.Union([\n Type.Literal('text'),\n Type.Literal('image'),\n Type.Literal('video'),\n Type.Literal('file'),\n Type.Literal('object')\n ]),\n content: Type.Optional(Type.String()), // text type\n url: Type.Optional(Type.String()), // image, video, file types\n alt: Type.Optional(Type.String()), // image type\n width: Type.Optional(Type.Number()), // image type\n height: Type.Optional(Type.Number()), // image type\n thumbnail: Type.Optional(Type.String()), // video type\n duration: Type.Optional(Type.Number()), // video type\n filename: Type.Optional(Type.String()), // file type\n size: Type.Optional(Type.Number()), // file type\n fields: Type.Optional(Type.Any()) // object type - recursive structure\n});\n\n/**\n * POST /_cms/values/:labelId - 라벨 값 저장\n * - version: null → Draft 저장 (덮어쓰기)\n * - version: number → Published 버전 생성 (불변)\n */\nexport const saveValuesContract = {\n method: 'POST' as const,\n path: '/_cms/values/:labelId',\n params: Type.Object({\n labelId: Type.String({ description: '라벨 ID' })\n }),\n body: Type.Object({\n version: Type.Union([\n Type.Null({ description: 'Draft 저장 (덮어쓰기)' }),\n Type.Number({ description: '버전 번호 (불변)', minimum: 1 })\n ]),\n values: Type.Array(\n Type.Object({\n locale: Type.String({ description: '언어 코드 (ko, en, ja)', default: 'ko' }),\n breakpoint: Type.Optional(Type.Union([\n Type.Literal('sm'),\n Type.Literal('md'),\n Type.Literal('lg'),\n Type.Literal('xl'),\n Type.Literal('2xl'),\n Type.Null()\n ], { description: '반응형 브레이크포인트' })),\n value: LabelValueSchema\n })\n )\n }),\n response: Type.Union([\n Type.Object({\n success: Type.Boolean(),\n saved: Type.Number(),\n version: Type.Union([Type.Null(), Type.Number()])\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * GET /_cms/values/:labelId/:version - 특정 버전의 값 조회\n */\nexport const getValuesContract = {\n method: 'GET' as const,\n path: '/_cms/values/:labelId/:version',\n params: Type.Object({\n labelId: Type.String({ description: '라벨 ID' }),\n version: Type.String({ description: '버전 번호' })\n }),\n query: Type.Object({\n locale: Type.Optional(Type.String({ description: '언어 코드 (ko, en, ja)' })),\n breakpoint: Type.Optional(Type.String({ description: '반응형 브레이크포인트' }))\n }),\n response: Type.Union([\n Type.Object({\n labelId: Type.Number(),\n version: Type.Number(),\n values: Type.Array(\n Type.Object({\n id: Type.Number(),\n locale: Type.String(),\n breakpoint: Type.Union([Type.String(), Type.Null()]),\n value: Type.Any(),\n createdAt: Type.String()\n })\n )\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;","/**\n * useSections Hook\n *\n * 여러 섹션을 한번에 사용\n */\n\n'use client';\n\nimport { useCmsStore } from '../store/cms.store';\nimport type { useSection } from './useSection';\n\n/**\n * 변수 치환 헬퍼 (서버와 동일)\n */\nfunction replaceVariables(text: string, replace: Record<string, string | number>): string\n{\n return text.replace(/\\{(\\w+)}/g, (match, key) =>\n {\n const value = replace[key];\n return value !== undefined ? String(value) : match;\n });\n}\n\n/**\n * 여러 섹션 Hook\n *\n * @param sectionNames - 섹션 이름 배열\n * @returns { [section]: { t, data, loading }, ... }\n *\n * @example\n * ```tsx\n * 'use client';\n * import { useSections } from '@spfn/cms/client';\n *\n * export function Component()\n * {\n * const sections = useSections(['home', 'layout']);\n * return (\n * <div>\n * <h1>{sections.home.t('hero.title')}</h1>\n * <p>{sections.layout.t('footer.copyright')}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useSections(sectionNames: string[])\n{\n const allSections = useCmsStore((state) => state.sections);\n const allLoading = useCmsStore((state) => state.loading);\n\n const result: Record<string, ReturnType<typeof useSection>> = {};\n\n sectionNames.forEach((section) =>\n {\n const sectionData = allSections[section];\n const loading = allLoading[section] ?? false;\n\n const t = (key: string, defaultValue?: any, replace?: Record<string, string | number>) =>\n {\n if (!sectionData)\n {\n return defaultValue;\n }\n\n const fullKey = `${section}.${key}`;\n let value = sectionData.content[fullKey];\n\n if (value === undefined)\n {\n value = defaultValue;\n }\n\n if (typeof value === 'string' && replace)\n {\n value = replaceVariables(value, replace);\n }\n\n return value;\n };\n\n result[section] = {\n t,\n data: sectionData,\n loading,\n };\n });\n\n return result;\n}","/**\n * CMS Store Initializer\n *\n * 서버 컴포넌트에서 로드한 섹션 데이터를 클라이언트 store에 초기화\n */\n\n'use client';\n\nimport { useEffect } from 'react';\nimport { useCmsStore } from '@/client/store/cms.store';\nimport type { SectionAPI } from '@/server';\n\ninterface InitCmsProps\n{\n /**\n * 서버에서 로드한 섹션 데이터\n * { home: { t, data }, ... }\n */\n sections: Record<string, SectionAPI>;\n}\n\n/**\n * CMS Store 초기화 컴포넌트\n *\n * 서버 컴포넌트에서 로드한 데이터를 클라이언트 store에 주입\n * 이후 하위 클라이언트 컴포넌트에서 useSection() 사용 가능\n *\n * @param props - InitCmsProps\n * @param props.sections - 서버에서 로드한 섹션 데이터\n *\n * @example\n * // Server Component\n * const home = await getSection('home');\n * <InitCms sections={{ home }} />\n * // 이후 하위 클라이언트 컴포넌트에서 useSection('home') 사용 가능\n */\nexport function InitCms({ sections }: InitCmsProps)\n{\n const setSections = useCmsStore((state) => state.setSections);\n\n useEffect(() =>\n {\n // SectionAPI → SectionData 변환\n const sectionsData: Record<string, any> = {};\n Object.entries(sections).forEach(([key, { data }]) =>\n {\n sectionsData[key] = data;\n });\n\n setSections(sectionsData);\n }, [sections, setSections]);\n\n return null;\n}","\"use server\";\n\n/**\n * Locale Management Server Actions\n *\n * Server Actions으로 구현된 locale 관리 함수\n * - 서버 컴포넌트: 일반 함수 호출로 동작\n * - 클라이언트 컴포넌트: Server Action으로 자동 처리\n */\n\nimport { cookies, headers } from 'next/headers.js';\nimport { getCmsConfig } from '@/server/config/cms.config';\nimport {\n LOCALE_COOKIE_KEY,\n getLocaleInfo,\n type LocaleInfo,\n} from '@/lib/constants/locale.constants';\n\n/**\n * 브라우저 언어 감지\n *\n * Accept-Language 헤더에서 지원하는 언어를 찾습니다.\n *\n * @returns 감지된 언어 코드 또는 null\n */\nasync function detectBrowserLanguage(): Promise<string | null>\n{\n try\n {\n const headersList = await headers();\n const acceptLanguage = headersList.get('accept-language');\n\n if (!acceptLanguage)\n {\n return null;\n }\n\n // \"ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7\" 형식 파싱\n const languages = acceptLanguage\n .split(',')\n .map(lang =>\n {\n const [code] = lang.split(';');\n return code.split('-')[0].trim();\n });\n\n const config = getCmsConfig();\n\n // 지원하는 언어 중 첫 번째 매칭되는 언어 반환\n for (const lang of languages)\n {\n if (config.supportedLocales.includes(lang))\n {\n return lang;\n }\n }\n\n return null;\n }\n catch (error)\n {\n // 헤더 접근 실패 시\n return null;\n }\n}\n\n/**\n * 현재 locale 가져오기 (Server Action)\n *\n * 서버/클라이언트 컴포넌트 모두에서 사용 가능\n *\n * 우선순위:\n * 1. 쿠키 (사용자가 명시적으로 선택한 언어)\n * 2. 브라우저 언어 감지 (설정에서 활성화된 경우)\n * 3. 시스템 기본 언어 (CMS 설정)\n *\n * @returns 현재 locale (예: 'ko', 'en')\n *\n * @example\n * ```tsx\n * // Server Component\n * import { getLocale } from '@spfn/cms/actions';\n *\n * export default async function Page()\n * {\n * const locale = await getLocale();\n * return <div>Current locale: {locale}</div>;\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Client Component\n * 'use client';\n * import { getLocale } from '@spfn/cms/client';\n *\n * export default function LanguageSwitcher()\n * {\n * const [locale, setLocale] = useState('');\n *\n * useEffect(() => {\n * getLocale().then(setLocale);\n * }, []);\n *\n * return <div>Current locale: {locale}</div>;\n * }\n * ```\n */\nexport async function getLocale(): Promise<string>\n{\n const config = getCmsConfig();\n\n // 1순위: 쿠키 (사용자가 명시적으로 선택한 언어)\n const cookieStore = await cookies();\n const cookieLocale = cookieStore.get(LOCALE_COOKIE_KEY)?.value;\n\n if (cookieLocale && config.supportedLocales.includes(cookieLocale))\n {\n return cookieLocale;\n }\n\n // 2순위: 브라우저 언어 감지 (설정에서 활성화된 경우)\n if (config.detectBrowserLanguage)\n {\n const browserLang = await detectBrowserLanguage();\n if (browserLang)\n {\n return browserLang;\n }\n }\n\n // 3순위: 시스템 기본 언어\n return config.defaultLocale;\n}\n\n/**\n * Locale 설정하기 (Server Action)\n *\n * 서버/클라이언트 컴포넌트 모두에서 사용 가능\n * 쿠키에 locale을 저장합니다.\n *\n * @param locale - 설정할 locale (예: 'ko', 'en')\n * @throws {Error} 지원하지 않는 locale인 경우\n *\n * @example\n * ```tsx\n * // Server Component (Server Action)\n * import { setLocale } from '@spfn/cms/actions';\n *\n * export default async function Page()\n * {\n * await setLocale('en');\n * return <div>Locale changed</div>;\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Client Component (Server Action)\n * 'use client';\n * import { setLocale } from '@spfn/cms/client';\n *\n * export default function LanguageSwitcher()\n * {\n * const handleChange = async (newLocale: string) =>\n * {\n * await setLocale(newLocale);\n * window.location.reload(); // 페이지 새로고침\n * };\n *\n * return (\n * <button onClick={() => handleChange('en')}>\n * Switch to English\n * </button>\n * );\n * }\n * ```\n */\nexport async function setLocale(locale: string): Promise<void>\n{\n const config = getCmsConfig();\n\n // 유효성 검사\n if (!config.supportedLocales.includes(locale))\n {\n throw new Error(\n `Unsupported locale: ${locale}. Supported locales: ${config.supportedLocales.join(', ')}`\n );\n }\n\n const cookieStore = await cookies();\n\n cookieStore.set(LOCALE_COOKIE_KEY, locale, {\n path: '/',\n maxAge: 60 * 60 * 24 * 365, // 1년\n sameSite: 'lax',\n });\n}\n\n/**\n * 지원하는 locale 목록 가져오기 (Server Action)\n *\n * 서버/클라이언트 컴포넌트 모두에서 사용 가능\n *\n * @returns 지원하는 locale 배열 (예: ['ko', 'en', 'ja'])\n *\n * @example\n * ```tsx\n * // Server Component\n * import { getLocales } from '@spfn/cms/actions';\n *\n * export default async function Page()\n * {\n * const locales = await getLocales();\n * return <div>Supported: {locales.join(', ')}</div>;\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Client Component\n * 'use client';\n * import { getLocales } from '@spfn/cms/client';\n *\n * export default function LanguageSwitcher()\n * {\n * const [locales, setLocales] = useState<string[]>([]);\n *\n * useEffect(() => {\n * getLocales().then(setLocales);\n * }, []);\n *\n * return (\n * <div>\n * {locales.map(locale => (\n * <button key={locale}>{locale}</button>\n * ))}\n * </div>\n * );\n * }\n * ```\n */\nexport async function getLocales(): Promise<string[]>\n{\n const config = getCmsConfig();\n return config.supportedLocales;\n}\n\n/**\n * 현재 locale과 상세 정보 함께 가져오기 (Server Action)\n *\n * locale 코드와 함께 국가 코드, 국기, 전화번호 코드 등의 상세 정보를 반환합니다.\n *\n * @returns Locale 코드와 LocaleInfo 객체\n *\n * @example\n * ```tsx\n * // Server Component\n * import { getLocaleWithInfo } from '@spfn/cms/actions';\n *\n * export default async function Page()\n * {\n * const { locale, info } = await getLocaleWithInfo();\n *\n * return (\n * <div>\n * <span>{info?.flag}</span>\n * <span>{info?.nativeName}</span>\n * <span>{info?.dialCode}</span>\n * </div>\n * );\n * }\n * ```\n */\nexport async function getLocaleWithInfo(): Promise<{\n locale: string;\n info: LocaleInfo | undefined;\n}>\n{\n const locale = await getLocale();\n const info = getLocaleInfo(locale);\n\n return { locale, info };\n}\n\n/**\n * 지원하는 모든 locale과 상세 정보 가져오기 (Server Action)\n *\n * 시스템이 지원하는 모든 locale의 상세 정보를 배열로 반환합니다.\n * 언어 선택 UI를 만들 때 유용합니다.\n *\n * @returns LocaleInfo 배열\n *\n * @example\n * ```tsx\n * // Server Component\n * import { getLocalesWithInfo } from '@spfn/cms/actions';\n *\n * export default async function LanguageSelector()\n * {\n * const locales = await getLocalesWithInfo();\n *\n * return (\n * <select>\n * {locales.map(info => (\n * <option key={info.locale} value={info.locale}>\n * {info.flag} {info.nativeName}\n * </option>\n * ))}\n * </select>\n * );\n * }\n * ```\n */\nexport async function getLocalesWithInfo(): Promise<LocaleInfo[]>\n{\n const config = getCmsConfig();\n const supportedLocales = config.supportedLocales;\n\n return supportedLocales\n .map(locale => getLocaleInfo(locale))\n .filter((info): info is LocaleInfo => info !== undefined);\n}","/**\n * CMS Configuration Module\n *\n * 환경변수 기반 CMS 설정 관리\n * - SPFN_CMS_DEFAULT_LOCALE: 기본 언어 (기본값: 'ko')\n * - SPFN_CMS_SUPPORTED_LOCALES: 지원 언어 목록, 쉼표로 구분 (기본값: 'ko,en')\n * - SPFN_CMS_DETECT_BROWSER_LANGUAGE: 브라우저 언어 자동 감지 (기본값: 'false')\n */\n\n/**\n * CMS 설정 타입\n */\nexport interface CmsConfig\n{\n /**\n * 기본 언어 코드\n * @example 'ko', 'en', 'ja'\n */\n defaultLocale: string;\n\n /**\n * 지원하는 언어 목록\n * @example ['ko', 'en', 'ja']\n */\n supportedLocales: string[];\n\n /**\n * 브라우저 언어 자동 감지 여부\n * @default true\n */\n detectBrowserLanguage: boolean;\n}\n\n/**\n * 환경변수 읽기 헬퍼\n */\nfunction getEnvVar(key: string, defaultValue: string): string\n{\n return process.env[key] || defaultValue;\n}\n\n/**\n * 환경변수에서 boolean 읽기\n */\nfunction getEnvBoolean(key: string, defaultValue: boolean): boolean\n{\n const value = process.env[key];\n if (value === undefined) return defaultValue;\n return value === 'true' || value === '1';\n}\n\n/**\n * 환경변수에서 설정 로드\n */\nfunction loadConfigFromEnv(): CmsConfig\n{\n const defaultLocale = getEnvVar('SPFN_CMS_DEFAULT_LOCALE', 'en');\n const supportedLocalesStr = getEnvVar('SPFN_CMS_SUPPORTED_LOCALES', 'en,ko');\n const detectBrowserLanguage = getEnvBoolean('SPFN_CMS_DETECT_BROWSER_LANGUAGE', true);\n\n const supportedLocales = supportedLocalesStr\n .split(',')\n .map(locale => locale.trim())\n .filter(locale => locale.length > 0);\n\n // 기본 언어가 지원 목록에 없으면 추가\n if (!supportedLocales.includes(defaultLocale))\n {\n supportedLocales.unshift(defaultLocale);\n }\n\n return {\n defaultLocale,\n supportedLocales,\n detectBrowserLanguage,\n };\n}\n\n/**\n * 현재 설정 (환경변수에서 초기화)\n */\nlet currentConfig: CmsConfig = loadConfigFromEnv();\n\n/**\n * CMS 설정 조회\n *\n * @returns 현재 CMS 설정\n *\n * @example\n * ```tsx\n * import { getCmsConfig } from '@spfn/cms';\n *\n * const config = getCmsConfig();\n * console.log(config.defaultLocale); // 'ko'\n * console.log(config.supportedLocales); // ['ko', 'en']\n * ```\n */\nexport function getCmsConfig(): Readonly<CmsConfig>\n{\n return currentConfig;\n}\n\n/**\n * CMS 설정 변경 (런타임 오버라이드)\n *\n * 환경변수 설정을 런타임에 오버라이드합니다.\n * 주로 테스트나 특수한 경우에 사용됩니다.\n *\n * @param config - 변경할 설정 (부분 업데이트 가능)\n *\n * @example\n * ```tsx\n * import { configureCms } from '@spfn/cms';\n *\n * // 앱 초기화 시 (선택적)\n * configureCms({\n * defaultLocale: 'en',\n * supportedLocales: ['en', 'ko', 'ja'],\n * detectBrowserLanguage: true,\n * });\n * ```\n */\nexport function configureCms(config: Partial<CmsConfig>): void\n{\n currentConfig = {\n ...currentConfig,\n ...config,\n };\n\n // 기본 언어가 지원 목록에 있는지 확인\n if (config.defaultLocale && !currentConfig.supportedLocales.includes(config.defaultLocale))\n {\n console.warn(\n `[CMS Config] Default locale '${config.defaultLocale}' not in supported locales, adding automatically.`,\n `Supported locales: [${currentConfig.supportedLocales.join(', ')}]`\n );\n\n currentConfig.supportedLocales.unshift(config.defaultLocale);\n }\n}\n\n/**\n * 설정 초기화 (환경변수에서 재로드)\n *\n * @example\n * ```tsx\n * import { resetCmsConfig } from '@spfn/cms';\n *\n * // 환경변수 설정으로 되돌리기\n * resetCmsConfig();\n * ```\n */\nexport function resetCmsConfig(): void\n{\n currentConfig = loadConfigFromEnv();\n}","/**\n * Locale Constants\n *\n * Server/Client 양쪽에서 사용 가능한 locale 관련 상수\n */\n\n/**\n * Locale 쿠키 키\n */\nexport const LOCALE_COOKIE_KEY = 'spfn-locale';\n\n/**\n * 지원하는 Locale 타입 (Type-safe)\n */\nexport type SupportedLocale =\n // 아시아-태평양\n | 'ko' // 한국어\n | 'ja' // 일본어\n | 'zh' // 중국어 (간체)\n | 'zh-TW' // 중국어 (번체, 대만)\n | 'zh-HK' // 중국어 (홍콩)\n | 'hi' // 힌디어\n | 'th' // 태국어\n | 'vi' // 베트남어\n | 'id' // 인도네시아어\n | 'ms' // 말레이어\n // 영어권\n | 'en' // 영어 (미국)\n | 'en-GB' // 영어 (영국)\n | 'en-CA' // 영어 (캐나다)\n | 'en-AU' // 영어 (호주)\n | 'en-NZ' // 영어 (뉴질랜드)\n // 서유럽\n | 'es' // 스페인어 (스페인)\n | 'es-MX' // 스페인어 (멕시코)\n | 'es-AR' // 스페인어 (아르헨티나)\n | 'es-CO' // 스페인어 (콜롬비아)\n | 'fr' // 프랑스어\n | 'de' // 독일어\n | 'it' // 이탈리아어\n | 'pt' // 포르투갈어\n | 'nl' // 네덜란드어\n // 북유럽\n | 'sv' // 스웨덴어\n | 'no' // 노르웨이어\n | 'da' // 덴마크어\n | 'fi' // 핀란드어\n // 동유럽\n | 'ru' // 러시아어\n | 'pl' // 폴란드어\n | 'uk' // 우크라이나어\n | 'cs' // 체코어\n | 'hu' // 헝가리어\n | 'ro' // 루마니아어\n | 'bg' // 불가리아어\n | 'hr' // 크로아티아어\n | 'sr' // 세르비아어\n | 'sk' // 슬로바키아어\n | 'sl' // 슬로베니아어\n | 'lt' // 리투아니아어\n | 'lv' // 라트비아어\n | 'et' // 에스토니아어\n // 남유럽\n | 'el' // 그리스어\n // 중동\n | 'tr' // 터키어\n | 'ar' // 아랍어\n | 'fa' // 페르시아어\n | 'he' // 히브리어\n // 아프리카\n | 'sw'; // 스와힐리어\n\n/**\n * 국가/지역 정보 타입\n */\nexport interface LocaleInfo\n{\n /** Locale 코드 (ISO 639-1) */\n locale: SupportedLocale;\n /** 국가 코드 (ISO 3166-1 alpha-2) */\n countryCode: string;\n /** 국기 이모지 (HTML/React용) */\n flag: string;\n /** 전화번호 국가 코드 */\n dialCode: string;\n /** 네이티브 이름 (현지어) */\n nativeName: string;\n /** 영어 이름 */\n englishName: string;\n /** RTL (Right-to-Left) 여부 */\n rtl?: boolean;\n /** 통화 코드 (ISO 4217) */\n currencyCode?: string;\n /** 날짜 형식 예시 */\n dateFormat?: string;\n}\n\n/**\n * 사전 정의된 Locale 정보 맵\n *\n * 주요 언어/국가 정보를 포함합니다.\n * 프로젝트에 맞게 추가/수정 가능합니다.\n */\nexport const LOCALE_INFO_MAP: Record<SupportedLocale, LocaleInfo> = {\n // 한국어\n ko: {\n locale: 'ko',\n countryCode: 'KR',\n flag: '🇰🇷',\n dialCode: '+82',\n nativeName: '한국어',\n englishName: 'Korean',\n currencyCode: 'KRW',\n dateFormat: 'YYYY.MM.DD',\n },\n\n // 영어 (미국)\n en: {\n locale: 'en',\n countryCode: 'US',\n flag: '🇺🇸',\n dialCode: '+1',\n nativeName: 'English',\n englishName: 'English',\n currencyCode: 'USD',\n dateFormat: 'MM/DD/YYYY',\n },\n\n // 일본어\n ja: {\n locale: 'ja',\n countryCode: 'JP',\n flag: '🇯🇵',\n dialCode: '+81',\n nativeName: '日本語',\n englishName: 'Japanese',\n currencyCode: 'JPY',\n dateFormat: 'YYYY/MM/DD',\n },\n\n // 중국어 (간체)\n zh: {\n locale: 'zh',\n countryCode: 'CN',\n flag: '🇨🇳',\n dialCode: '+86',\n nativeName: '简体中文',\n englishName: 'Chinese (Simplified)',\n currencyCode: 'CNY',\n dateFormat: 'YYYY-MM-DD',\n },\n\n // 중국어 (번체, 대만)\n 'zh-TW': {\n locale: 'zh-TW',\n countryCode: 'TW',\n flag: '🇹🇼',\n dialCode: '+886',\n nativeName: '繁體中文',\n englishName: 'Chinese (Traditional)',\n currencyCode: 'TWD',\n dateFormat: 'YYYY/MM/DD',\n },\n\n // 스페인어\n es: {\n locale: 'es',\n countryCode: 'ES',\n flag: '🇪🇸',\n dialCode: '+34',\n nativeName: 'Español',\n englishName: 'Spanish',\n currencyCode: 'EUR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 프랑스어\n fr: {\n locale: 'fr',\n countryCode: 'FR',\n flag: '🇫🇷',\n dialCode: '+33',\n nativeName: 'Français',\n englishName: 'French',\n currencyCode: 'EUR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 독일어\n de: {\n locale: 'de',\n countryCode: 'DE',\n flag: '🇩🇪',\n dialCode: '+49',\n nativeName: 'Deutsch',\n englishName: 'German',\n currencyCode: 'EUR',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 이탈리아어\n it: {\n locale: 'it',\n countryCode: 'IT',\n flag: '🇮🇹',\n dialCode: '+39',\n nativeName: 'Italiano',\n englishName: 'Italian',\n currencyCode: 'EUR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 포르투갈어 (브라질)\n pt: {\n locale: 'pt',\n countryCode: 'BR',\n flag: '🇧🇷',\n dialCode: '+55',\n nativeName: 'Português',\n englishName: 'Portuguese',\n currencyCode: 'BRL',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 러시아어\n ru: {\n locale: 'ru',\n countryCode: 'RU',\n flag: '🇷🇺',\n dialCode: '+7',\n nativeName: 'Русский',\n englishName: 'Russian',\n currencyCode: 'RUB',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 아랍어\n ar: {\n locale: 'ar',\n countryCode: 'SA',\n flag: '🇸🇦',\n dialCode: '+966',\n nativeName: 'العربية',\n englishName: 'Arabic',\n rtl: true,\n currencyCode: 'SAR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 힌디어\n hi: {\n locale: 'hi',\n countryCode: 'IN',\n flag: '🇮🇳',\n dialCode: '+91',\n nativeName: 'हिन्दी',\n englishName: 'Hindi',\n currencyCode: 'INR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 태국어\n th: {\n locale: 'th',\n countryCode: 'TH',\n flag: '🇹🇭',\n dialCode: '+66',\n nativeName: 'ไทย',\n englishName: 'Thai',\n currencyCode: 'THB',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 베트남어\n vi: {\n locale: 'vi',\n countryCode: 'VN',\n flag: '🇻🇳',\n dialCode: '+84',\n nativeName: 'Tiếng Việt',\n englishName: 'Vietnamese',\n currencyCode: 'VND',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 인도네시아어\n id: {\n locale: 'id',\n countryCode: 'ID',\n flag: '🇮🇩',\n dialCode: '+62',\n nativeName: 'Bahasa Indonesia',\n englishName: 'Indonesian',\n currencyCode: 'IDR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 터키어\n tr: {\n locale: 'tr',\n countryCode: 'TR',\n flag: '🇹🇷',\n dialCode: '+90',\n nativeName: 'Türkçe',\n englishName: 'Turkish',\n currencyCode: 'TRY',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 폴란드어\n pl: {\n locale: 'pl',\n countryCode: 'PL',\n flag: '🇵🇱',\n dialCode: '+48',\n nativeName: 'Polski',\n englishName: 'Polish',\n currencyCode: 'PLN',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 네덜란드어\n nl: {\n locale: 'nl',\n countryCode: 'NL',\n flag: '🇳🇱',\n dialCode: '+31',\n nativeName: 'Nederlands',\n englishName: 'Dutch',\n currencyCode: 'EUR',\n dateFormat: 'DD-MM-YYYY',\n },\n\n // 중국어 (홍콩)\n 'zh-HK': {\n locale: 'zh-HK',\n countryCode: 'HK',\n flag: '🇭🇰',\n dialCode: '+852',\n nativeName: '繁體中文 (香港)',\n englishName: 'Chinese (Hong Kong)',\n currencyCode: 'HKD',\n dateFormat: 'YYYY/MM/DD',\n },\n\n // 말레이어\n ms: {\n locale: 'ms',\n countryCode: 'MY',\n flag: '🇲🇾',\n dialCode: '+60',\n nativeName: 'Bahasa Melayu',\n englishName: 'Malay',\n currencyCode: 'MYR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 영어 (영국)\n 'en-GB': {\n locale: 'en-GB',\n countryCode: 'GB',\n flag: '🇬🇧',\n dialCode: '+44',\n nativeName: 'English (UK)',\n englishName: 'English (United Kingdom)',\n currencyCode: 'GBP',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 영어 (캐나다)\n 'en-CA': {\n locale: 'en-CA',\n countryCode: 'CA',\n flag: '🇨🇦',\n dialCode: '+1',\n nativeName: 'English (Canada)',\n englishName: 'English (Canada)',\n currencyCode: 'CAD',\n dateFormat: 'YYYY-MM-DD',\n },\n\n // 영어 (호주)\n 'en-AU': {\n locale: 'en-AU',\n countryCode: 'AU',\n flag: '🇦🇺',\n dialCode: '+61',\n nativeName: 'English (Australia)',\n englishName: 'English (Australia)',\n currencyCode: 'AUD',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 영어 (뉴질랜드)\n 'en-NZ': {\n locale: 'en-NZ',\n countryCode: 'NZ',\n flag: '🇳🇿',\n dialCode: '+64',\n nativeName: 'English (New Zealand)',\n englishName: 'English (New Zealand)',\n currencyCode: 'NZD',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 스페인어 (멕시코)\n 'es-MX': {\n locale: 'es-MX',\n countryCode: 'MX',\n flag: '🇲🇽',\n dialCode: '+52',\n nativeName: 'Español (México)',\n englishName: 'Spanish (Mexico)',\n currencyCode: 'MXN',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 스페인어 (아르헨티나)\n 'es-AR': {\n locale: 'es-AR',\n countryCode: 'AR',\n flag: '🇦🇷',\n dialCode: '+54',\n nativeName: 'Español (Argentina)',\n englishName: 'Spanish (Argentina)',\n currencyCode: 'ARS',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 스페인어 (콜롬비아)\n 'es-CO': {\n locale: 'es-CO',\n countryCode: 'CO',\n flag: '🇨🇴',\n dialCode: '+57',\n nativeName: 'Español (Colombia)',\n englishName: 'Spanish (Colombia)',\n currencyCode: 'COP',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 스웨덴어\n sv: {\n locale: 'sv',\n countryCode: 'SE',\n flag: '🇸🇪',\n dialCode: '+46',\n nativeName: 'Svenska',\n englishName: 'Swedish',\n currencyCode: 'SEK',\n dateFormat: 'YYYY-MM-DD',\n },\n\n // 노르웨이어\n no: {\n locale: 'no',\n countryCode: 'NO',\n flag: '🇳🇴',\n dialCode: '+47',\n nativeName: 'Norsk',\n englishName: 'Norwegian',\n currencyCode: 'NOK',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 덴마크어\n da: {\n locale: 'da',\n countryCode: 'DK',\n flag: '🇩🇰',\n dialCode: '+45',\n nativeName: 'Dansk',\n englishName: 'Danish',\n currencyCode: 'DKK',\n dateFormat: 'DD-MM-YYYY',\n },\n\n // 핀란드어\n fi: {\n locale: 'fi',\n countryCode: 'FI',\n flag: '🇫🇮',\n dialCode: '+358',\n nativeName: 'Suomi',\n englishName: 'Finnish',\n currencyCode: 'EUR',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 우크라이나어\n uk: {\n locale: 'uk',\n countryCode: 'UA',\n flag: '🇺🇦',\n dialCode: '+380',\n nativeName: 'Українська',\n englishName: 'Ukrainian',\n currencyCode: 'UAH',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 체코어\n cs: {\n locale: 'cs',\n countryCode: 'CZ',\n flag: '🇨🇿',\n dialCode: '+420',\n nativeName: 'Čeština',\n englishName: 'Czech',\n currencyCode: 'CZK',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 헝가리어\n hu: {\n locale: 'hu',\n countryCode: 'HU',\n flag: '🇭🇺',\n dialCode: '+36',\n nativeName: 'Magyar',\n englishName: 'Hungarian',\n currencyCode: 'HUF',\n dateFormat: 'YYYY.MM.DD.',\n },\n\n // 루마니아어\n ro: {\n locale: 'ro',\n countryCode: 'RO',\n flag: '🇷🇴',\n dialCode: '+40',\n nativeName: 'Română',\n englishName: 'Romanian',\n currencyCode: 'RON',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 불가리아어\n bg: {\n locale: 'bg',\n countryCode: 'BG',\n flag: '🇧🇬',\n dialCode: '+359',\n nativeName: 'Български',\n englishName: 'Bulgarian',\n currencyCode: 'BGN',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 크로아티아어\n hr: {\n locale: 'hr',\n countryCode: 'HR',\n flag: '🇭🇷',\n dialCode: '+385',\n nativeName: 'Hrvatski',\n englishName: 'Croatian',\n currencyCode: 'HRK',\n dateFormat: 'DD.MM.YYYY.',\n },\n\n // 세르비아어\n sr: {\n locale: 'sr',\n countryCode: 'RS',\n flag: '🇷🇸',\n dialCode: '+381',\n nativeName: 'Српски',\n englishName: 'Serbian',\n currencyCode: 'RSD',\n dateFormat: 'DD.MM.YYYY.',\n },\n\n // 슬로바키아어\n sk: {\n locale: 'sk',\n countryCode: 'SK',\n flag: '🇸🇰',\n dialCode: '+421',\n nativeName: 'Slovenčina',\n englishName: 'Slovak',\n currencyCode: 'EUR',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 슬로베니아어\n sl: {\n locale: 'sl',\n countryCode: 'SI',\n flag: '🇸🇮',\n dialCode: '+386',\n nativeName: 'Slovenščina',\n englishName: 'Slovenian',\n currencyCode: 'EUR',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 리투아니아어\n lt: {\n locale: 'lt',\n countryCode: 'LT',\n flag: '🇱🇹',\n dialCode: '+370',\n nativeName: 'Lietuvių',\n englishName: 'Lithuanian',\n currencyCode: 'EUR',\n dateFormat: 'YYYY-MM-DD',\n },\n\n // 라트비아어\n lv: {\n locale: 'lv',\n countryCode: 'LV',\n flag: '🇱🇻',\n dialCode: '+371',\n nativeName: 'Latviešu',\n englishName: 'Latvian',\n currencyCode: 'EUR',\n dateFormat: 'DD.MM.YYYY.',\n },\n\n // 에스토니아어\n et: {\n locale: 'et',\n countryCode: 'EE',\n flag: '🇪🇪',\n dialCode: '+372',\n nativeName: 'Eesti',\n englishName: 'Estonian',\n currencyCode: 'EUR',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 그리스어\n el: {\n locale: 'el',\n countryCode: 'GR',\n flag: '🇬🇷',\n dialCode: '+30',\n nativeName: 'Ελληνικά',\n englishName: 'Greek',\n currencyCode: 'EUR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 페르시아어\n fa: {\n locale: 'fa',\n countryCode: 'IR',\n flag: '🇮🇷',\n dialCode: '+98',\n nativeName: 'فارسی',\n englishName: 'Persian',\n rtl: true,\n currencyCode: 'IRR',\n dateFormat: 'YYYY/MM/DD',\n },\n\n // 히브리어\n he: {\n locale: 'he',\n countryCode: 'IL',\n flag: '🇮🇱',\n dialCode: '+972',\n nativeName: 'עברית',\n englishName: 'Hebrew',\n rtl: true,\n currencyCode: 'ILS',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 스와힐리어\n sw: {\n locale: 'sw',\n countryCode: 'KE',\n flag: '🇰🇪',\n dialCode: '+254',\n nativeName: 'Kiswahili',\n englishName: 'Swahili',\n currencyCode: 'KES',\n dateFormat: 'DD/MM/YYYY',\n },\n};\n\n/**\n * Locale 정보 가져오기\n *\n * @param locale - Locale 코드 (예: 'ko', 'en', 'ja')\n * @returns LocaleInfo 또는 undefined\n *\n * @example\n * ```typescript\n * const koInfo = getLocaleInfo('ko');\n * console.log(koInfo.flag); // 🇰🇷\n * console.log(koInfo.dialCode); // +82\n * ```\n */\nexport function getLocaleInfo(locale: string): LocaleInfo | undefined\n{\n return LOCALE_INFO_MAP[locale as SupportedLocale];\n}\n\n/**\n * 지원하는 모든 Locale 목록 가져오기\n *\n * @returns Locale 코드 배열\n */\nexport function getSupportedLocales(): SupportedLocale[]\n{\n return Object.keys(LOCALE_INFO_MAP) as SupportedLocale[];\n}\n\n/**\n * 국기 이모지만 가져오기\n *\n * @param locale - Locale 코드\n * @returns 국기 이모지 또는 빈 문자열\n *\n * @example\n * ```typescript\n * getFlag('ko'); // 🇰🇷\n * getFlag('en'); // 🇺🇸\n * ```\n */\nexport function getFlag(locale: string): string\n{\n return LOCALE_INFO_MAP[locale as SupportedLocale]?.flag ?? '';\n}\n\n/**\n * 전화번호 국가 코드 가져오기\n *\n * @param locale - Locale 코드\n * @returns 전화번호 코드 또는 빈 문자열\n *\n * @example\n * ```typescript\n * getDialCode('ko'); // +82\n * getDialCode('en'); // +1\n * ```\n */\nexport function getDialCode(locale: string): string\n{\n return LOCALE_INFO_MAP[locale as SupportedLocale]?.dialCode ?? '';\n}\n\n/**\n * RTL (Right-to-Left) 여부 확인\n *\n * @param locale - Locale 코드\n * @returns RTL 여부\n *\n * @example\n * ```typescript\n * isRTL('ar'); // true (Arabic)\n * isRTL('ko'); // false (Korean)\n * ```\n */\nexport function isRTL(locale: string): boolean\n{\n return LOCALE_INFO_MAP[locale as SupportedLocale]?.rtl ?? false;\n}"],"mappings":"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","names":["client","client","client","client","client","client","client","client","Type","client","client","Type","client","state","replaceVariables","detectBrowserLanguage"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/hooks/useSection.ts","../src/client/store/cms.store.ts","../src/api/index.ts","../src/api/cms-labels.ts","../src/lib/contracts/labels.ts","../src/api/cms-labels-by-key.ts","../src/api/cms-labels-publish.ts","../src/api/cms-labels-admin.ts","../src/api/cms-labels-versions.ts","../src/api/cms-published-cache.ts","../src/lib/contracts/published-cache.ts","../src/api/cms-values.ts","../src/lib/contracts/values.ts","../src/client/hooks/useSections.ts","../src/client/components/InitCms.tsx","../src/server/helpers/locale.actions.ts","../src/server/config/cms.config.ts","../src/lib/constants/locale.constants.ts"],"sourcesContent":["/**\n * useSection Hook\n *\n * 클라이언트 컴포넌트에서 섹션 데이터 사용\n */\n\n'use client';\n\nimport React from 'react';\nimport { useCmsStore } from '../store/cms.store';\n\n/**\n * 변수 치환 헬퍼 (서버와 동일)\n */\nfunction replaceVariables(text: string, replace: Record<string, string | number>): string\n{\n return text.replace(/\\{(\\w+)}/g, (match, key) =>\n {\n const value = replace[key];\n return value !== undefined ? String(value) : match;\n });\n}\n\n/**\n * 섹션 Hook (서버 API와 동일한 패턴)\n *\n * @param section - 섹션 이름\n * @param options - 옵션 (autoLoad: 자동 로드 여부)\n * @returns { t, data, loading }\n *\n * @example\n * ```tsx\n * 'use client';\n * import { useSection } from '@spfn/cms/client';\n *\n * export function ClientComponent()\n * {\n * const { t } = useSection('home', { autoLoad: true });\n * return <h1>{t('hero.title')}</h1>;\n * }\n * ```\n */\nexport function useSection(\n section: string,\n options: { autoLoad?: boolean; locale?: string } = {}\n)\n{\n const { autoLoad = false, locale = 'ko' } = options;\n\n const sectionData = useCmsStore((state) => state.sections[section]);\n const loading = useCmsStore((state) => state.loading[section] ?? false);\n const loadSection = useCmsStore((state) => state.loadSection);\n\n // 자동 로드 옵션이 켜져있고 데이터가 없으면 로드\n React.useEffect(() =>\n {\n if (autoLoad && !sectionData && !loading)\n {\n loadSection(section, locale);\n }\n }, [autoLoad, section, locale, sectionData, loading, loadSection]);\n\n // Translation function (서버와 동일)\n const t = React.useCallback(\n (key: string, defaultValue?: any, replace?: Record<string, string | number>) =>\n {\n if (!sectionData)\n {\n return defaultValue;\n }\n\n const fullKey = `${section}.${key}`;\n let value = sectionData.content[fullKey];\n\n if (value === undefined)\n {\n value = defaultValue;\n }\n\n // 문자열이고 치환 맵이 있으면 변수 치환\n if (typeof value === 'string' && replace)\n {\n value = replaceVariables(value, replace);\n }\n\n return value;\n },\n [section, sectionData]\n );\n\n return {\n t,\n data: sectionData,\n loading,\n };\n}","/**\n * CMS Zustand Store\n *\n * 클라이언트 컴포넌트에서 CMS 사용을 위한 상태 관리\n * - 서버에서 초기화된 데이터를 클라이언트로 전달\n * - 클라이언트에서 비동기로 로드 가능\n */\n\n'use client';\n\nimport { create } from 'zustand';\nimport { cmsApi } from '@/api';\nimport type { SectionData } from '@/server';\n\ninterface CmsState\n{\n /**\n * 섹션별 데이터\n * { 'home': { section: 'home', content: {...}, version: 1, ... }, ... }\n */\n sections: Record<string, SectionData>;\n\n /**\n * 로딩 상태\n */\n loading: Record<string, boolean>;\n\n /**\n * 섹션 데이터 설정 (서버에서 초기화용)\n */\n setSection: (section: string, data: SectionData) => void;\n\n /**\n * 여러 섹션 한번에 설정\n */\n setSections: (sections: Record<string, SectionData>) => void;\n\n /**\n * 섹션 비동기 로드\n */\n loadSection: (section: string, locale?: string) => Promise<void>;\n\n /**\n * 라벨 업데이트 (Draft Mode용)\n */\n updateLabel: (section: string, key: string, value: any) => void;\n\n /**\n * 초기화\n */\n reset: () => void;\n}\n\nexport const useCmsStore = create<CmsState>((set, get) => ({\n sections: {},\n loading: {},\n\n setSection: (section, data) =>\n {\n set((state) => ({\n sections: {\n ...state.sections,\n [section]: data,\n },\n }));\n },\n\n setSections: (sections) =>\n {\n set((state) => ({\n sections: {\n ...state.sections,\n ...sections,\n },\n }));\n },\n\n loadSection: async (section, locale = 'ko') =>\n {\n const state = get();\n\n // 이미 로드 중이면 스킵\n if (state.loading[section])\n {\n return;\n }\n\n // 이미 로드되어 있으면 스킵\n if (state.sections[section])\n {\n return;\n }\n\n set((state) => ({\n loading: { ...state.loading, [section]: true },\n }));\n\n try\n {\n const response = await cmsApi.getPublishedCache({\n query: { sections: section, locale },\n });\n\n // Check for error response\n if ('error' in response)\n {\n console.error(`Failed to load section ${section}:`, response.error);\n return;\n }\n\n // Response is array, get first element\n const data = response[0];\n\n if (!data)\n {\n console.warn(`Section ${section} not found`);\n return;\n }\n\n const sectionData: SectionData = {\n section: data.section,\n locale: data.locale,\n content: (data.content as Record<string, any>) || {},\n version: data.version || 0,\n publishedAt: data.publishedAt || null,\n };\n\n set((state) => ({\n sections: {\n ...state.sections,\n [section]: sectionData,\n },\n loading: { ...state.loading, [section]: false },\n }));\n }\n catch (error)\n {\n console.error(`Error loading CMS section ${section}:`, error);\n set((state) => ({\n loading: { ...state.loading, [section]: false },\n }));\n }\n },\n\n updateLabel: (section, key, value) =>\n {\n set((state) => ({\n sections: {\n ...state.sections,\n [section]: {\n ...state.sections[section],\n content: {\n ...state.sections[section]?.content,\n [`${section}.${key}`]: value,\n },\n },\n },\n }));\n },\n\n reset: () =>\n {\n set({\n sections: {},\n loading: {},\n });\n },\n}));","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T13:40:07.039Z\n */\n\nexport { client } from '@spfn/core/client';\n\nexport type { GetLabelsResponse, GetLabelsQuery, CreateLabelResponse, CreateLabelBody, GetLabelResponse, GetLabelParams, UpdateLabelResponse, UpdateLabelParams, UpdateLabelBody, DeleteLabelResponse, DeleteLabelParams } from './cms-labels.js';\nexport type { GetLabelByKeyResponse, GetLabelByKeyParams } from './cms-labels-by-key.js';\nexport type { PublishLabelResponse, PublishLabelParams, PublishLabelBody } from './cms-labels-publish.js';\nexport type { GetAdminLabelResponse, GetAdminLabelParams } from './cms-labels-admin.js';\nexport type { GetLabelVersionsResponse, GetLabelVersionsParams } from './cms-labels-versions.js';\nexport type { GetPublishedCacheResponse, GetPublishedCacheQuery, UpsertPublishedCacheResponse, UpsertPublishedCacheBody } from './cms-published-cache.js';\nexport type { SaveValuesResponse, SaveValuesParams, SaveValuesBody, GetValuesResponse, GetValuesQuery, GetValuesParams } from './cms-values.js';\n\nimport { getLabels, createLabel, getLabel, updateLabel, deleteLabel } from './cms-labels.js';\nimport { getLabelByKey } from './cms-labels-by-key.js';\nimport { publishLabel } from './cms-labels-publish.js';\nimport { getAdminLabel } from './cms-labels-admin.js';\nimport { getLabelVersions } from './cms-labels-versions.js';\nimport { getPublishedCache, upsertPublishedCache } from './cms-published-cache.js';\nimport { saveValues, getValues } from './cms-values.js';\n\n/**\n * Type-safe API client\n */\nexport const cmsApi = {\n getLabels,\n createLabel,\n getLabel,\n updateLabel,\n deleteLabel,\n getLabelByKey,\n publishLabel,\n getAdminLabel,\n getLabelVersions,\n getPublishedCache,\n upsertPublishedCache,\n saveValues,\n getValues\n} as const;\n","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T13:40:07.036Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { getLabelsContract, createLabelContract, getLabelContract, updateLabelContract, deleteLabelContract } from '@/lib/contracts/labels';\n\n// ============================================\n// Types\n// ============================================\n\nexport type GetLabelsResponse = InferContract<typeof getLabelsContract>['response'];\nexport type GetLabelsQuery = InferContract<typeof getLabelsContract>['query'];\n\nexport type CreateLabelResponse = InferContract<typeof createLabelContract>['response'];\nexport type CreateLabelBody = InferContract<typeof createLabelContract>['body'];\n\nexport type GetLabelResponse = InferContract<typeof getLabelContract>['response'];\nexport type GetLabelParams = InferContract<typeof getLabelContract>['params'];\n\nexport type UpdateLabelResponse = InferContract<typeof updateLabelContract>['response'];\nexport type UpdateLabelParams = InferContract<typeof updateLabelContract>['params'];\nexport type UpdateLabelBody = InferContract<typeof updateLabelContract>['body'];\n\nexport type DeleteLabelResponse = InferContract<typeof deleteLabelContract>['response'];\nexport type DeleteLabelParams = InferContract<typeof deleteLabelContract>['params'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * GET /_cms/labels\n */\nexport const getLabels = (options: { query?: GetLabelsQuery }) => client.call(getLabelsContract, options);\n\n/**\n * POST /_cms/labels\n */\nexport const createLabel = (options: { body: CreateLabelBody }) => client.call(createLabelContract, options);\n\n/**\n * GET /_cms/labels/:id\n */\nexport const getLabel = (options: { params: GetLabelParams }) => client.call(getLabelContract, options);\n\n/**\n * PATCH /_cms/labels/:id\n */\nexport const updateLabel = (options: { params: UpdateLabelParams, body: UpdateLabelBody }) => client.call(updateLabelContract, options);\n\n/**\n * DELETE /_cms/labels/:id\n */\nexport const deleteLabel = (options: { params: DeleteLabelParams }) => client.call(deleteLabelContract, options);\n\n","import { Type } from '@sinclair/typebox';\nimport type { RouteContract } from '@spfn/core/route';\n\n/**\n * CMS Labels Contracts\n *\n * 라벨 메타데이터 관리 API\n */\n\n/**\n * GET /_cms/labels - 라벨 목록 조회\n */\nexport const getLabelsContract = {\n method: 'GET' as const,\n path: '/_cms/labels',\n query: Type.Object({\n section: Type.Optional(Type.String({ description: '섹션으로 필터링 (예: home, why-futureplay)' })),\n limit: Type.Optional(Type.Number({ minimum: 1, maximum: 100, default: 20, description: '페이지당 항목 수' })),\n offset: Type.Optional(Type.Number({ minimum: 0, default: 0, description: '시작 오프셋' })),\n includeDefaultValues: Type.Optional(Type.Boolean({ description: '기본값 포함 여부', default: false }))\n }),\n response: Type.Object({\n labels: Type.Array(Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n description: Type.Union([Type.String(), Type.Null()], { description: '라벨 설명' }),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String(),\n defaultValue: Type.Optional(Type.Any({ description: '라벨 정의 파일의 기본값' }))\n })),\n total: Type.Number(),\n limit: Type.Number(),\n offset: Type.Number()\n })\n} as const satisfies RouteContract;\n\n/**\n * POST /_cms/labels - 새 라벨 생성\n */\nexport const createLabelContract = {\n method: 'POST' as const,\n path: '/_cms/labels',\n body: Type.Object({\n key: Type.String({\n description: '고유 키 (예: home.hero.title)',\n pattern: '^[a-z0-9-]+\\\\.[a-z0-9-]+\\\\.[a-z0-9-]+$'\n }),\n section: Type.String({\n description: '섹션 이름 (예: home, why-futureplay)',\n pattern: '^[a-z0-9-]+$'\n }),\n type: Type.Union([\n Type.Literal('text'),\n Type.Literal('image'),\n Type.Literal('video'),\n Type.Literal('file'),\n Type.Literal('object')\n ], { description: '값 타입' }),\n createdBy: Type.Optional(Type.String({ description: '생성자 ID' }))\n }),\n response: Type.Union([\n Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n Type.Object({\n error: Type.String(),\n key: Type.Optional(Type.String())\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * GET /_cms/labels/:id - 라벨 단건 조회\n */\nexport const getLabelContract = {\n method: 'GET' as const,\n path: '/_cms/labels/:id',\n params: Type.Object({\n id: Type.String({ description: '라벨 ID' })\n }),\n response: Type.Union([\n Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n description: Type.Union([Type.String(), Type.Null()]),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * PATCH /_cms/labels/:id - 라벨 메타데이터 수정\n */\nexport const updateLabelContract = {\n method: 'PATCH' as const,\n path: '/_cms/labels/:id',\n params: Type.Object({\n id: Type.String({ description: '라벨 ID' })\n }),\n body: Type.Object({\n section: Type.Optional(Type.String({ description: '섹션 변경' })),\n type: Type.Optional(Type.Union([\n Type.Literal('text'),\n Type.Literal('image'),\n Type.Literal('video'),\n Type.Literal('file'),\n Type.Literal('object')\n ]))\n }),\n response: Type.Union([\n Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n description: Type.Union([Type.String(), Type.Null()]),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * DELETE /_cms/labels/:id - 라벨 삭제\n */\nexport const deleteLabelContract = {\n method: 'DELETE' as const,\n path: '/_cms/labels/:id',\n params: Type.Object({\n id: Type.String({ description: '라벨 ID' })\n }),\n response: Type.Union([\n Type.Object({\n success: Type.Boolean(),\n id: Type.Number()\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * GET /_cms/labels/by-key/:key - Key로 라벨 조회\n */\nexport const getLabelByKeyContract = {\n method: 'GET' as const,\n path: '/_cms/labels/by-key/:key',\n params: Type.Object({\n key: Type.String({ description: '라벨 Key (예: home.hero.title)' })\n }),\n response: Type.Union([\n Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n description: Type.Union([Type.String(), Type.Null()]),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n Type.Object({\n error: Type.String(),\n key: Type.Optional(Type.String())\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * POST /_cms/labels/:labelId/publish - 라벨 발행 (Draft → Published)\n */\nexport const publishLabelContract = {\n method: 'POST' as const,\n path: '/_cms/labels/:labelId/publish',\n params: Type.Object({\n labelId: Type.String({ description: '라벨 ID' })\n }),\n body: Type.Object({\n notes: Type.Optional(Type.String({ description: '발행 노트 (버전 설명)' })),\n publishedBy: Type.Optional(Type.String({ description: '발행자 ID' }))\n }),\n response: Type.Union([\n Type.Object({\n success: Type.Boolean(),\n labelId: Type.Number(),\n version: Type.Number(),\n message: Type.String()\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * GET /_cms/labels/:labelId/admin - 관리자용 라벨 조회 (Draft + Published + Status)\n */\nexport const getAdminLabelContract = {\n method: 'GET' as const,\n path: '/_cms/labels/:labelId/admin',\n params: Type.Object({\n labelId: Type.String({ description: '라벨 ID' })\n }),\n response: Type.Union([\n Type.Object({\n label: Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n description: Type.Union([Type.String(), Type.Null()]),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n draft: Type.Array(Type.Object({\n id: Type.Number(),\n labelId: Type.Number(),\n version: Type.Null(),\n locale: Type.String(),\n breakpoint: Type.Union([Type.String(), Type.Null()]),\n value: Type.Any(),\n createdAt: Type.String()\n })),\n published: Type.Array(Type.Object({\n id: Type.Number(),\n labelId: Type.Number(),\n version: Type.Number(),\n locale: Type.String(),\n breakpoint: Type.Union([Type.String(), Type.Null()]),\n value: Type.Any(),\n createdAt: Type.String()\n })),\n status: Type.Union([\n Type.Literal('default-only'),\n Type.Literal('unpublished'),\n Type.Literal('published'),\n Type.Literal('modified')\n ])\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * GET /_cms/labels/:labelId/versions - 라벨 버전 히스토리 조회\n */\nexport const getLabelVersionsContract = {\n method: 'GET' as const,\n path: '/_cms/labels/:labelId/versions',\n params: Type.Object({\n labelId: Type.String({ description: '라벨 ID' })\n }),\n response: Type.Union([\n Type.Object({\n versions: Type.Array(Type.Object({\n version: Type.Number({ description: '버전 번호' }),\n publishedAt: Type.String({ description: '발행 시각 (ISO 8601)' }),\n publishedBy: Type.Union([Type.String(), Type.Null()], { description: '발행자 ID' }),\n notes: Type.Union([Type.String(), Type.Null()], { description: '발행 노트' }),\n values: Type.Array(Type.Object({\n id: Type.Number(),\n locale: Type.String(),\n breakpoint: Type.Union([Type.String(), Type.Null()]),\n value: Type.Any(),\n createdAt: Type.String()\n }))\n }))\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T13:40:07.037Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { getLabelByKeyContract } from '@/lib/contracts/labels';\n\n// ============================================\n// Types\n// ============================================\n\nexport type GetLabelByKeyResponse = InferContract<typeof getLabelByKeyContract>['response'];\nexport type GetLabelByKeyParams = InferContract<typeof getLabelByKeyContract>['params'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * GET /_cms/labels/by-key/:key\n */\nexport const getLabelByKey = (options: { params: GetLabelByKeyParams }) => client.call(getLabelByKeyContract, options);\n\n","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T13:40:07.037Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { publishLabelContract } from '@/lib/contracts/labels';\n\n// ============================================\n// Types\n// ============================================\n\nexport type PublishLabelResponse = InferContract<typeof publishLabelContract>['response'];\nexport type PublishLabelParams = InferContract<typeof publishLabelContract>['params'];\nexport type PublishLabelBody = InferContract<typeof publishLabelContract>['body'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * POST /_cms/labels/:labelId/publish\n */\nexport const publishLabel = (options: { params: PublishLabelParams, body: PublishLabelBody }) => client.call(publishLabelContract, options);\n\n","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T13:40:07.038Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { getAdminLabelContract } from '@/lib/contracts/labels';\n\n// ============================================\n// Types\n// ============================================\n\nexport type GetAdminLabelResponse = InferContract<typeof getAdminLabelContract>['response'];\nexport type GetAdminLabelParams = InferContract<typeof getAdminLabelContract>['params'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * GET /_cms/labels/:labelId/admin\n */\nexport const getAdminLabel = (options: { params: GetAdminLabelParams }) => client.call(getAdminLabelContract, options);\n\n","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T13:40:07.038Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { getLabelVersionsContract } from '@/lib/contracts/labels';\n\n// ============================================\n// Types\n// ============================================\n\nexport type GetLabelVersionsResponse = InferContract<typeof getLabelVersionsContract>['response'];\nexport type GetLabelVersionsParams = InferContract<typeof getLabelVersionsContract>['params'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * GET /_cms/labels/:labelId/versions\n */\nexport const getLabelVersions = (options: { params: GetLabelVersionsParams }) => client.call(getLabelVersionsContract, options);\n\n","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T13:40:07.038Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { getPublishedCacheContract, upsertPublishedCacheContract } from '@/lib/contracts/published-cache';\n\n// ============================================\n// Types\n// ============================================\n\nexport type GetPublishedCacheResponse = InferContract<typeof getPublishedCacheContract>['response'];\nexport type GetPublishedCacheQuery = InferContract<typeof getPublishedCacheContract>['query'];\n\nexport type UpsertPublishedCacheResponse = InferContract<typeof upsertPublishedCacheContract>['response'];\nexport type UpsertPublishedCacheBody = InferContract<typeof upsertPublishedCacheContract>['body'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * GET /_cms/published-cache\n */\nexport const getPublishedCache = (options: { query?: GetPublishedCacheQuery }) => client.call(getPublishedCacheContract, options);\n\n/**\n * POST /_cms/published-cache\n */\nexport const upsertPublishedCache = (options: { body: UpsertPublishedCacheBody }) => client.call(upsertPublishedCacheContract, options);\n\n","import { Type } from '@sinclair/typebox';\nimport type { RouteContract } from '@spfn/core/route';\n\nconst SectionData = Type.Object({\n section: Type.String(),\n locale: Type.String(),\n content: Type.Record(Type.String(), Type.Any()),\n version: Type.Number(),\n publishedAt: Type.Union([Type.String(), Type.Null()]),\n});\n\n/**\n * GET /_cms/published-cache\n * 발행된 콘텐츠 캐시 조회 (단일 또는 여러 섹션)\n */\nexport const getPublishedCacheContract = {\n method: 'GET' as const,\n path: '/_cms/published-cache',\n query: Type.Object({\n sections: Type.Union([\n Type.String({ description: '단일 섹션 이름 (예: home)' }),\n Type.Array(Type.String(), { description: '여러 섹션 이름 (예: [\"home\", \"footer\"])' })\n ]),\n locale: Type.Optional(Type.String({ default: 'ko', description: '언어 코드' })),\n }),\n response: Type.Union([\n // 성공: 항상 배열로 반환\n Type.Array(SectionData),\n // 에러\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * POST /_cms/published-cache\n * 발행된 콘텐츠 캐시 업데이트/생성 (upsert)\n */\nexport const upsertPublishedCacheContract = {\n method: 'POST' as const,\n path: '/_cms/published-cache',\n body: Type.Object({\n section: Type.String({ description: '섹션 이름 (예: home)' }),\n locale: Type.String({ description: '언어 코드 (예: ko, en, ja)' }),\n content: Type.Record(Type.String(), Type.Any(), { description: '발행할 콘텐츠 (key-value 형태)' }),\n version: Type.Number({ description: '버전 번호' })\n }),\n response: Type.Union([\n SectionData,\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;","/**\n * Auto-generated API Client\n *\n * Generated by @spfn/core codegen\n * DO NOT EDIT MANUALLY\n *\n * @generated 2025-11-03T13:40:07.039Z\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\nimport { saveValuesContract, getValuesContract } from '@/lib/contracts/values';\n\n// ============================================\n// Types\n// ============================================\n\nexport type SaveValuesResponse = InferContract<typeof saveValuesContract>['response'];\nexport type SaveValuesParams = InferContract<typeof saveValuesContract>['params'];\nexport type SaveValuesBody = InferContract<typeof saveValuesContract>['body'];\n\nexport type GetValuesResponse = InferContract<typeof getValuesContract>['response'];\nexport type GetValuesQuery = InferContract<typeof getValuesContract>['query'];\nexport type GetValuesParams = InferContract<typeof getValuesContract>['params'];\n\n// ============================================\n// API Functions\n// ============================================\n\n/**\n * POST /_cms/values/:labelId\n */\nexport const saveValues = (options: { params: SaveValuesParams, body: SaveValuesBody }) => client.call(saveValuesContract, options);\n\n/**\n * GET /_cms/values/:labelId/:version\n */\nexport const getValues = (options: { params: GetValuesParams, query?: GetValuesQuery }) => client.call(getValuesContract, options);\n\n","import { Type } from '@sinclair/typebox';\nimport type { RouteContract } from '@spfn/core/route';\n\n/**\n * Label Value 타입 정의\n */\nconst LabelValueSchema = Type.Object({\n type: Type.Union([\n Type.Literal('text'),\n Type.Literal('image'),\n Type.Literal('video'),\n Type.Literal('file'),\n Type.Literal('object')\n ]),\n content: Type.Optional(Type.String()), // text type\n url: Type.Optional(Type.String()), // image, video, file types\n alt: Type.Optional(Type.String()), // image type\n width: Type.Optional(Type.Number()), // image type\n height: Type.Optional(Type.Number()), // image type\n thumbnail: Type.Optional(Type.String()), // video type\n duration: Type.Optional(Type.Number()), // video type\n filename: Type.Optional(Type.String()), // file type\n size: Type.Optional(Type.Number()), // file type\n fields: Type.Optional(Type.Any()) // object type - recursive structure\n});\n\n/**\n * POST /_cms/values/:labelId - 라벨 값 저장\n * - version: null → Draft 저장 (덮어쓰기)\n * - version: number → Published 버전 생성 (불변)\n */\nexport const saveValuesContract = {\n method: 'POST' as const,\n path: '/_cms/values/:labelId',\n params: Type.Object({\n labelId: Type.String({ description: '라벨 ID' })\n }),\n body: Type.Object({\n version: Type.Union([\n Type.Null({ description: 'Draft 저장 (덮어쓰기)' }),\n Type.Number({ description: '버전 번호 (불변)', minimum: 1 })\n ]),\n values: Type.Array(\n Type.Object({\n locale: Type.String({ description: '언어 코드 (ko, en, ja)', default: 'ko' }),\n breakpoint: Type.Optional(Type.Union([\n Type.Literal('sm'),\n Type.Literal('md'),\n Type.Literal('lg'),\n Type.Literal('xl'),\n Type.Literal('2xl'),\n Type.Null()\n ], { description: '반응형 브레이크포인트' })),\n value: LabelValueSchema\n })\n )\n }),\n response: Type.Union([\n Type.Object({\n success: Type.Boolean(),\n saved: Type.Number(),\n version: Type.Union([Type.Null(), Type.Number()])\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * GET /_cms/values/:labelId/:version - 특정 버전의 값 조회\n */\nexport const getValuesContract = {\n method: 'GET' as const,\n path: '/_cms/values/:labelId/:version',\n params: Type.Object({\n labelId: Type.String({ description: '라벨 ID' }),\n version: Type.String({ description: '버전 번호' })\n }),\n query: Type.Object({\n locale: Type.Optional(Type.String({ description: '언어 코드 (ko, en, ja)' })),\n breakpoint: Type.Optional(Type.String({ description: '반응형 브레이크포인트' }))\n }),\n response: Type.Union([\n Type.Object({\n labelId: Type.Number(),\n version: Type.Number(),\n values: Type.Array(\n Type.Object({\n id: Type.Number(),\n locale: Type.String(),\n breakpoint: Type.Union([Type.String(), Type.Null()]),\n value: Type.Any(),\n createdAt: Type.String()\n })\n )\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;","/**\n * useSections Hook\n *\n * 여러 섹션을 한번에 사용\n */\n\n'use client';\n\nimport { useCmsStore } from '../store/cms.store';\nimport type { useSection } from './useSection';\n\n/**\n * 변수 치환 헬퍼 (서버와 동일)\n */\nfunction replaceVariables(text: string, replace: Record<string, string | number>): string\n{\n return text.replace(/\\{(\\w+)}/g, (match, key) =>\n {\n const value = replace[key];\n return value !== undefined ? String(value) : match;\n });\n}\n\n/**\n * 여러 섹션 Hook\n *\n * @param sectionNames - 섹션 이름 배열\n * @returns { [section]: { t, data, loading }, ... }\n *\n * @example\n * ```tsx\n * 'use client';\n * import { useSections } from '@spfn/cms/client';\n *\n * export function Component()\n * {\n * const sections = useSections(['home', 'layout']);\n * return (\n * <div>\n * <h1>{sections.home.t('hero.title')}</h1>\n * <p>{sections.layout.t('footer.copyright')}</p>\n * </div>\n * );\n * }\n * ```\n */\nexport function useSections(sectionNames: string[])\n{\n const allSections = useCmsStore((state) => state.sections);\n const allLoading = useCmsStore((state) => state.loading);\n\n const result: Record<string, ReturnType<typeof useSection>> = {};\n\n sectionNames.forEach((section) =>\n {\n const sectionData = allSections[section];\n const loading = allLoading[section] ?? false;\n\n const t = (key: string, defaultValue?: any, replace?: Record<string, string | number>) =>\n {\n if (!sectionData)\n {\n return defaultValue;\n }\n\n const fullKey = `${section}.${key}`;\n let value = sectionData.content[fullKey];\n\n if (value === undefined)\n {\n value = defaultValue;\n }\n\n if (typeof value === 'string' && replace)\n {\n value = replaceVariables(value, replace);\n }\n\n return value;\n };\n\n result[section] = {\n t,\n data: sectionData,\n loading,\n };\n });\n\n return result;\n}","/**\n * CMS Store Initializer\n *\n * 서버 컴포넌트에서 로드한 섹션 데이터를 클라이언트 store에 초기화\n */\n\n'use client';\n\nimport { useEffect } from 'react';\nimport { useCmsStore } from '@/client/store/cms.store';\nimport type { SectionAPI } from '@/server';\n\ninterface InitCmsProps\n{\n /**\n * 서버에서 로드한 섹션 데이터\n * { home: { t, data }, ... }\n */\n sections: Record<string, SectionAPI>;\n}\n\n/**\n * CMS Store 초기화 컴포넌트\n *\n * 서버 컴포넌트에서 로드한 데이터를 클라이언트 store에 주입\n * 이후 하위 클라이언트 컴포넌트에서 useSection() 사용 가능\n *\n * @param props - InitCmsProps\n * @param props.sections - 서버에서 로드한 섹션 데이터\n *\n * @example\n * // Server Component\n * const home = await getSection('home');\n * <InitCms sections={{ home }} />\n * // 이후 하위 클라이언트 컴포넌트에서 useSection('home') 사용 가능\n */\nexport function InitCms({ sections }: InitCmsProps)\n{\n const setSections = useCmsStore((state) => state.setSections);\n\n useEffect(() =>\n {\n // SectionAPI → SectionData 변환\n const sectionsData: Record<string, any> = {};\n Object.entries(sections).forEach(([key, { data }]) =>\n {\n sectionsData[key] = data;\n });\n\n setSections(sectionsData);\n }, [sections, setSections]);\n\n return null;\n}","\"use server\";\n\n/**\n * Locale Management Server Actions\n *\n * Server Actions으로 구현된 locale 관리 함수\n * - 서버 컴포넌트: 일반 함수 호출로 동작\n * - 클라이언트 컴포넌트: Server Action으로 자동 처리\n */\n\nimport { cookies, headers } from 'next/headers.js';\nimport { getCmsConfig } from '@/server/config/cms.config';\nimport {\n LOCALE_COOKIE_KEY,\n getLocaleInfo,\n type LocaleInfo,\n} from '@/lib/constants/locale.constants';\n\n/**\n * 브라우저 언어 감지\n *\n * Accept-Language 헤더에서 지원하는 언어를 찾습니다.\n *\n * @returns 감지된 언어 코드 또는 null\n */\nasync function detectBrowserLanguage(): Promise<string | null>\n{\n try\n {\n const headersList = await headers();\n const acceptLanguage = headersList.get('accept-language');\n\n if (!acceptLanguage)\n {\n return null;\n }\n\n // \"ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7\" 형식 파싱\n const languages = acceptLanguage\n .split(',')\n .map(lang =>\n {\n const [code] = lang.split(';');\n return code.split('-')[0].trim();\n });\n\n const config = getCmsConfig();\n\n // 지원하는 언어 중 첫 번째 매칭되는 언어 반환\n for (const lang of languages)\n {\n if (config.supportedLocales.includes(lang))\n {\n return lang;\n }\n }\n\n return null;\n }\n catch (error)\n {\n // 헤더 접근 실패 시\n return null;\n }\n}\n\n/**\n * 현재 locale 가져오기 (Server Action)\n *\n * 서버/클라이언트 컴포넌트 모두에서 사용 가능\n *\n * 우선순위:\n * 1. 쿠키 (사용자가 명시적으로 선택한 언어)\n * 2. 브라우저 언어 감지 (설정에서 활성화된 경우)\n * 3. 시스템 기본 언어 (CMS 설정)\n *\n * @returns 현재 locale (예: 'ko', 'en')\n *\n * @example\n * ```tsx\n * // Server Component\n * import { getLocale } from '@spfn/cms/actions';\n *\n * export default async function Page()\n * {\n * const locale = await getLocale();\n * return <div>Current locale: {locale}</div>;\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Client Component\n * 'use client';\n * import { getLocale } from '@spfn/cms/client';\n *\n * export default function LanguageSwitcher()\n * {\n * const [locale, setLocale] = useState('');\n *\n * useEffect(() => {\n * getLocale().then(setLocale);\n * }, []);\n *\n * return <div>Current locale: {locale}</div>;\n * }\n * ```\n */\nexport async function getLocale(): Promise<string>\n{\n const config = getCmsConfig();\n\n // 1순위: 쿠키 (사용자가 명시적으로 선택한 언어)\n const cookieStore = await cookies();\n const cookieLocale = cookieStore.get(LOCALE_COOKIE_KEY)?.value;\n\n if (cookieLocale && config.supportedLocales.includes(cookieLocale))\n {\n return cookieLocale;\n }\n\n // 2순위: 브라우저 언어 감지 (설정에서 활성화된 경우)\n if (config.detectBrowserLanguage)\n {\n const browserLang = await detectBrowserLanguage();\n if (browserLang)\n {\n return browserLang;\n }\n }\n\n // 3순위: 시스템 기본 언어\n return config.defaultLocale;\n}\n\n/**\n * Locale 설정하기 (Server Action)\n *\n * 서버/클라이언트 컴포넌트 모두에서 사용 가능\n * 쿠키에 locale을 저장합니다.\n *\n * @param locale - 설정할 locale (예: 'ko', 'en')\n * @throws {Error} 지원하지 않는 locale인 경우\n *\n * @example\n * ```tsx\n * // Server Component (Server Action)\n * import { setLocale } from '@spfn/cms/actions';\n *\n * export default async function Page()\n * {\n * await setLocale('en');\n * return <div>Locale changed</div>;\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Client Component (Server Action)\n * 'use client';\n * import { setLocale } from '@spfn/cms/client';\n *\n * export default function LanguageSwitcher()\n * {\n * const handleChange = async (newLocale: string) =>\n * {\n * await setLocale(newLocale);\n * window.location.reload(); // 페이지 새로고침\n * };\n *\n * return (\n * <button onClick={() => handleChange('en')}>\n * Switch to English\n * </button>\n * );\n * }\n * ```\n */\nexport async function setLocale(locale: string): Promise<void>\n{\n const config = getCmsConfig();\n\n // 유효성 검사\n if (!config.supportedLocales.includes(locale))\n {\n throw new Error(\n `Unsupported locale: ${locale}. Supported locales: ${config.supportedLocales.join(', ')}`\n );\n }\n\n const cookieStore = await cookies();\n\n cookieStore.set(LOCALE_COOKIE_KEY, locale, {\n path: '/',\n maxAge: 60 * 60 * 24 * 365, // 1년\n sameSite: 'lax',\n });\n}\n\n/**\n * 지원하는 locale 목록 가져오기 (Server Action)\n *\n * 서버/클라이언트 컴포넌트 모두에서 사용 가능\n *\n * @returns 지원하는 locale 배열 (예: ['ko', 'en', 'ja'])\n *\n * @example\n * ```tsx\n * // Server Component\n * import { getLocales } from '@spfn/cms/actions';\n *\n * export default async function Page()\n * {\n * const locales = await getLocales();\n * return <div>Supported: {locales.join(', ')}</div>;\n * }\n * ```\n *\n * @example\n * ```tsx\n * // Client Component\n * 'use client';\n * import { getLocales } from '@spfn/cms/client';\n *\n * export default function LanguageSwitcher()\n * {\n * const [locales, setLocales] = useState<string[]>([]);\n *\n * useEffect(() => {\n * getLocales().then(setLocales);\n * }, []);\n *\n * return (\n * <div>\n * {locales.map(locale => (\n * <button key={locale}>{locale}</button>\n * ))}\n * </div>\n * );\n * }\n * ```\n */\nexport async function getLocales(): Promise<string[]>\n{\n const config = getCmsConfig();\n return config.supportedLocales;\n}\n\n/**\n * 현재 locale과 상세 정보 함께 가져오기 (Server Action)\n *\n * locale 코드와 함께 국가 코드, 국기, 전화번호 코드 등의 상세 정보를 반환합니다.\n *\n * @returns Locale 코드와 LocaleInfo 객체\n *\n * @example\n * ```tsx\n * // Server Component\n * import { getLocaleWithInfo } from '@spfn/cms/actions';\n *\n * export default async function Page()\n * {\n * const { locale, info } = await getLocaleWithInfo();\n *\n * return (\n * <div>\n * <span>{info?.flag}</span>\n * <span>{info?.nativeName}</span>\n * <span>{info?.dialCode}</span>\n * </div>\n * );\n * }\n * ```\n */\nexport async function getLocaleWithInfo(): Promise<{\n locale: string;\n info: LocaleInfo | undefined;\n}>\n{\n const locale = await getLocale();\n const info = getLocaleInfo(locale);\n\n return { locale, info };\n}\n\n/**\n * 지원하는 모든 locale과 상세 정보 가져오기 (Server Action)\n *\n * 시스템이 지원하는 모든 locale의 상세 정보를 배열로 반환합니다.\n * 언어 선택 UI를 만들 때 유용합니다.\n *\n * @returns LocaleInfo 배열\n *\n * @example\n * ```tsx\n * // Server Component\n * import { getLocalesWithInfo } from '@spfn/cms/actions';\n *\n * export default async function LanguageSelector()\n * {\n * const locales = await getLocalesWithInfo();\n *\n * return (\n * <select>\n * {locales.map(info => (\n * <option key={info.locale} value={info.locale}>\n * {info.flag} {info.nativeName}\n * </option>\n * ))}\n * </select>\n * );\n * }\n * ```\n */\nexport async function getLocalesWithInfo(): Promise<LocaleInfo[]>\n{\n const config = getCmsConfig();\n const supportedLocales = config.supportedLocales;\n\n return supportedLocales\n .map(locale => getLocaleInfo(locale))\n .filter((info): info is LocaleInfo => info !== undefined);\n}","/**\n * CMS Configuration Module\n *\n * 환경변수 기반 CMS 설정 관리\n * - SPFN_CMS_DEFAULT_LOCALE: 기본 언어 (기본값: 'ko')\n * - SPFN_CMS_SUPPORTED_LOCALES: 지원 언어 목록, 쉼표로 구분 (기본값: 'ko,en')\n * - SPFN_CMS_DETECT_BROWSER_LANGUAGE: 브라우저 언어 자동 감지 (기본값: 'false')\n */\n\n/**\n * CMS 설정 타입\n */\nexport interface CmsConfig\n{\n /**\n * 기본 언어 코드\n * @example 'ko', 'en', 'ja'\n */\n defaultLocale: string;\n\n /**\n * 지원하는 언어 목록\n * @example ['ko', 'en', 'ja']\n */\n supportedLocales: string[];\n\n /**\n * 브라우저 언어 자동 감지 여부\n * @default true\n */\n detectBrowserLanguage: boolean;\n}\n\n/**\n * 환경변수 읽기 헬퍼\n */\nfunction getEnvVar(key: string, defaultValue: string): string\n{\n return process.env[key] || defaultValue;\n}\n\n/**\n * 환경변수에서 boolean 읽기\n */\nfunction getEnvBoolean(key: string, defaultValue: boolean): boolean\n{\n const value = process.env[key];\n if (value === undefined) return defaultValue;\n return value === 'true' || value === '1';\n}\n\n/**\n * 환경변수에서 설정 로드\n */\nfunction loadConfigFromEnv(): CmsConfig\n{\n const defaultLocale = getEnvVar('SPFN_CMS_DEFAULT_LOCALE', 'en');\n const supportedLocalesStr = getEnvVar('SPFN_CMS_SUPPORTED_LOCALES', 'en,ko');\n const detectBrowserLanguage = getEnvBoolean('SPFN_CMS_DETECT_BROWSER_LANGUAGE', true);\n\n const supportedLocales = supportedLocalesStr\n .split(',')\n .map(locale => locale.trim())\n .filter(locale => locale.length > 0);\n\n // 기본 언어가 지원 목록에 없으면 추가\n if (!supportedLocales.includes(defaultLocale))\n {\n supportedLocales.unshift(defaultLocale);\n }\n\n return {\n defaultLocale,\n supportedLocales,\n detectBrowserLanguage,\n };\n}\n\n/**\n * 현재 설정 (환경변수에서 초기화)\n */\nlet currentConfig: CmsConfig = loadConfigFromEnv();\n\n/**\n * CMS 설정 조회\n *\n * @returns 현재 CMS 설정\n *\n * @example\n * ```tsx\n * import { getCmsConfig } from '@spfn/cms';\n *\n * const config = getCmsConfig();\n * console.log(config.defaultLocale); // 'ko'\n * console.log(config.supportedLocales); // ['ko', 'en']\n * ```\n */\nexport function getCmsConfig(): Readonly<CmsConfig>\n{\n return currentConfig;\n}\n\n/**\n * CMS 설정 변경 (런타임 오버라이드)\n *\n * 환경변수 설정을 런타임에 오버라이드합니다.\n * 주로 테스트나 특수한 경우에 사용됩니다.\n *\n * @param config - 변경할 설정 (부분 업데이트 가능)\n *\n * @example\n * ```tsx\n * import { configureCms } from '@spfn/cms';\n *\n * // 앱 초기화 시 (선택적)\n * configureCms({\n * defaultLocale: 'en',\n * supportedLocales: ['en', 'ko', 'ja'],\n * detectBrowserLanguage: true,\n * });\n * ```\n */\nexport function configureCms(config: Partial<CmsConfig>): void\n{\n currentConfig = {\n ...currentConfig,\n ...config,\n };\n\n // 기본 언어가 지원 목록에 있는지 확인\n if (config.defaultLocale && !currentConfig.supportedLocales.includes(config.defaultLocale))\n {\n console.warn(\n `[CMS Config] Default locale '${config.defaultLocale}' not in supported locales, adding automatically.`,\n `Supported locales: [${currentConfig.supportedLocales.join(', ')}]`\n );\n\n currentConfig.supportedLocales.unshift(config.defaultLocale);\n }\n}\n\n/**\n * 설정 초기화 (환경변수에서 재로드)\n *\n * @example\n * ```tsx\n * import { resetCmsConfig } from '@spfn/cms';\n *\n * // 환경변수 설정으로 되돌리기\n * resetCmsConfig();\n * ```\n */\nexport function resetCmsConfig(): void\n{\n currentConfig = loadConfigFromEnv();\n}","/**\n * Locale Constants\n *\n * Server/Client 양쪽에서 사용 가능한 locale 관련 상수\n */\n\n/**\n * Locale 쿠키 키\n */\nexport const LOCALE_COOKIE_KEY = 'spfn-locale';\n\n/**\n * 지원하는 Locale 타입 (Type-safe)\n */\nexport type SupportedLocale =\n // 아시아-태평양\n | 'ko' // 한국어\n | 'ja' // 일본어\n | 'zh' // 중국어 (간체)\n | 'zh-TW' // 중국어 (번체, 대만)\n | 'zh-HK' // 중국어 (홍콩)\n | 'hi' // 힌디어\n | 'th' // 태국어\n | 'vi' // 베트남어\n | 'id' // 인도네시아어\n | 'ms' // 말레이어\n // 영어권\n | 'en' // 영어 (미국)\n | 'en-GB' // 영어 (영국)\n | 'en-CA' // 영어 (캐나다)\n | 'en-AU' // 영어 (호주)\n | 'en-NZ' // 영어 (뉴질랜드)\n // 서유럽\n | 'es' // 스페인어 (스페인)\n | 'es-MX' // 스페인어 (멕시코)\n | 'es-AR' // 스페인어 (아르헨티나)\n | 'es-CO' // 스페인어 (콜롬비아)\n | 'fr' // 프랑스어\n | 'de' // 독일어\n | 'it' // 이탈리아어\n | 'pt' // 포르투갈어\n | 'nl' // 네덜란드어\n // 북유럽\n | 'sv' // 스웨덴어\n | 'no' // 노르웨이어\n | 'da' // 덴마크어\n | 'fi' // 핀란드어\n // 동유럽\n | 'ru' // 러시아어\n | 'pl' // 폴란드어\n | 'uk' // 우크라이나어\n | 'cs' // 체코어\n | 'hu' // 헝가리어\n | 'ro' // 루마니아어\n | 'bg' // 불가리아어\n | 'hr' // 크로아티아어\n | 'sr' // 세르비아어\n | 'sk' // 슬로바키아어\n | 'sl' // 슬로베니아어\n | 'lt' // 리투아니아어\n | 'lv' // 라트비아어\n | 'et' // 에스토니아어\n // 남유럽\n | 'el' // 그리스어\n // 중동\n | 'tr' // 터키어\n | 'ar' // 아랍어\n | 'fa' // 페르시아어\n | 'he' // 히브리어\n // 아프리카\n | 'sw'; // 스와힐리어\n\n/**\n * 국가/지역 정보 타입\n */\nexport interface LocaleInfo\n{\n /** Locale 코드 (ISO 639-1) */\n locale: SupportedLocale;\n /** 국가 코드 (ISO 3166-1 alpha-2) */\n countryCode: string;\n /** 국기 이모지 (HTML/React용) */\n flag: string;\n /** 전화번호 국가 코드 */\n dialCode: string;\n /** 네이티브 이름 (현지어) */\n nativeName: string;\n /** 영어 이름 */\n englishName: string;\n /** RTL (Right-to-Left) 여부 */\n rtl?: boolean;\n /** 통화 코드 (ISO 4217) */\n currencyCode?: string;\n /** 날짜 형식 예시 */\n dateFormat?: string;\n}\n\n/**\n * 사전 정의된 Locale 정보 맵\n *\n * 주요 언어/국가 정보를 포함합니다.\n * 프로젝트에 맞게 추가/수정 가능합니다.\n */\nexport const LOCALE_INFO_MAP: Record<SupportedLocale, LocaleInfo> = {\n // 한국어\n ko: {\n locale: 'ko',\n countryCode: 'KR',\n flag: '🇰🇷',\n dialCode: '+82',\n nativeName: '한국어',\n englishName: 'Korean',\n currencyCode: 'KRW',\n dateFormat: 'YYYY.MM.DD',\n },\n\n // 영어 (미국)\n en: {\n locale: 'en',\n countryCode: 'US',\n flag: '🇺🇸',\n dialCode: '+1',\n nativeName: 'English',\n englishName: 'English',\n currencyCode: 'USD',\n dateFormat: 'MM/DD/YYYY',\n },\n\n // 일본어\n ja: {\n locale: 'ja',\n countryCode: 'JP',\n flag: '🇯🇵',\n dialCode: '+81',\n nativeName: '日本語',\n englishName: 'Japanese',\n currencyCode: 'JPY',\n dateFormat: 'YYYY/MM/DD',\n },\n\n // 중국어 (간체)\n zh: {\n locale: 'zh',\n countryCode: 'CN',\n flag: '🇨🇳',\n dialCode: '+86',\n nativeName: '简体中文',\n englishName: 'Chinese (Simplified)',\n currencyCode: 'CNY',\n dateFormat: 'YYYY-MM-DD',\n },\n\n // 중국어 (번체, 대만)\n 'zh-TW': {\n locale: 'zh-TW',\n countryCode: 'TW',\n flag: '🇹🇼',\n dialCode: '+886',\n nativeName: '繁體中文',\n englishName: 'Chinese (Traditional)',\n currencyCode: 'TWD',\n dateFormat: 'YYYY/MM/DD',\n },\n\n // 스페인어\n es: {\n locale: 'es',\n countryCode: 'ES',\n flag: '🇪🇸',\n dialCode: '+34',\n nativeName: 'Español',\n englishName: 'Spanish',\n currencyCode: 'EUR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 프랑스어\n fr: {\n locale: 'fr',\n countryCode: 'FR',\n flag: '🇫🇷',\n dialCode: '+33',\n nativeName: 'Français',\n englishName: 'French',\n currencyCode: 'EUR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 독일어\n de: {\n locale: 'de',\n countryCode: 'DE',\n flag: '🇩🇪',\n dialCode: '+49',\n nativeName: 'Deutsch',\n englishName: 'German',\n currencyCode: 'EUR',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 이탈리아어\n it: {\n locale: 'it',\n countryCode: 'IT',\n flag: '🇮🇹',\n dialCode: '+39',\n nativeName: 'Italiano',\n englishName: 'Italian',\n currencyCode: 'EUR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 포르투갈어 (브라질)\n pt: {\n locale: 'pt',\n countryCode: 'BR',\n flag: '🇧🇷',\n dialCode: '+55',\n nativeName: 'Português',\n englishName: 'Portuguese',\n currencyCode: 'BRL',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 러시아어\n ru: {\n locale: 'ru',\n countryCode: 'RU',\n flag: '🇷🇺',\n dialCode: '+7',\n nativeName: 'Русский',\n englishName: 'Russian',\n currencyCode: 'RUB',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 아랍어\n ar: {\n locale: 'ar',\n countryCode: 'SA',\n flag: '🇸🇦',\n dialCode: '+966',\n nativeName: 'العربية',\n englishName: 'Arabic',\n rtl: true,\n currencyCode: 'SAR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 힌디어\n hi: {\n locale: 'hi',\n countryCode: 'IN',\n flag: '🇮🇳',\n dialCode: '+91',\n nativeName: 'हिन्दी',\n englishName: 'Hindi',\n currencyCode: 'INR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 태국어\n th: {\n locale: 'th',\n countryCode: 'TH',\n flag: '🇹🇭',\n dialCode: '+66',\n nativeName: 'ไทย',\n englishName: 'Thai',\n currencyCode: 'THB',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 베트남어\n vi: {\n locale: 'vi',\n countryCode: 'VN',\n flag: '🇻🇳',\n dialCode: '+84',\n nativeName: 'Tiếng Việt',\n englishName: 'Vietnamese',\n currencyCode: 'VND',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 인도네시아어\n id: {\n locale: 'id',\n countryCode: 'ID',\n flag: '🇮🇩',\n dialCode: '+62',\n nativeName: 'Bahasa Indonesia',\n englishName: 'Indonesian',\n currencyCode: 'IDR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 터키어\n tr: {\n locale: 'tr',\n countryCode: 'TR',\n flag: '🇹🇷',\n dialCode: '+90',\n nativeName: 'Türkçe',\n englishName: 'Turkish',\n currencyCode: 'TRY',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 폴란드어\n pl: {\n locale: 'pl',\n countryCode: 'PL',\n flag: '🇵🇱',\n dialCode: '+48',\n nativeName: 'Polski',\n englishName: 'Polish',\n currencyCode: 'PLN',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 네덜란드어\n nl: {\n locale: 'nl',\n countryCode: 'NL',\n flag: '🇳🇱',\n dialCode: '+31',\n nativeName: 'Nederlands',\n englishName: 'Dutch',\n currencyCode: 'EUR',\n dateFormat: 'DD-MM-YYYY',\n },\n\n // 중국어 (홍콩)\n 'zh-HK': {\n locale: 'zh-HK',\n countryCode: 'HK',\n flag: '🇭🇰',\n dialCode: '+852',\n nativeName: '繁體中文 (香港)',\n englishName: 'Chinese (Hong Kong)',\n currencyCode: 'HKD',\n dateFormat: 'YYYY/MM/DD',\n },\n\n // 말레이어\n ms: {\n locale: 'ms',\n countryCode: 'MY',\n flag: '🇲🇾',\n dialCode: '+60',\n nativeName: 'Bahasa Melayu',\n englishName: 'Malay',\n currencyCode: 'MYR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 영어 (영국)\n 'en-GB': {\n locale: 'en-GB',\n countryCode: 'GB',\n flag: '🇬🇧',\n dialCode: '+44',\n nativeName: 'English (UK)',\n englishName: 'English (United Kingdom)',\n currencyCode: 'GBP',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 영어 (캐나다)\n 'en-CA': {\n locale: 'en-CA',\n countryCode: 'CA',\n flag: '🇨🇦',\n dialCode: '+1',\n nativeName: 'English (Canada)',\n englishName: 'English (Canada)',\n currencyCode: 'CAD',\n dateFormat: 'YYYY-MM-DD',\n },\n\n // 영어 (호주)\n 'en-AU': {\n locale: 'en-AU',\n countryCode: 'AU',\n flag: '🇦🇺',\n dialCode: '+61',\n nativeName: 'English (Australia)',\n englishName: 'English (Australia)',\n currencyCode: 'AUD',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 영어 (뉴질랜드)\n 'en-NZ': {\n locale: 'en-NZ',\n countryCode: 'NZ',\n flag: '🇳🇿',\n dialCode: '+64',\n nativeName: 'English (New Zealand)',\n englishName: 'English (New Zealand)',\n currencyCode: 'NZD',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 스페인어 (멕시코)\n 'es-MX': {\n locale: 'es-MX',\n countryCode: 'MX',\n flag: '🇲🇽',\n dialCode: '+52',\n nativeName: 'Español (México)',\n englishName: 'Spanish (Mexico)',\n currencyCode: 'MXN',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 스페인어 (아르헨티나)\n 'es-AR': {\n locale: 'es-AR',\n countryCode: 'AR',\n flag: '🇦🇷',\n dialCode: '+54',\n nativeName: 'Español (Argentina)',\n englishName: 'Spanish (Argentina)',\n currencyCode: 'ARS',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 스페인어 (콜롬비아)\n 'es-CO': {\n locale: 'es-CO',\n countryCode: 'CO',\n flag: '🇨🇴',\n dialCode: '+57',\n nativeName: 'Español (Colombia)',\n englishName: 'Spanish (Colombia)',\n currencyCode: 'COP',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 스웨덴어\n sv: {\n locale: 'sv',\n countryCode: 'SE',\n flag: '🇸🇪',\n dialCode: '+46',\n nativeName: 'Svenska',\n englishName: 'Swedish',\n currencyCode: 'SEK',\n dateFormat: 'YYYY-MM-DD',\n },\n\n // 노르웨이어\n no: {\n locale: 'no',\n countryCode: 'NO',\n flag: '🇳🇴',\n dialCode: '+47',\n nativeName: 'Norsk',\n englishName: 'Norwegian',\n currencyCode: 'NOK',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 덴마크어\n da: {\n locale: 'da',\n countryCode: 'DK',\n flag: '🇩🇰',\n dialCode: '+45',\n nativeName: 'Dansk',\n englishName: 'Danish',\n currencyCode: 'DKK',\n dateFormat: 'DD-MM-YYYY',\n },\n\n // 핀란드어\n fi: {\n locale: 'fi',\n countryCode: 'FI',\n flag: '🇫🇮',\n dialCode: '+358',\n nativeName: 'Suomi',\n englishName: 'Finnish',\n currencyCode: 'EUR',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 우크라이나어\n uk: {\n locale: 'uk',\n countryCode: 'UA',\n flag: '🇺🇦',\n dialCode: '+380',\n nativeName: 'Українська',\n englishName: 'Ukrainian',\n currencyCode: 'UAH',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 체코어\n cs: {\n locale: 'cs',\n countryCode: 'CZ',\n flag: '🇨🇿',\n dialCode: '+420',\n nativeName: 'Čeština',\n englishName: 'Czech',\n currencyCode: 'CZK',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 헝가리어\n hu: {\n locale: 'hu',\n countryCode: 'HU',\n flag: '🇭🇺',\n dialCode: '+36',\n nativeName: 'Magyar',\n englishName: 'Hungarian',\n currencyCode: 'HUF',\n dateFormat: 'YYYY.MM.DD.',\n },\n\n // 루마니아어\n ro: {\n locale: 'ro',\n countryCode: 'RO',\n flag: '🇷🇴',\n dialCode: '+40',\n nativeName: 'Română',\n englishName: 'Romanian',\n currencyCode: 'RON',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 불가리아어\n bg: {\n locale: 'bg',\n countryCode: 'BG',\n flag: '🇧🇬',\n dialCode: '+359',\n nativeName: 'Български',\n englishName: 'Bulgarian',\n currencyCode: 'BGN',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 크로아티아어\n hr: {\n locale: 'hr',\n countryCode: 'HR',\n flag: '🇭🇷',\n dialCode: '+385',\n nativeName: 'Hrvatski',\n englishName: 'Croatian',\n currencyCode: 'HRK',\n dateFormat: 'DD.MM.YYYY.',\n },\n\n // 세르비아어\n sr: {\n locale: 'sr',\n countryCode: 'RS',\n flag: '🇷🇸',\n dialCode: '+381',\n nativeName: 'Српски',\n englishName: 'Serbian',\n currencyCode: 'RSD',\n dateFormat: 'DD.MM.YYYY.',\n },\n\n // 슬로바키아어\n sk: {\n locale: 'sk',\n countryCode: 'SK',\n flag: '🇸🇰',\n dialCode: '+421',\n nativeName: 'Slovenčina',\n englishName: 'Slovak',\n currencyCode: 'EUR',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 슬로베니아어\n sl: {\n locale: 'sl',\n countryCode: 'SI',\n flag: '🇸🇮',\n dialCode: '+386',\n nativeName: 'Slovenščina',\n englishName: 'Slovenian',\n currencyCode: 'EUR',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 리투아니아어\n lt: {\n locale: 'lt',\n countryCode: 'LT',\n flag: '🇱🇹',\n dialCode: '+370',\n nativeName: 'Lietuvių',\n englishName: 'Lithuanian',\n currencyCode: 'EUR',\n dateFormat: 'YYYY-MM-DD',\n },\n\n // 라트비아어\n lv: {\n locale: 'lv',\n countryCode: 'LV',\n flag: '🇱🇻',\n dialCode: '+371',\n nativeName: 'Latviešu',\n englishName: 'Latvian',\n currencyCode: 'EUR',\n dateFormat: 'DD.MM.YYYY.',\n },\n\n // 에스토니아어\n et: {\n locale: 'et',\n countryCode: 'EE',\n flag: '🇪🇪',\n dialCode: '+372',\n nativeName: 'Eesti',\n englishName: 'Estonian',\n currencyCode: 'EUR',\n dateFormat: 'DD.MM.YYYY',\n },\n\n // 그리스어\n el: {\n locale: 'el',\n countryCode: 'GR',\n flag: '🇬🇷',\n dialCode: '+30',\n nativeName: 'Ελληνικά',\n englishName: 'Greek',\n currencyCode: 'EUR',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 페르시아어\n fa: {\n locale: 'fa',\n countryCode: 'IR',\n flag: '🇮🇷',\n dialCode: '+98',\n nativeName: 'فارسی',\n englishName: 'Persian',\n rtl: true,\n currencyCode: 'IRR',\n dateFormat: 'YYYY/MM/DD',\n },\n\n // 히브리어\n he: {\n locale: 'he',\n countryCode: 'IL',\n flag: '🇮🇱',\n dialCode: '+972',\n nativeName: 'עברית',\n englishName: 'Hebrew',\n rtl: true,\n currencyCode: 'ILS',\n dateFormat: 'DD/MM/YYYY',\n },\n\n // 스와힐리어\n sw: {\n locale: 'sw',\n countryCode: 'KE',\n flag: '🇰🇪',\n dialCode: '+254',\n nativeName: 'Kiswahili',\n englishName: 'Swahili',\n currencyCode: 'KES',\n dateFormat: 'DD/MM/YYYY',\n },\n};\n\n/**\n * Locale 정보 가져오기\n *\n * @param locale - Locale 코드 (예: 'ko', 'en', 'ja')\n * @returns LocaleInfo 또는 undefined\n *\n * @example\n * ```typescript\n * const koInfo = getLocaleInfo('ko');\n * console.log(koInfo.flag); // 🇰🇷\n * console.log(koInfo.dialCode); // +82\n * ```\n */\nexport function getLocaleInfo(locale: string): LocaleInfo | undefined\n{\n return LOCALE_INFO_MAP[locale as SupportedLocale];\n}\n\n/**\n * 지원하는 모든 Locale 목록 가져오기\n *\n * @returns Locale 코드 배열\n */\nexport function getSupportedLocales(): SupportedLocale[]\n{\n return Object.keys(LOCALE_INFO_MAP) as SupportedLocale[];\n}\n\n/**\n * 국기 이모지만 가져오기\n *\n * @param locale - Locale 코드\n * @returns 국기 이모지 또는 빈 문자열\n *\n * @example\n * ```typescript\n * getFlag('ko'); // 🇰🇷\n * getFlag('en'); // 🇺🇸\n * ```\n */\nexport function getFlag(locale: string): string\n{\n return LOCALE_INFO_MAP[locale as SupportedLocale]?.flag ?? '';\n}\n\n/**\n * 전화번호 국가 코드 가져오기\n *\n * @param locale - Locale 코드\n * @returns 전화번호 코드 또는 빈 문자열\n *\n * @example\n * ```typescript\n * getDialCode('ko'); // +82\n * getDialCode('en'); // +1\n * ```\n */\nexport function getDialCode(locale: string): string\n{\n return LOCALE_INFO_MAP[locale as SupportedLocale]?.dialCode ?? '';\n}\n\n/**\n * RTL (Right-to-Left) 여부 확인\n *\n * @param locale - Locale 코드\n * @returns RTL 여부\n *\n * @example\n * ```typescript\n * isRTL('ar'); // true (Arabic)\n * isRTL('ko'); // false (Korean)\n * ```\n */\nexport function isRTL(locale: string): boolean\n{\n return LOCALE_INFO_MAP[locale as SupportedLocale]?.rtl ?? false;\n}"],"mappings":"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","names":["client","client","client","client","client","client","client","client","client","client","Type","client","client","Type","client","state","replaceVariables","detectBrowserLanguage"]}
|
|
@@ -23,6 +23,7 @@ declare const getLabelsContract: {
|
|
|
23
23
|
key: _sinclair_typebox.TString;
|
|
24
24
|
section: _sinclair_typebox.TString;
|
|
25
25
|
type: _sinclair_typebox.TString;
|
|
26
|
+
description: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
26
27
|
publishedVersion: _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TNull]>;
|
|
27
28
|
createdBy: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
28
29
|
createdAt: _sinclair_typebox.TString;
|
|
@@ -74,6 +75,7 @@ declare const getLabelContract: {
|
|
|
74
75
|
key: _sinclair_typebox.TString;
|
|
75
76
|
section: _sinclair_typebox.TString;
|
|
76
77
|
type: _sinclair_typebox.TString;
|
|
78
|
+
description: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
77
79
|
publishedVersion: _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TNull]>;
|
|
78
80
|
createdBy: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
79
81
|
createdAt: _sinclair_typebox.TString;
|
|
@@ -100,6 +102,7 @@ declare const updateLabelContract: {
|
|
|
100
102
|
key: _sinclair_typebox.TString;
|
|
101
103
|
section: _sinclair_typebox.TString;
|
|
102
104
|
type: _sinclair_typebox.TString;
|
|
105
|
+
description: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
103
106
|
publishedVersion: _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TNull]>;
|
|
104
107
|
createdBy: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
105
108
|
createdAt: _sinclair_typebox.TString;
|
|
@@ -138,6 +141,7 @@ declare const getLabelByKeyContract: {
|
|
|
138
141
|
key: _sinclair_typebox.TString;
|
|
139
142
|
section: _sinclair_typebox.TString;
|
|
140
143
|
type: _sinclair_typebox.TString;
|
|
144
|
+
description: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
141
145
|
publishedVersion: _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TNull]>;
|
|
142
146
|
createdBy: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
143
147
|
createdAt: _sinclair_typebox.TString;
|
|
@@ -184,6 +188,7 @@ declare const getAdminLabelContract: {
|
|
|
184
188
|
key: _sinclair_typebox.TString;
|
|
185
189
|
section: _sinclair_typebox.TString;
|
|
186
190
|
type: _sinclair_typebox.TString;
|
|
191
|
+
description: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
187
192
|
publishedVersion: _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TNull]>;
|
|
188
193
|
createdBy: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
189
194
|
createdAt: _sinclair_typebox.TString;
|
|
@@ -212,5 +217,32 @@ declare const getAdminLabelContract: {
|
|
|
212
217
|
error: _sinclair_typebox.TString;
|
|
213
218
|
}>]>;
|
|
214
219
|
};
|
|
220
|
+
/**
|
|
221
|
+
* GET /_cms/labels/:labelId/versions - 라벨 버전 히스토리 조회
|
|
222
|
+
*/
|
|
223
|
+
declare const getLabelVersionsContract: {
|
|
224
|
+
readonly method: "GET";
|
|
225
|
+
readonly path: "/_cms/labels/:labelId/versions";
|
|
226
|
+
readonly params: _sinclair_typebox.TObject<{
|
|
227
|
+
labelId: _sinclair_typebox.TString;
|
|
228
|
+
}>;
|
|
229
|
+
readonly response: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
|
|
230
|
+
versions: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
|
|
231
|
+
version: _sinclair_typebox.TNumber;
|
|
232
|
+
publishedAt: _sinclair_typebox.TString;
|
|
233
|
+
publishedBy: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
234
|
+
notes: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
235
|
+
values: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
|
|
236
|
+
id: _sinclair_typebox.TNumber;
|
|
237
|
+
locale: _sinclair_typebox.TString;
|
|
238
|
+
breakpoint: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
|
|
239
|
+
value: _sinclair_typebox.TAny;
|
|
240
|
+
createdAt: _sinclair_typebox.TString;
|
|
241
|
+
}>>;
|
|
242
|
+
}>>;
|
|
243
|
+
}>, _sinclair_typebox.TObject<{
|
|
244
|
+
error: _sinclair_typebox.TString;
|
|
245
|
+
}>]>;
|
|
246
|
+
};
|
|
215
247
|
|
|
216
|
-
export { createLabelContract, deleteLabelContract, getAdminLabelContract, getLabelByKeyContract, getLabelContract, getLabelsContract, publishLabelContract, updateLabelContract };
|
|
248
|
+
export { createLabelContract, deleteLabelContract, getAdminLabelContract, getLabelByKeyContract, getLabelContract, getLabelVersionsContract, getLabelsContract, publishLabelContract, updateLabelContract };
|