@spfn/cms 0.1.0-alpha.5 → 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 -244
  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/store.d.ts CHANGED
@@ -1,12 +1,6 @@
1
- /**
2
- * CMS Zustand Store
3
- *
4
- * 클라이언트 컴포넌트에서 CMS 사용을 위한 상태 관리
5
- * - 서버에서 초기화된 데이터를 클라이언트로 전달
6
- * - 클라이언트에서 비동기로 로드 가능
7
- * - 서버 API와 동일한 패턴 ({ t } 사용)
8
- */
9
- import type { SectionData } from './server';
1
+ import * as zustand from 'zustand';
2
+ import { SectionData } from './server.js';
3
+
10
4
  interface CmsState {
11
5
  /**
12
6
  * 섹션별 데이터
@@ -38,7 +32,7 @@ interface CmsState {
38
32
  */
39
33
  reset: () => void;
40
34
  }
41
- export declare const useCmsStore: import("zustand").UseBoundStore<import("zustand").StoreApi<CmsState>>;
35
+ declare const useCmsStore: zustand.UseBoundStore<zustand.StoreApi<CmsState>>;
42
36
  /**
43
37
  * 섹션 Hook (서버 API와 동일한 패턴)
44
38
  *
@@ -58,7 +52,7 @@ export declare const useCmsStore: import("zustand").UseBoundStore<import("zustan
58
52
  * }
59
53
  * ```
60
54
  */
