@spfn/cms 0.1.0-alpha.6 → 0.1.0-alpha.60

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.
Files changed (176) hide show
  1. package/dist/actions.d.ts +140 -6
  2. package/dist/actions.js +97 -10
  3. package/dist/actions.js.map +1 -1
  4. package/dist/client.d.ts +43 -9
  5. package/dist/client.js +406 -56
  6. package/dist/client.js.map +1 -1
  7. package/dist/contracts/labels.d.ts +149 -0
  8. package/dist/contracts/labels.js +166 -0
  9. package/dist/contracts/labels.js.map +1 -0
  10. package/dist/contracts/published-cache.d.ts +25 -0
  11. package/dist/contracts/published-cache.js +32 -0
  12. package/dist/contracts/published-cache.js.map +1 -0
  13. package/dist/contracts/values.d.ts +69 -0
  14. package/dist/contracts/values.js +100 -0
  15. package/dist/contracts/values.js.map +1 -0
  16. package/dist/entities/cms-audit-logs.d.ts +15 -70
  17. package/dist/entities/cms-audit-logs.js +75 -100
  18. package/dist/entities/cms-audit-logs.js.map +1 -1
  19. package/dist/entities/cms-draft-cache.d.ts +13 -73
  20. package/dist/entities/cms-draft-cache.js +35 -109
  21. package/dist/entities/cms-draft-cache.js.map +1 -1
  22. package/dist/entities/cms-label-values.d.ts +14 -65
  23. package/dist/entities/cms-label-values.js +78 -102
  24. package/dist/entities/cms-label-values.js.map +1 -1
  25. package/dist/entities/cms-label-versions.d.ts +16 -49
  26. package/dist/entities/cms-label-versions.js +73 -77
  27. package/dist/entities/cms-label-versions.js.map +1 -1
  28. package/dist/entities/cms-labels.d.ts +17 -14
  29. package/dist/entities/cms-labels.js +39 -45
  30. package/dist/entities/cms-labels.js.map +1 -1
  31. package/dist/entities/cms-published-cache.d.ts +14 -69
  32. package/dist/entities/cms-published-cache.js +33 -100
  33. package/dist/entities/cms-published-cache.js.map +1 -1
  34. package/dist/entities/index.d.ts +7 -10
  35. package/dist/entities/index.js +217 -9
  36. package/dist/entities/index.js.map +1 -1
  37. package/dist/generators/index.d.ts +8 -7
  38. package/dist/generators/index.js +657 -17
  39. package/dist/generators/index.js.map +1 -1
  40. package/dist/index.d.ts +134 -20
  41. package/dist/index.js +1115 -23
  42. package/dist/index.js.map +1 -1
  43. package/dist/{generators/label-sync-generator.d.ts → label-sync-generator-lQrcVfja.d.ts} +9 -6
  44. package/dist/labels/index.d.ts +31 -4
  45. package/dist/labels/index.js +31 -6
  46. package/dist/labels/index.js.map +1 -1
  47. package/dist/repositories/index.d.ts +205 -6
  48. package/dist/repositories/index.js +435 -8
  49. package/dist/repositories/index.js.map +1 -1
  50. package/dist/routes/labels/[id]/index.js +499 -89
  51. package/dist/routes/labels/[id]/index.js.map +1 -1
  52. package/dist/routes/labels/{[id] → _id_}/index.d.ts +5 -3
  53. package/dist/routes/labels/by-key/[key]/index.js +453 -29
  54. package/dist/routes/labels/by-key/[key]/index.js.map +1 -1
  55. package/dist/routes/labels/by-key/_key_/index.d.ts +10 -0
  56. package/dist/routes/labels/index.d.ts +5 -3
  57. package/dist/routes/labels/index.js +488 -68
  58. package/dist/routes/labels/index.js.map +1 -1
  59. package/dist/routes/published-cache/index.d.ts +5 -3
  60. package/dist/routes/published-cache/index.js +325 -30
  61. package/dist/routes/published-cache/index.js.map +1 -1
  62. package/dist/routes/values/[labelId]/[version]/index.js +467 -41
  63. package/dist/routes/values/[labelId]/[version]/index.js.map +1 -1
  64. package/dist/routes/values/[labelId]/index.js +463 -39
  65. package/dist/routes/values/[labelId]/index.js.map +1 -1
  66. package/dist/routes/values/_labelId_/_version_/index.d.ts +10 -0
  67. package/dist/routes/values/_labelId_/index.d.ts +10 -0
  68. package/dist/server.d.ts +17 -7
  69. package/dist/server.js +263 -252
  70. package/dist/server.js.map +1 -1
  71. package/dist/store.d.ts +8 -14
  72. package/dist/store.js +396 -198
  73. package/dist/store.js.map +1 -1
  74. package/dist/types.d.ts +14 -7
  75. package/dist/types.js +0 -6
  76. package/dist/types.js.map +1 -1
  77. package/migrations/0000_condemned_centennial.sql +89 -0
  78. package/migrations/meta/0000_snapshot.json +687 -0
  79. package/migrations/meta/_journal.json +13 -0
  80. package/package.json +33 -16
  81. package/dist/actions.d.ts.map +0 -1
  82. package/dist/client.d.ts.map +0 -1
  83. package/dist/cms.config.d.ts +0 -77
  84. package/dist/cms.config.d.ts.map +0 -1
  85. package/dist/cms.config.js +0 -111
  86. package/dist/cms.config.js.map +0 -1
  87. package/dist/entities/cms-audit-logs.d.ts.map +0 -1
  88. package/dist/entities/cms-draft-cache.d.ts.map +0 -1
  89. package/dist/entities/cms-label-values.d.ts.map +0 -1
  90. package/dist/entities/cms-label-versions.d.ts.map +0 -1
  91. package/dist/entities/cms-labels.d.ts.map +0 -1
  92. package/dist/entities/cms-published-cache.d.ts.map +0 -1
  93. package/dist/entities/index.d.ts.map +0 -1
  94. package/dist/generators/index.d.ts.map +0 -1
  95. package/dist/generators/label-sync-generator.d.ts.map +0 -1
  96. package/dist/generators/label-sync-generator.js +0 -87
  97. package/dist/generators/label-sync-generator.js.map +0 -1
  98. package/dist/helpers/locale.actions.d.ts +0 -132
  99. package/dist/helpers/locale.actions.d.ts.map +0 -1
  100. package/dist/helpers/locale.actions.js +0 -210
  101. package/dist/helpers/locale.actions.js.map +0 -1
  102. package/dist/helpers/locale.constants.d.ts +0 -10
  103. package/dist/helpers/locale.constants.d.ts.map +0 -1
  104. package/dist/helpers/locale.constants.js +0 -10
  105. package/dist/helpers/locale.constants.js.map +0 -1
  106. package/dist/helpers/locale.d.ts +0 -17
  107. package/dist/helpers/locale.d.ts.map +0 -1
  108. package/dist/helpers/locale.js +0 -20
  109. package/dist/helpers/locale.js.map +0 -1
  110. package/dist/helpers/sync.d.ts +0 -41
  111. package/dist/helpers/sync.d.ts.map +0 -1
  112. package/dist/helpers/sync.js +0 -309
  113. package/dist/helpers/sync.js.map +0 -1
  114. package/dist/index.d.ts.map +0 -1
  115. package/dist/init.d.ts +0 -31
  116. package/dist/init.d.ts.map +0 -1
  117. package/dist/init.js +0 -36
  118. package/dist/init.js.map +0 -1
  119. package/dist/labels/helpers.d.ts +0 -31
  120. package/dist/labels/helpers.d.ts.map +0 -1
  121. package/dist/labels/helpers.js +0 -60
  122. package/dist/labels/helpers.js.map +0 -1
  123. package/dist/labels/index.d.ts.map +0 -1
  124. package/dist/repositories/cms-draft-cache.repository.d.ts +0 -62
  125. package/dist/repositories/cms-draft-cache.repository.d.ts.map +0 -1
  126. package/dist/repositories/cms-draft-cache.repository.js +0 -56
  127. package/dist/repositories/cms-draft-cache.repository.js.map +0 -1
  128. package/dist/repositories/cms-label-values.repository.d.ts +0 -32
  129. package/dist/repositories/cms-label-values.repository.d.ts.map +0 -1
  130. package/dist/repositories/cms-label-values.repository.js +0 -72
  131. package/dist/repositories/cms-label-values.repository.js.map +0 -1
  132. package/dist/repositories/cms-labels.repository.d.ts +0 -53
  133. package/dist/repositories/cms-labels.repository.d.ts.map +0 -1
  134. package/dist/repositories/cms-labels.repository.js +0 -77
  135. package/dist/repositories/cms-labels.repository.js.map +0 -1
  136. package/dist/repositories/cms-published-cache.repository.d.ts +0 -53
  137. package/dist/repositories/cms-published-cache.repository.d.ts.map +0 -1
  138. package/dist/repositories/cms-published-cache.repository.js +0 -54
  139. package/dist/repositories/cms-published-cache.repository.js.map +0 -1
  140. package/dist/repositories/index.d.ts.map +0 -1
  141. package/dist/routes/labels/[id]/contract.d.ts +0 -68
  142. package/dist/routes/labels/[id]/contract.d.ts.map +0 -1
  143. package/dist/routes/labels/[id]/contract.js +0 -84
  144. package/dist/routes/labels/[id]/contract.js.map +0 -1
  145. package/dist/routes/labels/[id]/index.d.ts.map +0 -1
  146. package/dist/routes/labels/by-key/[key]/contract.d.ts +0 -24
  147. package/dist/routes/labels/by-key/[key]/contract.d.ts.map +0 -1
  148. package/dist/routes/labels/by-key/[key]/contract.js +0 -28
  149. package/dist/routes/labels/by-key/[key]/contract.js.map +0 -1
  150. package/dist/routes/labels/by-key/[key]/index.d.ts +0 -8
  151. package/dist/routes/labels/by-key/[key]/index.d.ts.map +0 -1
  152. package/dist/routes/labels/contract.d.ts +0 -59
  153. package/dist/routes/labels/contract.d.ts.map +0 -1
  154. package/dist/routes/labels/contract.js +0 -75
  155. package/dist/routes/labels/contract.js.map +0 -1
  156. package/dist/routes/labels/index.d.ts.map +0 -1
  157. package/dist/routes/published-cache/contract.d.ts +0 -25
  158. package/dist/routes/published-cache/contract.d.ts.map +0 -1
  159. package/dist/routes/published-cache/contract.js +0 -35
  160. package/dist/routes/published-cache/contract.js.map +0 -1
  161. package/dist/routes/published-cache/index.d.ts.map +0 -1
  162. package/dist/routes/values/[labelId]/[version]/contract.d.ts +0 -29
  163. package/dist/routes/values/[labelId]/[version]/contract.d.ts.map +0 -1
  164. package/dist/routes/values/[labelId]/[version]/contract.js +0 -33
  165. package/dist/routes/values/[labelId]/[version]/contract.js.map +0 -1
  166. package/dist/routes/values/[labelId]/[version]/index.d.ts +0 -8
  167. package/dist/routes/values/[labelId]/[version]/index.d.ts.map +0 -1
  168. package/dist/routes/values/[labelId]/contract.d.ts +0 -38
  169. package/dist/routes/values/[labelId]/contract.d.ts.map +0 -1
  170. package/dist/routes/values/[labelId]/contract.js +0 -59
  171. package/dist/routes/values/[labelId]/contract.js.map +0 -1
  172. package/dist/routes/values/[labelId]/index.d.ts +0 -8
  173. package/dist/routes/values/[labelId]/index.d.ts.map +0 -1
  174. package/dist/server.d.ts.map +0 -1
  175. package/dist/store.d.ts.map +0 -1
  176. package/dist/types.d.ts.map +0 -1