61
- export declare function useSection(section: string, options?: {
55
+ declare function useSection(section: string, options?: {
62
56
  autoLoad?: boolean;
63
57
  locale?: string;
64
58
  }): {
@@ -78,10 +72,10 @@ export declare function useSection(section: string, options?: {
78
72
  * sections.home.t('hero.title');
79
73
  * ```
80
74
  */
81
- export declare function useSections(sectionNames: string[]): Record<string, {
75
+ declare function useSections(sectionNames: string[]): Record<string, {
82
76
  t: (key: string, defaultValue?: any, replace?: Record<string, string | number>) => any;
83
77
  data: SectionData;
84
78
  loading: boolean;
85
79
  }>;
86
- export {};
87
- //# sourceMappingURL=store.d.ts.map
80
+
81
+ export { useCmsStore, useSection, useSections };
package/dist/store.js CHANGED
@@ -1,205 +1,403 @@
1
- /**
2
- * CMS Zustand Store
3
- *
4
- * 클라이언트 컴포넌트에서 CMS 사용을 위한 상태 관리
5
- * - 서버에서 초기화된 데이터를 클라이언트로 전달
6
- * - 클라이언트에서 비동기로 로드 가능
7
- * - 서버 API와 동일한 패턴 ({ t } 사용)
8
- */
9
- 'use client';
10
- import React from 'react';
11
- import { create } from 'zustand';
12
- import { cmsApi } from './client';
13
- /**
14
- * 변수 치환 헬퍼 (서버와 동일)
15
- */
1
+ "use client";
2
+
3
+ // src/store.ts
4
+ import React from "react";
5
+ import { create } from "zustand";
6
+
7
+ // src/client.ts
8
+ import { client } from "@spfn/core/client";
9
+
10
+ // src/contracts/labels.ts
11
+ import { Type } from "@sinclair/typebox";
12
+ var getLabelsContract = {
13
+ method: "GET",
14
+ path: "/cms/labels",
15
+ query: Type.Object({
16
+ section: Type.Optional(Type.String({ description: "\uC139\uC158\uC73C\uB85C \uD544\uD130\uB9C1 (\uC608: home, why-futureplay)" })),
17
+ limit: Type.Optional(Type.Number({ minimum: 1, maximum: 100, default: 20, description: "\uD398\uC774\uC9C0\uB2F9 \uD56D\uBAA9 \uC218" })),
18
+ offset: Type.Optional(Type.Number({ minimum: 0, default: 0, description: "\uC2DC\uC791 \uC624\uD504\uC14B" }))
19
+ }),
20
+ response: Type.Object({
21
+ labels: Type.Array(Type.Object({
22
+ id: Type.Number(),
23
+ key: Type.String(),
24
+ section: Type.String(),
25
+ type: Type.String(),
26
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
27
+ createdBy: Type.Union([Type.String(), Type.Null()]),
28
+ createdAt: Type.String(),
29
+ updatedAt: Type.String()
30
+ })),
31
+ total: Type.Number(),
32
+ limit: Type.Number(),
33
+ offset: Type.Number()
34
+ })
35
+ };
36
+ var createLabelContract = {
37
+ method: "POST",
38
+ path: "/cms/labels",
39
+ body: Type.Object({
40
+ key: Type.String({
41
+ description: "\uACE0\uC720 \uD0A4 (\uC608: home.hero.title)",
42
+ pattern: "^[a-z0-9-]+\\.[a-z0-9-]+\\.[a-z0-9-]+$"
43
+ }),
44
+ section: Type.String({
45
+ description: "\uC139\uC158 \uC774\uB984 (\uC608: home, why-futureplay)",
46
+ pattern: "^[a-z0-9-]+$"
47
+ }),
48
+ type: Type.Union([
49
+ Type.Literal("text"),
50
+ Type.Literal("image"),
51
+ Type.Literal("video"),
52
+ Type.Literal("file"),
53
+ Type.Literal("object")
54
+ ], { description: "\uAC12 \uD0C0\uC785" }),
55
+ createdBy: Type.Optional(Type.String({ description: "\uC0DD\uC131\uC790 ID" }))
56
+ }),
57
+ response: Type.Union([
58
+ Type.Object({
59
+ id: Type.Number(),
60
+ key: Type.String(),
61
+ section: Type.String(),
62
+ type: Type.String(),
63
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
64
+ createdBy: Type.Union([Type.String(), Type.Null()]),
65
+ createdAt: Type.String(),
66
+ updatedAt: Type.String()
67
+ }),
68
+ Type.Object({
69
+ error: Type.String(),
70
+ key: Type.Optional(Type.String())
71
+ })
72
+ ])
73
+ };
74
+ var getLabelContract = {
75
+ method: "GET",
76
+ path: "/cms/labels/:id",
77
+ params: Type.Object({
78
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
79
+ }),
80
+ response: Type.Union([
81
+ Type.Object({
82
+ id: Type.Number(),
83
+ key: Type.String(),
84
+ section: Type.String(),
85
+ type: Type.String(),
86
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
87
+ createdBy: Type.Union([Type.String(), Type.Null()]),
88
+ createdAt: Type.String(),
89
+ updatedAt: Type.String()
90
+ }),
91
+ Type.Object({
92
+ error: Type.String()
93
+ })
94
+ ])
95
+ };
96
+ var updateLabelContract = {
97
+ method: "PATCH",
98
+ path: "/cms/labels/:id",
99
+ params: Type.Object({
100
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
101
+ }),
102
+ body: Type.Object({
103
+ section: Type.Optional(Type.String({ description: "\uC139\uC158 \uBCC0\uACBD" })),
104
+ type: Type.Optional(Type.Union([
105
+ Type.Literal("text"),
106
+ Type.Literal("image"),
107
+ Type.Literal("video"),
108
+ Type.Literal("file"),
109
+ Type.Literal("object")
110
+ ]))
111
+ }),
112
+ response: Type.Union([
113
+ Type.Object({
114
+ id: Type.Number(),
115
+ key: Type.String(),
116
+ section: Type.String(),
117
+ type: Type.String(),
118
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
119
+ createdBy: Type.Union([Type.String(), Type.Null()]),
120
+ createdAt: Type.String(),
121
+ updatedAt: Type.String()
122
+ }),
123
+ Type.Object({
124
+ error: Type.String()
125
+ })
126
+ ])
127
+ };
128
+ var deleteLabelContract = {
129
+ method: "DELETE",
130
+ path: "/cms/labels/:id",
131
+ params: Type.Object({
132
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
133
+ }),
134
+ response: Type.Union([
135
+ Type.Object({
136
+ success: Type.Boolean(),
137
+ id: Type.Number()
138
+ }),
139
+ Type.Object({
140
+ error: Type.String()
141
+ })
142
+ ])
143
+ };
144
+ var getLabelByKeyContract = {
145
+ method: "GET",
146
+ path: "/cms/labels/by-key/:key",
147
+ params: Type.Object({
148
+ key: Type.String({ description: "\uB77C\uBCA8 Key (\uC608: home.hero.title)" })
149
+ }),
150
+ response: Type.Union([
151
+ Type.Object({
152
+ id: Type.Number(),
153
+ key: Type.String(),
154
+ section: Type.String(),
155
+ type: Type.String(),
156
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
157
+ createdBy: Type.Union([Type.String(), Type.Null()]),
158
+ createdAt: Type.String(),
159
+ updatedAt: Type.String()
160
+ }),
161
+ Type.Object({
162
+ error: Type.String(),
163
+ key: Type.Optional(Type.String())
164
+ })
165
+ ])
166
+ };
167
+
168
+ // src/contracts/published-cache.ts
169
+ import { Type as Type2 } from "@sinclair/typebox";
170
+ var SectionData = Type2.Object({
171
+ section: Type2.String(),
172
+ locale: Type2.String(),
173
+ content: Type2.Record(Type2.String(), Type2.Any()),
174
+ version: Type2.Number(),
175
+ publishedAt: Type2.Union([Type2.String(), Type2.Null()])
176
+ });
177
+ var getPublishedCacheContract = {
178
+ method: "GET",
179
+ path: "/cms/published-cache",
180
+ query: Type2.Object({
181
+ sections: Type2.Union([
182
+ Type2.String({ description: "\uB2E8\uC77C \uC139\uC158 \uC774\uB984 (\uC608: home)" }),
183
+ Type2.Array(Type2.String(), { description: '\uC5EC\uB7EC \uC139\uC158 \uC774\uB984 (\uC608: ["home", "footer"])' })
184
+ ]),
185
+ locale: Type2.Optional(Type2.String({ default: "ko", description: "\uC5B8\uC5B4 \uCF54\uB4DC" }))
186
+ }),
187
+ response: Type2.Union([
188
+ // 성공: 항상 배열로 반환
189
+ Type2.Array(SectionData),
190
+ // 에러
191
+ Type2.Object({
192
+ error: Type2.String()
193
+ })
194
+ ])
195
+ };
196
+
197
+ // src/init.tsx
198
+ import { useEffect } from "react";
199
+
200
+ // src/client.ts
201
+ var cmsApi = {
202
+ /**
203
+ * Labels API
204
+ */
205
+ labels: {
206
+ /**
207
+ * GET /cms/labels
208
+ * 라벨 목록 조회 (섹션 필터, 페이지네이션)
209
+ */
210
+ list: (options) => client.call(getLabelsContract, options),
211
+ /**
212
+ * GET /cms/labels/:id
213
+ * 특정 라벨 조회
214
+ */
215
+ getById: (options) => client.call(getLabelContract, options),
216
+ /**
217
+ * POST /cms/labels
218
+ * 새 라벨 생성
219
+ */
220
+ create: (options) => client.call(createLabelContract, options),
221
+ /**
222
+ * PATCH /cms/labels/:id
223
+ * 라벨 업데이트
224
+ */
225
+ update: (options) => client.call(updateLabelContract, options),
226
+ /**
227
+ * DELETE /cms/labels/:id
228
+ * 라벨 삭제
229
+ */
230
+ delete: (options) => client.call(deleteLabelContract, options)
231
+ },
232
+ /**
233
+ * Published Cache API
234
+ */
235
+ publishedCache: {
236
+ /**
237
+ * GET /cms/published-cache
238
+ * 발행된 콘텐츠 캐시 조회
239
+ */
240
+ get: (options) => client.call(getPublishedCacheContract, options)
241
+ }
242
+ };
243
+
244
+ // src/store.ts
16
245
  function replaceVariables(text, replace) {
17
- return text.replace(/\{(\w+)}/g, (match, key) => {
18
- const value = replace[key];
19
- return value !== undefined ? String(value) : match;
20
- });
246
+ return text.replace(/\{(\w+)}/g, (match, key) => {
247
+ const value = replace[key];
248
+ return value !== void 0 ? String(value) : match;
249
+ });
21
250
  }
22
- export const useCmsStore = create((set, get) => ({
23
- sections: {},
24
- loading: {},
25
- setSection: (section, data) => {
26
- set((state) => ({
27
- sections: {
28
- ...state.sections,
29
- [section]: data,
30
- },
31
- }));
32
- },
33
- setSections: (sections) => {
34
- set((state) => ({
35
- sections: {
36
- ...state.sections,
37
- ...sections,
38
- },
39
- }));
40
- },
41
- loadSection: async (section, locale = 'ko') => {
42
- const state = get();
43
- // 이미 로드 중이면 스킵
44
- if (state.loading[section]) {
45
- return;
46
- }
47
- // 이미 로드되어 있으면 스킵
48
- if (state.sections[section]) {
49
- return;
50
- }
51
- set((state) => ({
52
- loading: { ...state.loading, [section]: true },
53
- }));
54
- try {
55
- const response = await cmsApi.publishedCache.get({
56
- query: { sections: section, locale },
57
- });
58
- // Check for error response
59
- if ('error' in response) {
60
- console.error(`Failed to load section ${section}:`, response.error);
61
- return;
62
- }
63
- // Response is array, get first element
64
- const data = response[0];
65
- if (!data) {
66
- console.warn(`Section ${section} not found`);
67
- return;
68
- }
69
- const sectionData = {
70
- section: data.section,
71
- locale: data.locale,
72
- content: data.content || {},
73
- version: data.version || 0,
74
- publishedAt: data.publishedAt || null,
75
- };
76
- set((state) => ({
77
- sections: {
78
- ...state.sections,
79
- [section]: sectionData,
80
- },
81
- loading: { ...state.loading, [section]: false },
82
- }));
251
+ var useCmsStore = create((set, get) => ({
252
+ sections: {},
253
+ loading: {},
254
+ setSection: (section, data) => {
255
+ set((state) => ({
256
+ sections: {
257
+ ...state.sections,
258
+ [section]: data
259
+ }
260
+ }));
261
+ },
262
+ setSections: (sections) => {
263
+ set((state) => ({
264
+ sections: {
265
+ ...state.sections,
266
+ ...sections
267
+ }
268
+ }));
269
+ },
270
+ loadSection: async (section, locale = "ko") => {
271
+ const state = get();
272
+ if (state.loading[section]) {
273
+ return;
274
+ }
275
+ if (state.sections[section]) {
276
+ return;
277
+ }
278
+ set((state2) => ({
279
+ loading: { ...state2.loading, [section]: true }
280
+ }));
281
+ try {
282
+ const response = await cmsApi.publishedCache.get({
283
+ query: { sections: section, locale }
284
+ });
285
+ if ("error" in response) {
286
+ console.error(`Failed to load section ${section}:`, response.error);
287
+ return;
288
+ }
289
+ const data = response[0];
290
+ if (!data) {
291
+ console.warn(`Section ${section} not found`);
292
+ return;
293
+ }
294
+ const sectionData = {
295
+ section: data.section,
296
+ locale: data.locale,
297
+ content: data.content || {},
298
+ version: data.version || 0,
299
+ publishedAt: data.publishedAt || null
300
+ };
301
+ set((state2) => ({
302
+ sections: {
303
+ ...state2.sections,
304
+ [section]: sectionData
305
+ },
306
+ loading: { ...state2.loading, [section]: false }
307
+ }));
308
+ } catch (error) {
309
+ console.error(`Error loading CMS section ${section}:`, error);
310
+ set((state2) => ({
311
+ loading: { ...state2.loading, [section]: false }
312
+ }));
313
+ }
314
+ },
315
+ updateLabel: (section, key, value) => {
316
+ set((state) => ({
317
+ sections: {
318
+ ...state.sections,
319
+ [section]: {
320
+ ...state.sections[section],
321
+ content: {
322
+ ...state.sections[section]?.content,
323
+ [`${section}.${key}`]: value
324
+ }
83
325
  }
84
- catch (error) {
85
- console.error(`Error loading CMS section ${section}:`, error);
86
- set((state) => ({
87
- loading: { ...state.loading, [section]: false },
88
- }));
89
- }
90
- },
91
- updateLabel: (section, key, value) => {
92
- set((state) => ({
93
- sections: {
94
- ...state.sections,
95
- [section]: {
96
- ...state.sections[section],
97
- content: {
98
- ...state.sections[section]?.content,
99
- [`${section}.${key}`]: value,
100
- },
101
- },
102
- },
103
- }));
104
- },
105
- reset: () => {
106
- set({
107
- sections: {},
108
- loading: {},
109
- });
110
- },
326
+ }
327
+ }));
328
+ },
329
+ reset: () => {
330
+ set({
331
+ sections: {},
332
+ loading: {}
333
+ });
334
+ }
111
335
  }));
112
- /**
113
- * 섹션 Hook (서버 API와 동일한 패턴)
114
- *
115
- * @param section - 섹션 이름
116
- * @param options - 옵션 (autoLoad: 자동 로드 여부)
117
- * @returns { t, data, loading }
118
- *
119
- * @example
120
- * ```tsx
121
- * 'use client';
122
- * import { useSection } from '@/lib/cms';
123
- *
124
- * export function ClientComponent()
125
- * {
126
- * const { t } = useSection('home');
127
- * return <h1>{t('hero.title')}</h1>;
128
- * }
129
- * ```
130
- */
131
- export function useSection(section, options = {}) {
132
- const { autoLoad = false, locale = 'ko' } = options;
133
- const sectionData = useCmsStore((state) => state.sections[section]);
134
- const loading = useCmsStore((state) => state.loading[section] ?? false);
135
- const loadSection = useCmsStore((state) => state.loadSection);
136
- // 자동 로드 옵션이 켜져있고 데이터가 없으면 로드
137
- React.useEffect(() => {
138
- if (autoLoad && !sectionData && !loading) {
139
- loadSection(section, locale);
140
- }
141
- }, [autoLoad, section, locale, sectionData, loading, loadSection]);
142
- // Translation function (서버와 동일)
143
- const t = React.useCallback((key, defaultValue, replace) => {
144
- if (!sectionData) {
145
- return defaultValue;
146
- }
147
- const fullKey = `${section}.${key}`;
148
- let value = sectionData.content[fullKey];
149
- if (value === undefined) {
150
- value = defaultValue;
151
- }
152
- // 문자열이고 치환 맵이 있으면 변수 치환
153
- if (typeof value === 'string' && replace) {
154
- value = replaceVariables(value, replace);
155
- }
156
- return value;
157
- }, [section, sectionData]);
158
- return {
159
- t,
160
- data: sectionData,
161
- loading,
162
- };
336
+ function useSection(section, options = {}) {
337
+ const { autoLoad = false, locale = "ko" } = options;
338
+ const sectionData = useCmsStore((state) => state.sections[section]);
339
+ const loading = useCmsStore((state) => state.loading[section] ?? false);
340
+ const loadSection = useCmsStore((state) => state.loadSection);
341
+ React.useEffect(() => {
342
+ if (autoLoad && !sectionData && !loading) {
343
+ loadSection(section, locale);
344
+ }
345
+ }, [autoLoad, section, locale, sectionData, loading, loadSection]);
346
+ const t = React.useCallback(
347
+ (key, defaultValue, replace) => {
348
+ if (!sectionData) {
349
+ return defaultValue;
350
+ }
351
+ const fullKey = `${section}.${key}`;
352
+ let value = sectionData.content[fullKey];
353
+ if (value === void 0) {
354
+ value = defaultValue;
355
+ }
356
+ if (typeof value === "string" && replace) {
357
+ value = replaceVariables(value, replace);
358
+ }
359
+ return value;
360
+ },
361
+ [section, sectionData]
362
+ );
363
+ return {
364
+ t,
365
+ data: sectionData,
366
+ loading
367
+ };
163
368
  }
164
- /**
165
- * 여러 섹션 Hook
166
- *
167
- * @param sectionNames - 섹션 이름 배열
168
- * @returns { [section]: { t, data, loading }, ... }
169
- *
170
- * @example
171
- * ```tsx
172
- * const sections = useSections(['home', 'why-futureplay']);
173
- * sections.home.t('hero.title');
174
- * ```
175
- */
176
- export function useSections(sectionNames) {
177
- const allSections = useCmsStore((state) => state.sections);
178
- const allLoading = useCmsStore((state) => state.loading);
179
- const result = {};
180
- sectionNames.forEach((section) => {
181
- const sectionData = allSections[section];
182
- const loading = allLoading[section] ?? false;
183
- const t = (key, defaultValue, replace) => {
184
- if (!sectionData) {
185
- return defaultValue;
186
- }
187
- const fullKey = `${section}.${key}`;
188
- let value = sectionData.content[fullKey];
189
- if (value === undefined) {
190
- value = defaultValue;
191
- }
192
- if (typeof value === 'string' && replace) {
193
- value = replaceVariables(value, replace);
194
- }
195
- return value;
196
- };
197
- result[section] = {
198
- t,
199
- data: sectionData,
200
- loading,
201
- };
202
- });
203
- return result;
369
+ function useSections(sectionNames) {
370
+ const allSections = useCmsStore((state) => state.sections);
371
+ const allLoading = useCmsStore((state) => state.loading);
372
+ const result = {};
373
+ sectionNames.forEach((section) => {
374
+ const sectionData = allSections[section];
375
+ const loading = allLoading[section] ?? false;
376
+ const t = (key, defaultValue, replace) => {
377
+ if (!sectionData) {
378
+ return defaultValue;
379
+ }
380
+ const fullKey = `${section}.${key}`;
381
+ let value = sectionData.content[fullKey];
382
+ if (value === void 0) {
383
+ value = defaultValue;
384
+ }
385
+ if (typeof value === "string" && replace) {
386
+ value = replaceVariables(value, replace);
387
+ }
388
+ return value;
389
+ };
390
+ result[section] = {
391
+ t,
392
+ data: sectionData,
393
+ loading
394
+ };
395
+ });
396
+ return result;
204
397
  }
398
+ export {
399
+ useCmsStore,
400
+ useSection,
401
+ useSections
402
+ };
205
403
  //# sourceMappingURL=store.js.map