package/dist/server.d.ts CHANGED
@@ -1,8 +1,18 @@
1
- import "server-only";
1
+ /**
2
+ * CMS Server Module
3
+ *
4
+ * Next.js 서버 컴포넌트용 CMS 유틸리티
5
+ * - React cache를 사용한 데이터 중복 제거
6
+ * - SPFN API를 통한 contract-based 호출
7
+ * - 변수 치환 지원
8
+ * - 쿠키 기반 locale 자동 관리
9
+ *
10
+ * @note This module should only be imported in server-side code
11
+ */
2
12
  /**
3
13
  * Section Data Type
4
14
  */
5
- export type SectionData = {
15
+ type SectionData = {
6
16
  section: string;
7
17
  locale: string;
8
18
  content: Record<string, any>;
@@ -16,7 +26,7 @@ type ServerTranslationFunction = (key: string, defaultValue?: any, replace?: Rec
16
26
  /**
17
27
  * Section API Return Type
18
28
  */
19
- export type SectionAPI = {
29
+ type SectionAPI = {
20
30
  /**
21
31
  * 라벨 값 가져오기 (변수 치환 지원)
22
32
  *
@@ -63,7 +73,7 @@ export type SectionAPI = {
63
73
  * }
64
74
  * ```
65
75
  */
66
- export declare const getSection: (section: string, locale?: string) => Promise<SectionAPI>;
76
+ declare const getSection: (section: string, locale?: string) => Promise<SectionAPI>;
67
77
  /**
68
78
  * 여러 섹션 한번에 로드 (React cache 적용)
69
79
  * 단일 API 호출로 여러 섹션을 효율적으로 가져옵니다
@@ -94,6 +104,6 @@ export declare const getSection: (section: string, locale?: string) => Promise<S
94
104
  * }
95
105
  * ```
96
106
  */
97
- export declare const getSections: (sections: string[], locale?: string) => Promise<Record<string, SectionAPI>>;
98
- export {};
99
- //# sourceMappingURL=server.d.ts.map
107
+ declare const getSections: (sections: string[], locale?: string) => Promise<Record<string, SectionAPI>>;
108
+
109
+ export { type SectionAPI, type SectionData, getSection, getSections };
package/dist/server.js CHANGED
@@ -1,264 +1,275 @@
1
- import "server-only";
2
- /**
3
- * CMS Server Module
4
- *
5
- * Next.js 서버 컴포넌트용 CMS 유틸리티
6
- * - React cache를 사용한 데이터 중복 제거
7
- * - SPFN API를 통한 contract-based 호출
8
- * - 변수 치환 지원
9
- * - 쿠키 기반 locale 자동 관리
10
- */
11
- import { cache } from 'react';
12
- import { client } from '@spfn/core/client';
13
- import { getPublishedCacheContract } from './routes/published-cache/contract.js';
14
- import { getLocale } from './helpers/locale.actions.js';
15
- /**
16
- * 변수 치환 헬퍼
17
- *
18
- * @param text - 치환할 텍스트 (예: 'Hello {name}!')
19
- * @param replace - 치환 맵 (예: { name: 'World' })
20
- * @returns 치환된 텍스트 (예: 'Hello World!')
21
- */
22
- function replaceVariables(text, replace) {
23
- return text.replace(/\{(\w+)}/g, (match, key) => {
24
- const value = replace[key];
25
- return value !== undefined ? String(value) : match;
1
+ // src/server.ts
2
+ import { cache } from "react";
3
+ import { client } from "@spfn/core/client";
4
+
5
+ // src/contracts/published-cache.ts
6
+ import { Type } from "@sinclair/typebox";
7
+ var SectionData = Type.Object({
8
+ section: Type.String(),
9
+ locale: Type.String(),
10
+ content: Type.Record(Type.String(), Type.Any()),
11
+ version: Type.Number(),
12
+ publishedAt: Type.Union([Type.String(), Type.Null()])
13
+ });
14
+ var getPublishedCacheContract = {
15
+ method: "GET",
16
+ path: "/cms/published-cache",
17
+ query: Type.Object({
18
+ sections: Type.Union([
19
+ Type.String({ description: "\uB2E8\uC77C \uC139\uC158 \uC774\uB984 (\uC608: home)" }),
20
+ Type.Array(Type.String(), { description: '\uC5EC\uB7EC \uC139\uC158 \uC774\uB984 (\uC608: ["home", "footer"])' })
21
+ ]),
22
+ locale: Type.Optional(Type.String({ default: "ko", description: "\uC5B8\uC5B4 \uCF54\uB4DC" }))
23
+ }),
24
+ response: Type.Union([
25
+ // 성공: 항상 배열로 반환
26
+ Type.Array(SectionData),
27
+ // 에러
28
+ Type.Object({
29
+ error: Type.String()
30
+ })
31
+ ])
32
+ };
33
+
34
+ // src/helpers/locale.actions.ts
35
+ import { cookies, headers } from "next/headers.js";
36
+
37
+ // src/cms.config.ts
38
+ function getEnvVar(key, defaultValue) {
39
+ return process.env[key] || defaultValue;
40
+ }
41
+ function getEnvBoolean(key, defaultValue) {
42
+ const value = process.env[key];
43
+ if (value === void 0) return defaultValue;
44
+ return value === "true" || value === "1";
45
+ }
46
+ function loadConfigFromEnv() {
47
+ const defaultLocale = getEnvVar("SPFN_CMS_DEFAULT_LOCALE", "en");
48
+ const supportedLocalesStr = getEnvVar("SPFN_CMS_SUPPORTED_LOCALES", "en,ko");
49
+ const detectBrowserLanguage2 = getEnvBoolean("SPFN_CMS_DETECT_BROWSER_LANGUAGE", true);
50
+ const supportedLocales = supportedLocalesStr.split(",").map((locale) => locale.trim()).filter((locale) => locale.length > 0);
51
+ if (!supportedLocales.includes(defaultLocale)) {
52
+ supportedLocales.unshift(defaultLocale);
53
+ }
54
+ return {
55
+ defaultLocale,
56
+ supportedLocales,
57
+ detectBrowserLanguage: detectBrowserLanguage2
58
+ };
59
+ }
60
+ var currentConfig = loadConfigFromEnv();
61
+ function getCmsConfig() {
62
+ return currentConfig;
63
+ }
64
+
65
+ // src/helpers/locale.constants.ts
66
+ var LOCALE_COOKIE_KEY = "spfn-locale";
67
+
68
+ // src/helpers/locale.actions.ts
69
+ async function detectBrowserLanguage() {
70
+ try {
71
+ const headersList = await headers();
72
+ const acceptLanguage = headersList.get("accept-language");
73
+ if (!acceptLanguage) {
74
+ return null;
75
+ }
76
+ const languages = acceptLanguage.split(",").map((lang) => {
77
+ const [code] = lang.split(";");
78
+ return code.split("-")[0].trim();
26
79
  });
80
+ const config = getCmsConfig();
81
+ for (const lang of languages) {
82
+ if (config.supportedLocales.includes(lang)) {
83
+ return lang;
84
+ }
85
+ }
86
+ return null;
87
+ } catch (error) {
88
+ return null;
89
+ }
27
90
  }
28
- /**
29
- * 섹션 데이터 로드 (React cache 적용)
30
- *
31
- * 동일한 요청 내에서 같은 섹션을 여러 번 요청해도 한 번만 API 호출
32
- *
33
- * @param section - 섹션 이름 (예: 'home', 'why-futureplay')
34
- * @param locale - 언어 코드 (선택, 미지정시 쿠키에서 자동 조회)
35
- * @returns Section API ({ t, data })
36
- *
37
- * @example
38
- * ```tsx
39
- * // Server Component
40
- * import { getSection } from '@spfn/cms/server';
41
- *
42
- * export default async function HomePage()
43
- * {
44
- * // locale을 지정하지 않으면 쿠키에서 자동으로 가져옴
45
- * const { t } = await getSection('home');
46
- *
47
- * // 또는 명시적으로 locale 지정
48
- * const { t: tEn } = await getSection('home', 'en');
49
- *
50
- * return (
51
- * <div>
52
- * <h1>{t('hero.title')}</h1>
53
- * <p>{t('hero.subtitle', 'Default Subtitle')}</p>
54
- * <p>{t('hero.greeting', 'Hello {name}!', { name: 'World' })}</p>
55
- * </div>
56
- * );
57
- * }
58
- * ```
59
- */
60
- export const getSection = cache(async (section, locale) => {
61
- // locale이 지정되지 않으면 쿠키에서 가져옴
62
- const actualLocale = locale ?? await getLocale();
63
- try {
64
- // Call SPFN API via contract (uses singleton client)
65
- const response = await client.call('/cms/published-cache', getPublishedCacheContract, {
66
- query: { sections: section, locale: actualLocale },
67
- });
68
- // Check if response has error
69
- if ('error' in response) {
70
- console.warn(`[CMS] ${response.error}`);
71
- // Return empty section data
72
- const sectionData = {
73
- section,
74
- locale: actualLocale,
75
- content: {},
76
- version: 0,
77
- publishedAt: null,
78
- };
79
- const t = (_key, defaultValue) => defaultValue ?? '';
80
- return { t, data: sectionData };
81
- }
82
- // Response is an array, get first element
83
- const found = response[0];
84
- if (!found) {
85
- // Section not found, return empty
86
- const sectionData = {
87
- section,
88
- locale: actualLocale,
89
- content: {},
90
- version: 0,
91
- publishedAt: null,
92
- };
93
- const t = (_key, defaultValue) => defaultValue ?? '';
94
- return { t, data: sectionData };
95
- }
96
- // Success response
97
- const sectionData = {
98
- section: found.section,
99
- locale: found.locale,
100
- content: found.content || {},
101
- version: found.version,
102
- publishedAt: found.publishedAt,
103
- };
104
- // Translation function
105
- const t = (key, defaultValue, replace) => {
106
- const fullKey = `${section}.${key}`;
107
- let value = sectionData.content[fullKey];
108
- if (value === undefined || value === null) {
109
- value = defaultValue ?? '';
110
- }
111
- // 문자열이 아니면 빈 문자열 반환
112
- if (typeof value !== 'string') {
113
- return '';
114
- }
115
- // 문자열이고 치환 맵이 있으면 변수 치환
116
- if (replace) {
117
- value = replaceVariables(value, replace);
118
- }
119
- return value;
120
- };
121
- return {
122
- t,
123
- data: sectionData,
124
- };
91
+ async function getLocale() {
92
+ const config = getCmsConfig();
93
+ const cookieStore = await cookies();
94
+ const cookieLocale = cookieStore.get(LOCALE_COOKIE_KEY)?.value;
95
+ if (cookieLocale && config.supportedLocales.includes(cookieLocale)) {
96
+ return cookieLocale;
97
+ }
98
+ if (config.detectBrowserLanguage) {
99
+ const browserLang = await detectBrowserLanguage();
100
+ if (browserLang) {
101
+ return browserLang;
102
+ }
103
+ }
104
+ return config.defaultLocale;
105
+ }
106
+
107
+ // src/server.ts
108
+ function replaceVariables(text, replace) {
109
+ return text.replace(/\{(\w+)}/g, (match, key) => {
110
+ const value = replace[key];
111
+ return value !== void 0 ? String(value) : match;
112
+ });
113
+ }
114
+ var getSection = cache(async (section, locale) => {
115
+ const actualLocale = locale ?? await getLocale();
116
+ try {
117
+ const response = await client.call(
118
+ getPublishedCacheContract,
119
+ {
120
+ query: { sections: section, locale: actualLocale }
121
+ }
122
+ );
123
+ if ("error" in response) {
124
+ console.warn(`[CMS] ${response.error}`);
125
+ const sectionData2 = {
126
+ section,
127
+ locale: actualLocale,
128
+ content: {},
129
+ version: 0,
130
+ publishedAt: null
131
+ };
132
+ const t2 = (_key, defaultValue) => defaultValue ?? "";
133
+ return { t: t2, data: sectionData2 };
134
+ }
135
+ const found = response[0];
136
+ if (!found) {
137
+ const sectionData2 = {
138
+ section,
139
+ locale: actualLocale,
140
+ content: {},
141
+ version: 0,
142
+ publishedAt: null
143
+ };
144
+ const t2 = (_key, defaultValue) => defaultValue ?? "";
145
+ return { t: t2, data: sectionData2 };
125
146
  }
126
- catch (error) {
127
- console.error(`[CMS] Failed to fetch section "${section}":`, error);
128
- // Return empty section data on error
129
- const sectionData = {
147
+ const sectionData = {
148
+ section: found.section,
149
+ locale: found.locale,
150
+ content: found.content || {},
151
+ version: found.version,
152
+ publishedAt: found.publishedAt
153
+ };
154
+ const t = (key, defaultValue, replace) => {
155
+ const fullKey = `${section}.${key}`;
156
+ let value = sectionData.content[fullKey];
157
+ if (value === void 0 || value === null) {
158
+ value = defaultValue ?? "";
159
+ }
160
+ if (typeof value !== "string") {
161
+ return "";
162
+ }
163
+ if (replace) {
164
+ value = replaceVariables(value, replace);
165
+ }
166
+ return value;
167
+ };
168
+ return {
169
+ t,
170
+ data: sectionData
171
+ };
172
+ } catch (error) {
173
+ console.error(`[CMS] Failed to fetch section "${section}":`, error);
174
+ const sectionData = {
175
+ section,
176
+ locale: actualLocale,
177
+ content: {},
178
+ version: 0,
179
+ publishedAt: null
180
+ };
181
+ const t = (_key, defaultValue) => defaultValue ?? "";
182
+ return { t, data: sectionData };
183
+ }
184
+ });
185
+ var getSections = cache(async (sections, locale) => {
186
+ const actualLocale = locale ?? await getLocale();
187
+ try {
188
+ const response = await client.call(
189
+ getPublishedCacheContract,
190
+ {
191
+ query: { sections, locale: actualLocale }
192
+ }
193
+ );
194
+ if ("error" in response) {
195
+ console.warn(`[CMS] ${response.error}`);
196
+ const sectionsMap2 = {};
197
+ sections.forEach((section) => {
198
+ sectionsMap2[section] = {
199
+ t: (_key, defaultValue) => defaultValue ?? "",
200
+ data: {
130
201
  section,
131
202
  locale: actualLocale,
132
203
  content: {},
133
204
  version: 0,
134
- publishedAt: null,
205
+ publishedAt: null
206
+ }
135
207
  };
136
- const t = (_key, defaultValue) => defaultValue ?? '';
137
- return { t, data: sectionData };
208
+ });
209
+ return sectionsMap2;
138
210
  }
139
- });
140
- /**
141
- * 여러 섹션 한번에 로드 (React cache 적용)
142
- * 단일 API 호출로 여러 섹션을 효율적으로 가져옵니다
143
- *
144
- * @param sections - 섹션 이름 배열
145
- * @param locale - 언어 코드 (선택, 미지정시 쿠키에서 자동 조회)
146
- * @returns Section API 맵 ({ home: { t, data }, ... })
147
- *
148
- * @example
149
- * ```tsx
150
- * // Server Component
151
- * import { getSections } from '@spfn/cms/server';
152
- *
153
- * export default async function Page()
154
- * {
155
- * // locale을 지정하지 않으면 쿠키에서 자동으로 가져옴
156
- * const sections = await getSections(['home', 'why-futureplay']);
157
- *
158
- * // 또는 명시적으로 locale 지정
159
- * const sectionsEn = await getSections(['home', 'why-futureplay'], 'en');
160
- *
161
- * return (
162
- * <div>
163
- * <h1>{sections.home.t('hero.title')}</h1>
164
- * <p>{sections['why-futureplay'].t('intro.text')}</p>
165
- * </div>
166
- * );
167
- * }
168
- * ```
169
- */
170
- export const getSections = cache(async (sections, locale) => {
171
- // locale이 지정되지 않으면 쿠키에서 가져옴
172
- const actualLocale = locale ?? await getLocale();
173
- try {
174
- // Call SPFN API with array of sections (single HTTP request)
175
- const response = await client.call('/cms/published-cache', getPublishedCacheContract, {
176
- query: { sections, locale: actualLocale },
177
- });
178
- // Check if response has error
179
- if ('error' in response) {
180
- console.warn(`[CMS] ${response.error}`);
181
- // Return empty sections
182
- const sectionsMap = {};
183
- sections.forEach(section => {
184
- sectionsMap[section] = {
185
- t: (_key, defaultValue) => defaultValue ?? '',
186
- data: {
187
- section,
188
- locale: actualLocale,
189
- content: {},
190
- version: 0,
191
- publishedAt: null,
192
- }
193
- };
194
- });
195
- return sectionsMap;
211
+ const sectionsMap = {};
212
+ sections.forEach((section) => {
213
+ sectionsMap[section] = {
214
+ t: (_key, defaultValue) => defaultValue ?? "",
215
+ data: {
216
+ section,
217
+ locale: actualLocale,
218
+ content: {},
219
+ version: 0,
220
+ publishedAt: null
196
221
  }
197
- // Build sections map from response
198
- const sectionsMap = {};
199
- // First, create empty entries for all requested sections
200
- sections.forEach(section => {
201
- sectionsMap[section] = {
202
- t: (_key, defaultValue) => defaultValue ?? '',
203
- data: {
204
- section,
205
- locale: actualLocale,
206
- content: {},
207
- version: 0,
208
- publishedAt: null,
209
- }
210
- };
211
- });
212
- // Then, fill in data for found sections
213
- response.forEach(sectionData => {
214
- const createTranslationFn = (section, content) => {
215
- return (key, defaultValue, replace) => {
216
- const fullKey = `${section}.${key}`;
217
- let value = content[fullKey];
218
- if (value === undefined || value === null) {
219
- value = defaultValue ?? '';
220
- }
221
- // 문자열이 아니면 빈 문자열 반환
222
- if (typeof value !== 'string') {
223
- return '';
224
- }
225
- // 문자열이고 치환 맵이 있으면 변수 치환
226
- if (replace) {
227
- value = replaceVariables(value, replace);
228
- }
229
- return value;
230
- };
231
- };
232
- sectionsMap[sectionData.section] = {
233
- t: createTranslationFn(sectionData.section, sectionData.content),
234
- data: {
235
- section: sectionData.section,
236
- locale: sectionData.locale,
237
- content: sectionData.content,
238
- version: sectionData.version,
239
- publishedAt: sectionData.publishedAt,
240
- }
241
- };
242
- });
243
- return sectionsMap;
244
- }
245
- catch (error) {
246
- console.error(`[CMS] Failed to fetch sections:`, error);
247
- // Return empty sections on error
248
- const sectionsMap = {};
249
- sections.forEach(section => {
250
- sectionsMap[section] = {
251
- t: (_key, defaultValue) => defaultValue ?? '',
252
- data: {
253
- section,
254
- locale: actualLocale,
255
- content: {},
256
- version: 0,
257
- publishedAt: null,
258
- }
259
- };
260
- });
261
- return sectionsMap;
262
- }
222
+ };
223
+ });
224
+ response.forEach((sectionData) => {
225
+ const createTranslationFn = (section, content) => {
226
+ return (key, defaultValue, replace) => {
227
+ const fullKey = `${section}.${key}`;
228
+ let value = content[fullKey];
229
+ if (value === void 0 || value === null) {
230
+ value = defaultValue ?? "";
231
+ }
232
+ if (typeof value !== "string") {
233
+ return "";
234
+ }
235
+ if (replace) {
236
+ value = replaceVariables(value, replace);
237
+ }
238
+ return value;
239
+ };
240
+ };
241
+ sectionsMap[sectionData.section] = {
242
+ t: createTranslationFn(sectionData.section, sectionData.content),
243
+ data: {
244
+ section: sectionData.section,
245
+ locale: sectionData.locale,
246
+ content: sectionData.content,
247
+ version: sectionData.version,
248
+ publishedAt: sectionData.publishedAt
249
+ }
250
+ };
251
+ });
252
+ return sectionsMap;
253
+ } catch (error) {
254
+ console.error(`[CMS] Failed to fetch sections:`, error);
255
+ const sectionsMap = {};
256
+ sections.forEach((section) => {
257
+ sectionsMap[section] = {
258
+ t: (_key, defaultValue) => defaultValue ?? "",
259
+ data: {
260
+ section,
261
+ locale: actualLocale,
262
+ content: {},
263
+ version: 0,
264
+ publishedAt: null
265
+ }
266
+ };
267
+ });
268
+ return sectionsMap;
269
+ }
263
270
  });
271
+ export {
272
+ getSection,
273
+ getSections
274
+ };
264
275
  //# sourceMappingURL=server.js.map