@spfn/cms 0.1.0-alpha.8 → 0.1.0-alpha.80

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 (233) hide show
  1. package/README.md +28 -416
  2. package/dist/{helpers/locale.actions.d.ts → actions-BEFWwQsh.d.ts} +70 -7
  3. package/dist/actions.d.ts +2 -9
  4. package/dist/actions.js +99 -10
  5. package/dist/actions.js.map +1 -1
  6. package/dist/api.d.ts +319 -0
  7. package/dist/api.js +467 -0
  8. package/dist/api.js.map +1 -0
  9. package/dist/client.d.ts +135 -127
  10. package/dist/client.js +1318 -59
  11. package/dist/client.js.map +1 -1
  12. package/dist/{types.d.ts → index-Dh5FjWzR.d.ts} +45 -7
  13. package/dist/index.d.ts +112 -16
  14. package/dist/index.js +625 -23
  15. package/dist/index.js.map +1 -1
  16. package/dist/label-sync-generator-B0EmvtWM.d.ts +32 -0
  17. package/dist/lib/contracts/labels.d.ts +244 -0
  18. package/dist/lib/contracts/labels.js +269 -0
  19. package/dist/lib/contracts/labels.js.map +1 -0
  20. package/dist/lib/contracts/published-cache.d.ts +48 -0
  21. package/dist/lib/contracts/published-cache.js +49 -0
  22. package/dist/lib/contracts/published-cache.js.map +1 -0
  23. package/dist/lib/contracts/values.d.ts +71 -0
  24. package/dist/lib/contracts/values.js +104 -0
  25. package/dist/lib/contracts/values.js.map +1 -0
  26. package/dist/locale.constants-BNkSdNP1.d.ts +108 -0
  27. package/dist/{entities → server/entities}/cms-audit-logs.d.ts +15 -70
  28. package/dist/server/entities/cms-audit-logs.js +78 -0
  29. package/dist/server/entities/cms-audit-logs.js.map +1 -0
  30. package/dist/{entities → server/entities}/cms-draft-cache.d.ts +13 -73
  31. package/dist/server/entities/cms-draft-cache.js +38 -0
  32. package/dist/server/entities/cms-draft-cache.js.map +1 -0
  33. package/dist/{entities → server/entities}/cms-label-values.d.ts +16 -67
  34. package/dist/server/entities/cms-label-values.js +81 -0
  35. package/dist/server/entities/cms-label-values.js.map +1 -0
  36. package/dist/{entities → server/entities}/cms-labels.d.ts +17 -14
  37. package/dist/server/entities/cms-labels.js +42 -0
  38. package/dist/server/entities/cms-labels.js.map +1 -0
  39. package/dist/{entities → server/entities}/cms-published-cache.d.ts +14 -69
  40. package/dist/server/entities/cms-published-cache.js +36 -0
  41. package/dist/server/entities/cms-published-cache.js.map +1 -0
  42. package/dist/server/entities/index.d.ts +6 -0
  43. package/dist/server/entities/index.js +185 -0
  44. package/dist/server/entities/index.js.map +1 -0
  45. package/dist/server/generators/index.d.ts +19 -0
  46. package/dist/server/generators/index.js +724 -0
  47. package/dist/server/generators/index.js.map +1 -0
  48. package/dist/server/labels/index.d.ts +1 -0
  49. package/dist/server/labels/index.js +33 -0
  50. package/dist/server/labels/index.js.map +1 -0
  51. package/dist/server/repositories/index.d.ts +212 -0
  52. package/dist/server/repositories/index.js +418 -0
  53. package/dist/server/repositories/index.js.map +1 -0
  54. package/dist/server/routes/labels/[id]/admin/index.js +679 -0
  55. package/dist/server/routes/labels/[id]/admin/index.js.map +1 -0
  56. package/dist/server/routes/labels/[id]/index.js +576 -0
  57. package/dist/server/routes/labels/[id]/index.js.map +1 -0
  58. package/dist/server/routes/labels/[id]/publish/index.js +720 -0
  59. package/dist/server/routes/labels/[id]/publish/index.js.map +1 -0
  60. package/dist/server/routes/labels/[id]/versions/index.js +548 -0
  61. package/dist/server/routes/labels/[id]/versions/index.js.map +1 -0
  62. package/dist/server/routes/labels/_id_/admin/index.d.ts +11 -0
  63. package/dist/{routes/labels/[id] → server/routes/labels/_id_}/index.d.ts +5 -3
  64. package/dist/server/routes/labels/_id_/publish/index.d.ts +11 -0
  65. package/dist/server/routes/labels/_id_/versions/index.d.ts +11 -0
  66. package/dist/server/routes/labels/by-key/[key]/index.js +525 -0
  67. package/dist/server/routes/labels/by-key/[key]/index.js.map +1 -0
  68. package/dist/server/routes/labels/by-key/_key_/index.d.ts +10 -0
  69. package/dist/server/routes/labels/index.d.ts +12 -0
  70. package/dist/server/routes/labels/index.js +684 -0
  71. package/dist/server/routes/labels/index.js.map +1 -0
  72. package/dist/server/routes/published-cache/index.d.ts +11 -0
  73. package/dist/server/routes/published-cache/index.js +337 -0
  74. package/dist/server/routes/published-cache/index.js.map +1 -0
  75. package/dist/server/routes/values/[labelId]/[version]/index.js +457 -0
  76. package/dist/server/routes/values/[labelId]/[version]/index.js.map +1 -0
  77. package/dist/server/routes/values/[labelId]/index.js +452 -0
  78. package/dist/server/routes/values/[labelId]/index.js.map +1 -0
  79. package/dist/server/routes/values/_labelId_/_version_/index.d.ts +10 -0
  80. package/dist/server/routes/values/_labelId_/index.d.ts +10 -0
  81. package/dist/server.d.ts +77 -7
  82. package/dist/server.js +1740 -247
  83. package/dist/server.js.map +1 -1
  84. package/migrations/0000_init.sql +3 -0
  85. package/migrations/0001_far_lady_vermin.sql +86 -0
  86. package/migrations/0002_heavy_the_enforcers.sql +2 -0
  87. package/migrations/0003_rare_runaways.sql +1 -0
  88. package/migrations/meta/0000_snapshot.json +15 -0
  89. package/migrations/meta/0001_snapshot.json +687 -0
  90. package/migrations/meta/0002_snapshot.json +686 -0
  91. package/migrations/meta/0003_snapshot.json +563 -0
  92. package/migrations/meta/_journal.json +34 -0
  93. package/package.json +55 -36
  94. package/dist/actions.d.ts.map +0 -1
  95. package/dist/client.d.ts.map +0 -1
  96. package/dist/cms.config.d.ts +0 -77
  97. package/dist/cms.config.d.ts.map +0 -1
  98. package/dist/cms.config.js +0 -111
  99. package/dist/cms.config.js.map +0 -1
  100. package/dist/entities/cms-audit-logs.d.ts.map +0 -1
  101. package/dist/entities/cms-audit-logs.js +0 -103
  102. package/dist/entities/cms-audit-logs.js.map +0 -1
  103. package/dist/entities/cms-draft-cache.d.ts.map +0 -1
  104. package/dist/entities/cms-draft-cache.js +0 -112
  105. package/dist/entities/cms-draft-cache.js.map +0 -1
  106. package/dist/entities/cms-label-values.d.ts.map +0 -1
  107. package/dist/entities/cms-label-values.js +0 -105
  108. package/dist/entities/cms-label-values.js.map +0 -1
  109. package/dist/entities/cms-label-versions.d.ts +0 -207
  110. package/dist/entities/cms-label-versions.d.ts.map +0 -1
  111. package/dist/entities/cms-label-versions.js +0 -80
  112. package/dist/entities/cms-label-versions.js.map +0 -1
  113. package/dist/entities/cms-labels.d.ts.map +0 -1
  114. package/dist/entities/cms-labels.js +0 -48
  115. package/dist/entities/cms-labels.js.map +0 -1
  116. package/dist/entities/cms-published-cache.d.ts.map +0 -1
  117. package/dist/entities/cms-published-cache.js +0 -103
  118. package/dist/entities/cms-published-cache.js.map +0 -1
  119. package/dist/entities/index.d.ts +0 -10
  120. package/dist/entities/index.d.ts.map +0 -1
  121. package/dist/entities/index.js +0 -10
  122. package/dist/entities/index.js.map +0 -1
  123. package/dist/generators/index.d.ts +0 -19
  124. package/dist/generators/index.d.ts.map +0 -1
  125. package/dist/generators/index.js +0 -19
  126. package/dist/generators/index.js.map +0 -1
  127. package/dist/generators/label-sync-generator.d.ts +0 -33
  128. package/dist/generators/label-sync-generator.d.ts.map +0 -1
  129. package/dist/generators/label-sync-generator.js +0 -86
  130. package/dist/generators/label-sync-generator.js.map +0 -1
  131. package/dist/helpers/locale.actions.d.ts.map +0 -1
  132. package/dist/helpers/locale.actions.js +0 -210
  133. package/dist/helpers/locale.actions.js.map +0 -1
  134. package/dist/helpers/locale.constants.d.ts +0 -10
  135. package/dist/helpers/locale.constants.d.ts.map +0 -1
  136. package/dist/helpers/locale.constants.js +0 -10
  137. package/dist/helpers/locale.constants.js.map +0 -1
  138. package/dist/helpers/locale.d.ts +0 -17
  139. package/dist/helpers/locale.d.ts.map +0 -1
  140. package/dist/helpers/locale.js +0 -20
  141. package/dist/helpers/locale.js.map +0 -1
  142. package/dist/helpers/sync.d.ts +0 -41
  143. package/dist/helpers/sync.d.ts.map +0 -1
  144. package/dist/helpers/sync.js +0 -309
  145. package/dist/helpers/sync.js.map +0 -1
  146. package/dist/index.d.ts.map +0 -1
  147. package/dist/init.d.ts +0 -31
  148. package/dist/init.d.ts.map +0 -1
  149. package/dist/init.js +0 -36
  150. package/dist/init.js.map +0 -1
  151. package/dist/labels/helpers.d.ts +0 -31
  152. package/dist/labels/helpers.d.ts.map +0 -1
  153. package/dist/labels/helpers.js +0 -60
  154. package/dist/labels/helpers.js.map +0 -1
  155. package/dist/labels/index.d.ts +0 -7
  156. package/dist/labels/index.d.ts.map +0 -1
  157. package/dist/labels/index.js +0 -7
  158. package/dist/labels/index.js.map +0 -1
  159. package/dist/repositories/cms-draft-cache.repository.d.ts +0 -62
  160. package/dist/repositories/cms-draft-cache.repository.d.ts.map +0 -1
  161. package/dist/repositories/cms-draft-cache.repository.js +0 -56
  162. package/dist/repositories/cms-draft-cache.repository.js.map +0 -1
  163. package/dist/repositories/cms-label-values.repository.d.ts +0 -32
  164. package/dist/repositories/cms-label-values.repository.d.ts.map +0 -1
  165. package/dist/repositories/cms-label-values.repository.js +0 -72
  166. package/dist/repositories/cms-label-values.repository.js.map +0 -1
  167. package/dist/repositories/cms-labels.repository.d.ts +0 -53
  168. package/dist/repositories/cms-labels.repository.d.ts.map +0 -1
  169. package/dist/repositories/cms-labels.repository.js +0 -77
  170. package/dist/repositories/cms-labels.repository.js.map +0 -1
  171. package/dist/repositories/cms-published-cache.repository.d.ts +0 -53
  172. package/dist/repositories/cms-published-cache.repository.d.ts.map +0 -1
  173. package/dist/repositories/cms-published-cache.repository.js +0 -54
  174. package/dist/repositories/cms-published-cache.repository.js.map +0 -1
  175. package/dist/repositories/index.d.ts +0 -8
  176. package/dist/repositories/index.d.ts.map +0 -1
  177. package/dist/repositories/index.js +0 -9
  178. package/dist/repositories/index.js.map +0 -1
  179. package/dist/routes/labels/[id]/contract.d.ts +0 -68
  180. package/dist/routes/labels/[id]/contract.d.ts.map +0 -1
  181. package/dist/routes/labels/[id]/contract.js +0 -84
  182. package/dist/routes/labels/[id]/contract.js.map +0 -1
  183. package/dist/routes/labels/[id]/index.d.ts.map +0 -1
  184. package/dist/routes/labels/[id]/index.js +0 -96
  185. package/dist/routes/labels/[id]/index.js.map +0 -1
  186. package/dist/routes/labels/by-key/[key]/contract.d.ts +0 -24
  187. package/dist/routes/labels/by-key/[key]/contract.d.ts.map +0 -1
  188. package/dist/routes/labels/by-key/[key]/contract.js +0 -28
  189. package/dist/routes/labels/by-key/[key]/contract.js.map +0 -1
  190. package/dist/routes/labels/by-key/[key]/index.d.ts +0 -8
  191. package/dist/routes/labels/by-key/[key]/index.d.ts.map +0 -1
  192. package/dist/routes/labels/by-key/[key]/index.js +0 -32
  193. package/dist/routes/labels/by-key/[key]/index.js.map +0 -1
  194. package/dist/routes/labels/contract.d.ts +0 -59
  195. package/dist/routes/labels/contract.d.ts.map +0 -1
  196. package/dist/routes/labels/contract.js +0 -75
  197. package/dist/routes/labels/contract.js.map +0 -1
  198. package/dist/routes/labels/index.d.ts +0 -10
  199. package/dist/routes/labels/index.d.ts.map +0 -1
  200. package/dist/routes/labels/index.js +0 -73
  201. package/dist/routes/labels/index.js.map +0 -1
  202. package/dist/routes/published-cache/contract.d.ts +0 -25
  203. package/dist/routes/published-cache/contract.d.ts.map +0 -1
  204. package/dist/routes/published-cache/contract.js +0 -35
  205. package/dist/routes/published-cache/contract.js.map +0 -1
  206. package/dist/routes/published-cache/index.d.ts +0 -8
  207. package/dist/routes/published-cache/index.d.ts.map +0 -1
  208. package/dist/routes/published-cache/index.js +0 -33
  209. package/dist/routes/published-cache/index.js.map +0 -1
  210. package/dist/routes/values/[labelId]/[version]/contract.d.ts +0 -29
  211. package/dist/routes/values/[labelId]/[version]/contract.d.ts.map +0 -1
  212. package/dist/routes/values/[labelId]/[version]/contract.js +0 -33
  213. package/dist/routes/values/[labelId]/[version]/contract.js.map +0 -1
  214. package/dist/routes/values/[labelId]/[version]/index.d.ts +0 -8
  215. package/dist/routes/values/[labelId]/[version]/index.d.ts.map +0 -1
  216. package/dist/routes/values/[labelId]/[version]/index.js +0 -45
  217. package/dist/routes/values/[labelId]/[version]/index.js.map +0 -1
  218. package/dist/routes/values/[labelId]/contract.d.ts +0 -38
  219. package/dist/routes/values/[labelId]/contract.d.ts.map +0 -1
  220. package/dist/routes/values/[labelId]/contract.js +0 -59
  221. package/dist/routes/values/[labelId]/contract.js.map +0 -1
  222. package/dist/routes/values/[labelId]/index.d.ts +0 -8
  223. package/dist/routes/values/[labelId]/index.d.ts.map +0 -1
  224. package/dist/routes/values/[labelId]/index.js +0 -42
  225. package/dist/routes/values/[labelId]/index.js.map +0 -1
  226. package/dist/server.d.ts.map +0 -1
  227. package/dist/store.d.ts +0 -87
  228. package/dist/store.d.ts.map +0 -1
  229. package/dist/store.js +0 -205
  230. package/dist/store.js.map +0 -1
  231. package/dist/types.d.ts.map +0 -1
  232. package/dist/types.js +0 -7
  233. package/dist/types.js.map +0 -1
package/dist/client.js CHANGED
@@ -1,62 +1,1321 @@
1
- /**
2
- * @spfn/cms/client
3
- *
4
- * Client Components Only
5
- * 클라이언트 컴포넌트 전용 (브라우저에서 실행)
6
- */
7
- import { client } from '@spfn/core/client';
8
- // Labels
9
- import { getLabelsContract, createLabelContract } from './routes/labels/contract';
10
- import { getLabelContract, updateLabelContract, deleteLabelContract } from './routes/labels/[id]/contract';
11
- // Published Cache
12
- import { getPublishedCacheContract } from './routes/published-cache/contract';
13
- /**
14
- * CMS API Client
15
- */
16
- export const cmsApi = {
17
- /**
18
- * Labels API
19
- */
20
- labels: {
21
- /**
22
- * GET /cms/labels
23
- * 라벨 목록 조회 (섹션 필터, 페이지네이션)
24
- */
25
- list: (options) => client.call('/cms/labels', getLabelsContract, options),
26
- /**
27
- * GET /cms/labels/:id
28
- * 특정 라벨 조회
29
- */
30
- getById: (options) => client.call('/cms/labels/:id', getLabelContract, options),
31
- /**
32
- * POST /cms/labels
33
- * 라벨 생성
34
- */
35
- create: (options) => client.call('/cms/labels', createLabelContract, options),
36
- /**
37
- * PATCH /cms/labels/:id
38
- * 라벨 업데이트
39
- */
40
- update: (options) => client.call('/cms/labels/:id', updateLabelContract, options),
41
- /**
42
- * DELETE /cms/labels/:id
43
- * 라벨 삭제
44
- */
45
- delete: (options) => client.call('/cms/labels/:id', deleteLabelContract, options),
46
- },
47
- /**
48
- * Published Cache API
49
- */
50
- publishedCache: {
51
- /**
52
- * GET /cms/published-cache
53
- * 발행된 콘텐츠 캐시 조회
54
- */
55
- get: (options) => client.call('/cms/published-cache', getPublishedCacheContract, options),
1
+ // src/client/hooks/useSection.ts
2
+ import React from "react";
3
+
4
+ // src/client/store/cms.store.ts
5
+ import { create } from "zustand";
6
+
7
+ // src/api/index.ts
8
+ import { client as client8 } from "@spfn/core/client";
9
+
10
+ // src/api/cms-labels.ts
11
+ import { client } from "@spfn/core/client";
12
+
13
+ // src/lib/contracts/labels.ts
14
+ import { Type } from "@sinclair/typebox";
15
+ var getLabelsContract = {
16
+ method: "GET",
17
+ path: "/_cms/labels",
18
+ query: Type.Object({
19
+ section: Type.Optional(Type.String({ description: "\uC139\uC158\uC73C\uB85C \uD544\uD130\uB9C1 (\uC608: home, why-futureplay)" })),
20
+ includeDefaultValues: Type.Optional(Type.Boolean({ description: "\uAE30\uBCF8\uAC12 \uD3EC\uD568 \uC5EC\uBD80" }))
21
+ }),
22
+ response: Type.Object({
23
+ labels: Type.Array(Type.Object({
24
+ id: Type.Number(),
25
+ key: Type.String(),
26
+ section: Type.String(),
27
+ type: Type.String(),
28
+ description: Type.Union([Type.String(), Type.Null()], { description: "\uB77C\uBCA8 \uC124\uBA85" }),
29
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
30
+ createdBy: Type.Union([Type.String(), Type.Null()]),
31
+ createdAt: Type.String(),
32
+ updatedAt: Type.String(),
33
+ defaultValue: Type.Optional(Type.Any({ description: "\uB77C\uBCA8 \uC815\uC758 \uD30C\uC77C\uC758 \uAE30\uBCF8\uAC12" }))
34
+ })),
35
+ total: Type.Number()
36
+ })
37
+ };
38
+ var createLabelContract = {
39
+ method: "POST",
40
+ path: "/_cms/labels",
41
+ body: Type.Object({
42
+ key: Type.String({
43
+ description: "\uACE0\uC720 \uD0A4 (\uC608: home.hero.title)",
44
+ pattern: "^[a-z0-9-]+\\.[a-z0-9-]+\\.[a-z0-9-]+$"
45
+ }),
46
+ section: Type.String({
47
+ description: "\uC139\uC158 \uC774\uB984 (\uC608: home, why-futureplay)",
48
+ pattern: "^[a-z0-9-]+$"
49
+ }),
50
+ type: Type.Union([
51
+ Type.Literal("text"),
52
+ Type.Literal("image"),
53
+ Type.Literal("video"),
54
+ Type.Literal("file"),
55
+ Type.Literal("object")
56
+ ], { description: "\uAC12 \uD0C0\uC785" }),
57
+ createdBy: Type.Optional(Type.String({ description: "\uC0DD\uC131\uC790 ID" }))
58
+ }),
59
+ response: Type.Union([
60
+ Type.Object({
61
+ id: Type.Number(),
62
+ key: Type.String(),
63
+ section: Type.String(),
64
+ type: Type.String(),
65
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
66
+ createdBy: Type.Union([Type.String(), Type.Null()]),
67
+ createdAt: Type.String(),
68
+ updatedAt: Type.String()
69
+ }),
70
+ Type.Object({
71
+ error: Type.String(),
72
+ key: Type.Optional(Type.String())
73
+ })
74
+ ])
75
+ };
76
+ var getLabelContract = {
77
+ method: "GET",
78
+ path: "/_cms/labels/:id",
79
+ params: Type.Object({
80
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
81
+ }),
82
+ response: Type.Union([
83
+ Type.Object({
84
+ id: Type.Number(),
85
+ key: Type.String(),
86
+ section: Type.String(),
87
+ type: Type.String(),
88
+ description: Type.Union([Type.String(), Type.Null()]),
89
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
90
+ createdBy: Type.Union([Type.String(), Type.Null()]),
91
+ createdAt: Type.String(),
92
+ updatedAt: Type.String()
93
+ }),
94
+ Type.Object({
95
+ error: Type.String()
96
+ })
97
+ ])
98
+ };
99
+ var updateLabelContract = {
100
+ method: "PATCH",
101
+ path: "/_cms/labels/:id",
102
+ params: Type.Object({
103
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
104
+ }),
105
+ body: Type.Object({
106
+ section: Type.Optional(Type.String({ description: "\uC139\uC158 \uBCC0\uACBD" })),
107
+ type: Type.Optional(Type.Union([
108
+ Type.Literal("text"),
109
+ Type.Literal("image"),
110
+ Type.Literal("video"),
111
+ Type.Literal("file"),
112
+ Type.Literal("object")
113
+ ]))
114
+ }),
115
+ response: Type.Union([
116
+ Type.Object({
117
+ id: Type.Number(),
118
+ key: Type.String(),
119
+ section: Type.String(),
120
+ type: Type.String(),
121
+ description: Type.Union([Type.String(), Type.Null()]),
122
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
123
+ createdBy: Type.Union([Type.String(), Type.Null()]),
124
+ createdAt: Type.String(),
125
+ updatedAt: Type.String()
126
+ }),
127
+ Type.Object({
128
+ error: Type.String()
129
+ })
130
+ ])
131
+ };
132
+ var deleteLabelContract = {
133
+ method: "DELETE",
134
+ path: "/_cms/labels/:id",
135
+ params: Type.Object({
136
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
137
+ }),
138
+ response: Type.Union([
139
+ Type.Object({
140
+ success: Type.Boolean(),
141
+ id: Type.Number()
142
+ }),
143
+ Type.Object({
144
+ error: Type.String()
145
+ })
146
+ ])
147
+ };
148
+ var getLabelByKeyContract = {
149
+ method: "GET",
150
+ path: "/_cms/labels/by-key/:key",
151
+ params: Type.Object({
152
+ key: Type.String({ description: "\uB77C\uBCA8 Key (\uC608: home.hero.title)" })
153
+ }),
154
+ response: Type.Union([
155
+ Type.Object({
156
+ id: Type.Number(),
157
+ key: Type.String(),
158
+ section: Type.String(),
159
+ type: Type.String(),
160
+ description: Type.Union([Type.String(), Type.Null()]),
161
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
162
+ createdBy: Type.Union([Type.String(), Type.Null()]),
163
+ createdAt: Type.String(),
164
+ updatedAt: Type.String()
165
+ }),
166
+ Type.Object({
167
+ error: Type.String(),
168
+ key: Type.Optional(Type.String())
169
+ })
170
+ ])
171
+ };
172
+ var publishLabelContract = {
173
+ method: "POST",
174
+ path: "/_cms/labels/:id/publish",
175
+ params: Type.Object({
176
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
177
+ }),
178
+ body: Type.Object({
179
+ notes: Type.Optional(Type.String({ description: "\uBC1C\uD589 \uB178\uD2B8 (\uBC84\uC804 \uC124\uBA85)" })),
180
+ publishedBy: Type.Optional(Type.String({ description: "\uBC1C\uD589\uC790 ID" }))
181
+ }),
182
+ response: Type.Union([
183
+ Type.Object({
184
+ success: Type.Boolean(),
185
+ id: Type.Number(),
186
+ version: Type.Number(),
187
+ message: Type.String()
188
+ }),
189
+ Type.Object({
190
+ error: Type.String()
191
+ })
192
+ ])
193
+ };
194
+ var getAdminLabelContract = {
195
+ method: "GET",
196
+ path: "/_cms/labels/:id/admin",
197
+ params: Type.Object({
198
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
199
+ }),
200
+ response: Type.Union([
201
+ Type.Object({
202
+ label: Type.Object({
203
+ id: Type.Number(),
204
+ key: Type.String(),
205
+ section: Type.String(),
206
+ type: Type.String(),
207
+ description: Type.Union([Type.String(), Type.Null()]),
208
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
209
+ createdBy: Type.Union([Type.String(), Type.Null()]),
210
+ createdAt: Type.String(),
211
+ updatedAt: Type.String()
212
+ }),
213
+ draft: Type.Array(Type.Object({
214
+ id: Type.Number(),
215
+ labelId: Type.Number(),
216
+ version: Type.Null(),
217
+ locale: Type.String(),
218
+ breakpoint: Type.Union([Type.String(), Type.Null()]),
219
+ value: Type.Any(),
220
+ createdAt: Type.String()
221
+ })),
222
+ published: Type.Array(Type.Object({
223
+ id: Type.Number(),
224
+ labelId: Type.Number(),
225
+ version: Type.Number(),
226
+ locale: Type.String(),
227
+ breakpoint: Type.Union([Type.String(), Type.Null()]),
228
+ value: Type.Any(),
229
+ createdAt: Type.String()
230
+ })),
231
+ status: Type.Union([
232
+ Type.Literal("default-only"),
233
+ Type.Literal("unpublished"),
234
+ Type.Literal("published"),
235
+ Type.Literal("modified")
236
+ ])
237
+ }),
238
+ Type.Object({
239
+ error: Type.String()
240
+ })
241
+ ])
242
+ };
243
+ var getLabelVersionsContract = {
244
+ method: "GET",
245
+ path: "/_cms/labels/:id/versions",
246
+ params: Type.Object({
247
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
248
+ }),
249
+ response: Type.Union([
250
+ Type.Object({
251
+ versions: Type.Array(Type.Object({
252
+ version: Type.Number({ description: "\uBC84\uC804 \uBC88\uD638" }),
253
+ publishedAt: Type.String({ description: "\uBC1C\uD589 \uC2DC\uAC01 (ISO 8601)" }),
254
+ publishedBy: Type.Union([Type.String(), Type.Null()], { description: "\uBC1C\uD589\uC790 ID" }),
255
+ notes: Type.Union([Type.String(), Type.Null()], { description: "\uBC1C\uD589 \uB178\uD2B8" }),
256
+ values: Type.Array(Type.Object({
257
+ id: Type.Number(),
258
+ locale: Type.String(),
259
+ breakpoint: Type.Union([Type.String(), Type.Null()]),
260
+ value: Type.Any(),
261
+ createdAt: Type.String()
262
+ }))
263
+ }))
264
+ }),
265
+ Type.Object({
266
+ error: Type.String()
267
+ })
268
+ ])
269
+ };
270
+
271
+ // src/api/cms-labels.ts
272
+ var getLabels = (options) => client.call(getLabelsContract, options);
273
+ var createLabel = (options) => client.call(createLabelContract, options);
274
+ var getLabel = (options) => client.call(getLabelContract, options);
275
+ var updateLabel = (options) => client.call(updateLabelContract, options);
276
+ var deleteLabel = (options) => client.call(deleteLabelContract, options);
277
+
278
+ // src/api/cms-labels-by-key.ts
279
+ import { client as client2 } from "@spfn/core/client";
280
+ var getLabelByKey = (options) => client2.call(getLabelByKeyContract, options);
281
+
282
+ // src/api/cms-labels-publish.ts
283
+ import { client as client3 } from "@spfn/core/client";
284
+ var publishLabel = (options) => client3.call(publishLabelContract, options);
285
+
286
+ // src/api/cms-labels-admin.ts
287
+ import { client as client4 } from "@spfn/core/client";
288
+ var getAdminLabel = (options) => client4.call(getAdminLabelContract, options);
289
+
290
+ // src/api/cms-labels-versions.ts
291
+ import { client as client5 } from "@spfn/core/client";
292
+ var getLabelVersions = (options) => client5.call(getLabelVersionsContract, options);
293
+
294
+ // src/api/cms-published-cache.ts
295
+ import { client as client6 } from "@spfn/core/client";
296
+
297
+ // src/lib/contracts/published-cache.ts
298
+ import { Type as Type2 } from "@sinclair/typebox";
299
+ var SectionData = Type2.Object({
300
+ section: Type2.String(),
301
+ locale: Type2.String(),
302
+ content: Type2.Record(Type2.String(), Type2.Any()),
303
+ version: Type2.Number(),
304
+ publishedAt: Type2.Union([Type2.String(), Type2.Null()])
305
+ });
306
+ var getPublishedCacheContract = {
307
+ method: "GET",
308
+ path: "/_cms/published-cache",
309
+ query: Type2.Object({
310
+ sections: Type2.Union([
311
+ Type2.String({ description: "\uB2E8\uC77C \uC139\uC158 \uC774\uB984 (\uC608: home)" }),
312
+ Type2.Array(Type2.String(), { description: '\uC5EC\uB7EC \uC139\uC158 \uC774\uB984 (\uC608: ["home", "footer"])' })
313
+ ]),
314
+ locale: Type2.Optional(Type2.String({ default: "ko", description: "\uC5B8\uC5B4 \uCF54\uB4DC" }))
315
+ }),
316
+ response: Type2.Union([
317
+ // 성공: 항상 배열로 반환
318
+ Type2.Array(SectionData),
319
+ // 에러
320
+ Type2.Object({
321
+ error: Type2.String()
322
+ })
323
+ ])
324
+ };
325
+ var upsertPublishedCacheContract = {
326
+ method: "POST",
327
+ path: "/_cms/published-cache",
328
+ body: Type2.Object({
329
+ section: Type2.String({ description: "\uC139\uC158 \uC774\uB984 (\uC608: home)" }),
330
+ locale: Type2.String({ description: "\uC5B8\uC5B4 \uCF54\uB4DC (\uC608: ko, en, ja)" }),
331
+ content: Type2.Record(Type2.String(), Type2.Any(), { description: "\uBC1C\uD589\uD560 \uCF58\uD150\uCE20 (key-value \uD615\uD0DC)" }),
332
+ version: Type2.Number({ description: "\uBC84\uC804 \uBC88\uD638" })
333
+ }),
334
+ response: Type2.Union([
335
+ SectionData,
336
+ Type2.Object({
337
+ error: Type2.String()
338
+ })
339
+ ])
340
+ };
341
+
342
+ // src/api/cms-published-cache.ts
343
+ var getPublishedCache = (options) => client6.call(getPublishedCacheContract, options);
344
+ var upsertPublishedCache = (options) => client6.call(upsertPublishedCacheContract, options);
345
+
346
+ // src/api/cms-values.ts
347
+ import { client as client7 } from "@spfn/core/client";
348
+
349
+ // src/lib/contracts/values.ts
350
+ import { Type as Type3 } from "@sinclair/typebox";
351
+ var LabelValueSchema = Type3.Object({
352
+ type: Type3.Union([
353
+ Type3.Literal("text"),
354
+ Type3.Literal("image"),
355
+ Type3.Literal("video"),
356
+ Type3.Literal("file"),
357
+ Type3.Literal("object")
358
+ ]),
359
+ content: Type3.Optional(Type3.String()),
360
+ // text type
361
+ url: Type3.Optional(Type3.String()),
362
+ // image, video, file types (required for these types but optional in schema)
363
+ alt: Type3.Optional(Type3.String()),
364
+ // image type
365
+ width: Type3.Optional(Type3.Number()),
366
+ // image type
367
+ height: Type3.Optional(Type3.Number()),
368
+ // image type
369
+ thumbnail: Type3.Optional(Type3.String()),
370
+ // video type
371
+ duration: Type3.Optional(Type3.Number()),
372
+ // video type
373
+ filename: Type3.Optional(Type3.String()),
374
+ // file type
375
+ size: Type3.Optional(Type3.Number()),
376
+ // file type
377
+ fields: Type3.Optional(Type3.Any())
378
+ // object type - recursive structure
379
+ });
380
+ var saveValuesContract = {
381
+ method: "POST",
382
+ path: "/_cms/values/:labelId",
383
+ params: Type3.Object({
384
+ labelId: Type3.String({ description: "\uB77C\uBCA8 ID" })
385
+ }),
386
+ body: Type3.Object({
387
+ version: Type3.Union([
388
+ Type3.Null({ description: "Draft \uC800\uC7A5 (\uB36E\uC5B4\uC4F0\uAE30)" }),
389
+ Type3.Number({ description: "\uBC84\uC804 \uBC88\uD638 (\uBD88\uBCC0)", minimum: 1 })
390
+ ]),
391
+ values: Type3.Array(
392
+ Type3.Object({
393
+ locale: Type3.String({ description: "\uC5B8\uC5B4 \uCF54\uB4DC (ko, en, ja)", default: "ko" }),
394
+ breakpoint: Type3.Optional(Type3.Union([
395
+ Type3.Literal("sm"),
396
+ Type3.Literal("md"),
397
+ Type3.Literal("lg"),
398
+ Type3.Literal("xl"),
399
+ Type3.Literal("2xl"),
400
+ Type3.Null()
401
+ ], { description: "\uBC18\uC751\uD615 \uBE0C\uB808\uC774\uD06C\uD3EC\uC778\uD2B8" })),
402
+ value: LabelValueSchema
403
+ // 모든 라벨 값은 객체 형태 (type 필드 필수)
404
+ })
405
+ )
406
+ }),
407
+ response: Type3.Union([
408
+ Type3.Object({
409
+ success: Type3.Boolean(),
410
+ saved: Type3.Number(),
411
+ version: Type3.Union([Type3.Null(), Type3.Number()])
412
+ }),
413
+ Type3.Object({
414
+ error: Type3.String()
415
+ })
416
+ ])
417
+ };
418
+ var getValuesContract = {
419
+ method: "GET",
420
+ path: "/_cms/values/:labelId/:version",
421
+ params: Type3.Object({
422
+ labelId: Type3.String({ description: "\uB77C\uBCA8 ID" }),
423
+ version: Type3.String({ description: "\uBC84\uC804 \uBC88\uD638" })
424
+ }),
425
+ query: Type3.Object({
426
+ locale: Type3.Optional(Type3.String({ description: "\uC5B8\uC5B4 \uCF54\uB4DC (ko, en, ja)" })),
427
+ breakpoint: Type3.Optional(Type3.String({ description: "\uBC18\uC751\uD615 \uBE0C\uB808\uC774\uD06C\uD3EC\uC778\uD2B8" }))
428
+ }),
429
+ response: Type3.Union([
430
+ Type3.Object({
431
+ labelId: Type3.Number(),
432
+ version: Type3.Number(),
433
+ values: Type3.Array(
434
+ Type3.Object({
435
+ id: Type3.Number(),
436
+ locale: Type3.String(),
437
+ breakpoint: Type3.Union([Type3.String(), Type3.Null()]),
438
+ value: Type3.Any(),
439
+ createdAt: Type3.String()
440
+ })
441
+ )
442
+ }),
443
+ Type3.Object({
444
+ error: Type3.String()
445
+ })
446
+ ])
447
+ };
448
+
449
+ // src/api/cms-values.ts
450
+ var saveValues = (options) => client7.call(saveValuesContract, options);
451
+ var getValues = (options) => client7.call(getValuesContract, options);
452
+
453
+ // src/api/index.ts
454
+ var cmsApi = {
455
+ getLabels,
456
+ createLabel,
457
+ getLabel,
458
+ updateLabel,
459
+ deleteLabel,
460
+ getLabelByKey,
461
+ publishLabel,
462
+ getAdminLabel,
463
+ getLabelVersions,
464
+ getPublishedCache,
465
+ upsertPublishedCache,
466
+ saveValues,
467
+ getValues
468
+ };
469
+
470
+ // src/client/store/cms.store.ts
471
+ var useCmsStore = create((set, get) => ({
472
+ sections: {},
473
+ loading: {},
474
+ setSection: (section, data) => {
475
+ set((state) => ({
476
+ sections: {
477
+ ...state.sections,
478
+ [section]: data
479
+ }
480
+ }));
481
+ },
482
+ setSections: (sections) => {
483
+ set((state) => ({
484
+ sections: {
485
+ ...state.sections,
486
+ ...sections
487
+ }
488
+ }));
489
+ },
490
+ loadSection: async (section, locale = "ko") => {
491
+ const state = get();
492
+ if (state.loading[section]) {
493
+ return;
494
+ }
495
+ if (state.sections[section]) {
496
+ return;
497
+ }
498
+ set((state2) => ({
499
+ loading: { ...state2.loading, [section]: true }
500
+ }));
501
+ try {
502
+ const response = await cmsApi.getPublishedCache({
503
+ query: { sections: section, locale }
504
+ });
505
+ if ("error" in response) {
506
+ console.error(`Failed to load section ${section}:`, response.error);
507
+ return;
508
+ }
509
+ const data = response[0];
510
+ if (!data) {
511
+ console.warn(`Section ${section} not found`);
512
+ return;
513
+ }
514
+ const sectionData = {
515
+ section: data.section,
516
+ locale: data.locale,
517
+ content: data.content || {},
518
+ version: data.version || 0,
519
+ publishedAt: data.publishedAt || null
520
+ };
521
+ set((state2) => ({
522
+ sections: {
523
+ ...state2.sections,
524
+ [section]: sectionData
525
+ },
526
+ loading: { ...state2.loading, [section]: false }
527
+ }));
528
+ } catch (error) {
529
+ console.error(`Error loading CMS section ${section}:`, error);
530
+ set((state2) => ({
531
+ loading: { ...state2.loading, [section]: false }
532
+ }));
533
+ }
534
+ },
535
+ updateLabel: (section, key, value) => {
536
+ set((state) => ({
537
+ sections: {
538
+ ...state.sections,
539
+ [section]: {
540
+ ...state.sections[section],
541
+ content: {
542
+ ...state.sections[section]?.content,
543
+ [`${section}.${key}`]: value
544
+ }
545
+ }
546
+ }
547
+ }));
548
+ },
549
+ reset: () => {
550
+ set({
551
+ sections: {},
552
+ loading: {}
553
+ });
554
+ }
555
+ }));
556
+
557
+ // src/client/hooks/useSection.ts
558
+ function replaceVariables(text, replace) {
559
+ return text.replace(/\{(\w+)}/g, (match, key) => {
560
+ const value = replace[key];
561
+ return value !== void 0 ? String(value) : match;
562
+ });
563
+ }
564
+ function useSection(section, options = {}) {
565
+ const { autoLoad = false, locale = "ko" } = options;
566
+ const sectionData = useCmsStore((state) => state.sections[section]);
567
+ const loading = useCmsStore((state) => state.loading[section] ?? false);
568
+ const loadSection = useCmsStore((state) => state.loadSection);
569
+ React.useEffect(() => {
570
+ if (autoLoad && !sectionData && !loading) {
571
+ loadSection(section, locale);
572
+ }
573
+ }, [autoLoad, section, locale, sectionData, loading, loadSection]);
574
+ const t = React.useCallback(
575
+ (key, defaultValue, replace) => {
576
+ if (!sectionData) {
577
+ return defaultValue;
578
+ }
579
+ const fullKey = `${section}.${key}`;
580
+ let value = sectionData.content[fullKey];
581
+ if (value === void 0) {
582
+ value = defaultValue;
583
+ }
584
+ if (typeof value === "string" && replace) {
585
+ value = replaceVariables(value, replace);
586
+ }
587
+ return value;
56
588
  },
589
+ [section, sectionData]
590
+ );
591
+ return {
592
+ t,
593
+ data: sectionData,
594
+ loading
595
+ };
596
+ }
597
+
598
+ // src/client/hooks/useSections.ts
599
+ function replaceVariables2(text, replace) {
600
+ return text.replace(/\{(\w+)}/g, (match, key) => {
601
+ const value = replace[key];
602
+ return value !== void 0 ? String(value) : match;
603
+ });
604
+ }
605
+ function useSections(sectionNames) {
606
+ const allSections = useCmsStore((state) => state.sections);
607
+ const allLoading = useCmsStore((state) => state.loading);
608
+ const result = {};
609
+ sectionNames.forEach((section) => {
610
+ const sectionData = allSections[section];
611
+ const loading = allLoading[section] ?? false;
612
+ const t = (key, defaultValue, replace) => {
613
+ if (!sectionData) {
614
+ return defaultValue;
615
+ }
616
+ const fullKey = `${section}.${key}`;
617
+ let value = sectionData.content[fullKey];
618
+ if (value === void 0) {
619
+ value = defaultValue;
620
+ }
621
+ if (typeof value === "string" && replace) {
622
+ value = replaceVariables2(value, replace);
623
+ }
624
+ return value;
625
+ };
626
+ result[section] = {
627
+ t,
628
+ data: sectionData,
629
+ loading
630
+ };
631
+ });
632
+ return result;
633
+ }
634
+
635
+ // src/client/components/InitCms.tsx
636
+ import { useEffect } from "react";
637
+ function InitCms({ sections }) {
638
+ const setSections = useCmsStore((state) => state.setSections);
639
+ useEffect(() => {
640
+ const sectionsData = {};
641
+ Object.entries(sections).forEach(([key, { data }]) => {
642
+ sectionsData[key] = data;
643
+ });
644
+ setSections(sectionsData);
645
+ }, [sections, setSections]);
646
+ return null;
647
+ }
648
+
649
+ // src/server/helpers/locale.actions.ts
650
+ import { cookies, headers } from "next/headers.js";
651
+
652
+ // src/server/config/cms.config.ts
653
+ function getEnvVar(key, defaultValue) {
654
+ return process.env[key] || defaultValue;
655
+ }
656
+ function getEnvBoolean(key, defaultValue) {
657
+ const value = process.env[key];
658
+ if (value === void 0) return defaultValue;
659
+ return value === "true" || value === "1";
660
+ }
661
+ function loadConfigFromEnv() {
662
+ const defaultLocale = getEnvVar("SPFN_CMS_DEFAULT_LOCALE", "en");
663
+ const supportedLocalesStr = getEnvVar("SPFN_CMS_SUPPORTED_LOCALES", "en,ko");
664
+ const detectBrowserLanguage2 = getEnvBoolean("SPFN_CMS_DETECT_BROWSER_LANGUAGE", true);
665
+ const locales = supportedLocalesStr.split(",").map((locale) => locale.trim()).filter((locale) => locale.length > 0);
666
+ if (!locales.includes(defaultLocale)) {
667
+ locales.unshift(defaultLocale);
668
+ }
669
+ return {
670
+ defaultLocale,
671
+ locales,
672
+ supportedLocales: locales,
673
+ // backward compatibility
674
+ detectBrowserLanguage: detectBrowserLanguage2
675
+ };
676
+ }
677
+ var currentConfig = loadConfigFromEnv();
678
+ function getCmsConfig() {
679
+ return currentConfig;
680
+ }
681
+
682
+ // src/lib/constants/locale.constants.ts
683
+ var LOCALE_COOKIE_KEY = "spfn-locale";
684
+ var LOCALE_INFO_MAP = {
685
+ // 한국어
686
+ ko: {
687
+ locale: "ko",
688
+ countryCode: "KR",
689
+ flag: "🇰🇷",
690
+ dialCode: "+82",
691
+ nativeName: "\uD55C\uAD6D\uC5B4",
692
+ englishName: "Korean",
693
+ currencyCode: "KRW",
694
+ dateFormat: "YYYY.MM.DD"
695
+ },
696
+ // 영어 (미국)
697
+ en: {
698
+ locale: "en",
699
+ countryCode: "US",
700
+ flag: "🇺🇸",
701
+ dialCode: "+1",
702
+ nativeName: "English",
703
+ englishName: "English",
704
+ currencyCode: "USD",
705
+ dateFormat: "MM/DD/YYYY"
706
+ },
707
+ // 일본어
708
+ ja: {
709
+ locale: "ja",
710
+ countryCode: "JP",
711
+ flag: "🇯🇵",
712
+ dialCode: "+81",
713
+ nativeName: "\u65E5\u672C\u8A9E",
714
+ englishName: "Japanese",
715
+ currencyCode: "JPY",
716
+ dateFormat: "YYYY/MM/DD"
717
+ },
718
+ // 중국어 (간체)
719
+ zh: {
720
+ locale: "zh",
721
+ countryCode: "CN",
722
+ flag: "🇨🇳",
723
+ dialCode: "+86",
724
+ nativeName: "\u7B80\u4F53\u4E2D\u6587",
725
+ englishName: "Chinese (Simplified)",
726
+ currencyCode: "CNY",
727
+ dateFormat: "YYYY-MM-DD"
728
+ },
729
+ // 중국어 (번체, 대만)
730
+ "zh-TW": {
731
+ locale: "zh-TW",
732
+ countryCode: "TW",
733
+ flag: "🇹🇼",
734
+ dialCode: "+886",
735
+ nativeName: "\u7E41\u9AD4\u4E2D\u6587",
736
+ englishName: "Chinese (Traditional)",
737
+ currencyCode: "TWD",
738
+ dateFormat: "YYYY/MM/DD"
739
+ },
740
+ // 스페인어
741
+ es: {
742
+ locale: "es",
743
+ countryCode: "ES",
744
+ flag: "🇪🇸",
745
+ dialCode: "+34",
746
+ nativeName: "Espa\xF1ol",
747
+ englishName: "Spanish",
748
+ currencyCode: "EUR",
749
+ dateFormat: "DD/MM/YYYY"
750
+ },
751
+ // 프랑스어
752
+ fr: {
753
+ locale: "fr",
754
+ countryCode: "FR",
755
+ flag: "🇫🇷",
756
+ dialCode: "+33",
757
+ nativeName: "Fran\xE7ais",
758
+ englishName: "French",
759
+ currencyCode: "EUR",
760
+ dateFormat: "DD/MM/YYYY"
761
+ },
762
+ // 독일어
763
+ de: {
764
+ locale: "de",
765
+ countryCode: "DE",
766
+ flag: "🇩🇪",
767
+ dialCode: "+49",
768
+ nativeName: "Deutsch",
769
+ englishName: "German",
770
+ currencyCode: "EUR",
771
+ dateFormat: "DD.MM.YYYY"
772
+ },
773
+ // 이탈리아어
774
+ it: {
775
+ locale: "it",
776
+ countryCode: "IT",
777
+ flag: "🇮🇹",
778
+ dialCode: "+39",
779
+ nativeName: "Italiano",
780
+ englishName: "Italian",
781
+ currencyCode: "EUR",
782
+ dateFormat: "DD/MM/YYYY"
783
+ },
784
+ // 포르투갈어 (브라질)
785
+ pt: {
786
+ locale: "pt",
787
+ countryCode: "BR",
788
+ flag: "🇧🇷",
789
+ dialCode: "+55",
790
+ nativeName: "Portugu\xEAs",
791
+ englishName: "Portuguese",
792
+ currencyCode: "BRL",
793
+ dateFormat: "DD/MM/YYYY"
794
+ },
795
+ // 러시아어
796
+ ru: {
797
+ locale: "ru",
798
+ countryCode: "RU",
799
+ flag: "🇷🇺",
800
+ dialCode: "+7",
801
+ nativeName: "\u0420\u0443\u0441\u0441\u043A\u0438\u0439",
802
+ englishName: "Russian",
803
+ currencyCode: "RUB",
804
+ dateFormat: "DD.MM.YYYY"
805
+ },
806
+ // 아랍어
807
+ ar: {
808
+ locale: "ar",
809
+ countryCode: "SA",
810
+ flag: "🇸🇦",
811
+ dialCode: "+966",
812
+ nativeName: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629",
813
+ englishName: "Arabic",
814
+ rtl: true,
815
+ currencyCode: "SAR",
816
+ dateFormat: "DD/MM/YYYY"
817
+ },
818
+ // 힌디어
819
+ hi: {
820
+ locale: "hi",
821
+ countryCode: "IN",
822
+ flag: "🇮🇳",
823
+ dialCode: "+91",
824
+ nativeName: "\u0939\u093F\u0928\u094D\u0926\u0940",
825
+ englishName: "Hindi",
826
+ currencyCode: "INR",
827
+ dateFormat: "DD/MM/YYYY"
828
+ },
829
+ // 태국어
830
+ th: {
831
+ locale: "th",
832
+ countryCode: "TH",
833
+ flag: "🇹🇭",
834
+ dialCode: "+66",
835
+ nativeName: "\u0E44\u0E17\u0E22",
836
+ englishName: "Thai",
837
+ currencyCode: "THB",
838
+ dateFormat: "DD/MM/YYYY"
839
+ },
840
+ // 베트남어
841
+ vi: {
842
+ locale: "vi",
843
+ countryCode: "VN",
844
+ flag: "🇻🇳",
845
+ dialCode: "+84",
846
+ nativeName: "Ti\u1EBFng Vi\u1EC7t",
847
+ englishName: "Vietnamese",
848
+ currencyCode: "VND",
849
+ dateFormat: "DD/MM/YYYY"
850
+ },
851
+ // 인도네시아어
852
+ id: {
853
+ locale: "id",
854
+ countryCode: "ID",
855
+ flag: "🇮🇩",
856
+ dialCode: "+62",
857
+ nativeName: "Bahasa Indonesia",
858
+ englishName: "Indonesian",
859
+ currencyCode: "IDR",
860
+ dateFormat: "DD/MM/YYYY"
861
+ },
862
+ // 터키어
863
+ tr: {
864
+ locale: "tr",
865
+ countryCode: "TR",
866
+ flag: "🇹🇷",
867
+ dialCode: "+90",
868
+ nativeName: "T\xFCrk\xE7e",
869
+ englishName: "Turkish",
870
+ currencyCode: "TRY",
871
+ dateFormat: "DD.MM.YYYY"
872
+ },
873
+ // 폴란드어
874
+ pl: {
875
+ locale: "pl",
876
+ countryCode: "PL",
877
+ flag: "🇵🇱",
878
+ dialCode: "+48",
879
+ nativeName: "Polski",
880
+ englishName: "Polish",
881
+ currencyCode: "PLN",
882
+ dateFormat: "DD.MM.YYYY"
883
+ },
884
+ // 네덜란드어
885
+ nl: {
886
+ locale: "nl",
887
+ countryCode: "NL",
888
+ flag: "🇳🇱",
889
+ dialCode: "+31",
890
+ nativeName: "Nederlands",
891
+ englishName: "Dutch",
892
+ currencyCode: "EUR",
893
+ dateFormat: "DD-MM-YYYY"
894
+ },
895
+ // 중국어 (홍콩)
896
+ "zh-HK": {
897
+ locale: "zh-HK",
898
+ countryCode: "HK",
899
+ flag: "🇭🇰",
900
+ dialCode: "+852",
901
+ nativeName: "\u7E41\u9AD4\u4E2D\u6587 (\u9999\u6E2F)",
902
+ englishName: "Chinese (Hong Kong)",
903
+ currencyCode: "HKD",
904
+ dateFormat: "YYYY/MM/DD"
905
+ },
906
+ // 말레이어
907
+ ms: {
908
+ locale: "ms",
909
+ countryCode: "MY",
910
+ flag: "🇲🇾",
911
+ dialCode: "+60",
912
+ nativeName: "Bahasa Melayu",
913
+ englishName: "Malay",
914
+ currencyCode: "MYR",
915
+ dateFormat: "DD/MM/YYYY"
916
+ },
917
+ // 영어 (영국)
918
+ "en-GB": {
919
+ locale: "en-GB",
920
+ countryCode: "GB",
921
+ flag: "🇬🇧",
922
+ dialCode: "+44",
923
+ nativeName: "English (UK)",
924
+ englishName: "English (United Kingdom)",
925
+ currencyCode: "GBP",
926
+ dateFormat: "DD/MM/YYYY"
927
+ },
928
+ // 영어 (캐나다)
929
+ "en-CA": {
930
+ locale: "en-CA",
931
+ countryCode: "CA",
932
+ flag: "🇨🇦",
933
+ dialCode: "+1",
934
+ nativeName: "English (Canada)",
935
+ englishName: "English (Canada)",
936
+ currencyCode: "CAD",
937
+ dateFormat: "YYYY-MM-DD"
938
+ },
939
+ // 영어 (호주)
940
+ "en-AU": {
941
+ locale: "en-AU",
942
+ countryCode: "AU",
943
+ flag: "🇦🇺",
944
+ dialCode: "+61",
945
+ nativeName: "English (Australia)",
946
+ englishName: "English (Australia)",
947
+ currencyCode: "AUD",
948
+ dateFormat: "DD/MM/YYYY"
949
+ },
950
+ // 영어 (뉴질랜드)
951
+ "en-NZ": {
952
+ locale: "en-NZ",
953
+ countryCode: "NZ",
954
+ flag: "🇳🇿",
955
+ dialCode: "+64",
956
+ nativeName: "English (New Zealand)",
957
+ englishName: "English (New Zealand)",
958
+ currencyCode: "NZD",
959
+ dateFormat: "DD/MM/YYYY"
960
+ },
961
+ // 스페인어 (멕시코)
962
+ "es-MX": {
963
+ locale: "es-MX",
964
+ countryCode: "MX",
965
+ flag: "🇲🇽",
966
+ dialCode: "+52",
967
+ nativeName: "Espa\xF1ol (M\xE9xico)",
968
+ englishName: "Spanish (Mexico)",
969
+ currencyCode: "MXN",
970
+ dateFormat: "DD/MM/YYYY"
971
+ },
972
+ // 스페인어 (아르헨티나)
973
+ "es-AR": {
974
+ locale: "es-AR",
975
+ countryCode: "AR",
976
+ flag: "🇦🇷",
977
+ dialCode: "+54",
978
+ nativeName: "Espa\xF1ol (Argentina)",
979
+ englishName: "Spanish (Argentina)",
980
+ currencyCode: "ARS",
981
+ dateFormat: "DD/MM/YYYY"
982
+ },
983
+ // 스페인어 (콜롬비아)
984
+ "es-CO": {
985
+ locale: "es-CO",
986
+ countryCode: "CO",
987
+ flag: "🇨🇴",
988
+ dialCode: "+57",
989
+ nativeName: "Espa\xF1ol (Colombia)",
990
+ englishName: "Spanish (Colombia)",
991
+ currencyCode: "COP",
992
+ dateFormat: "DD/MM/YYYY"
993
+ },
994
+ // 스웨덴어
995
+ sv: {
996
+ locale: "sv",
997
+ countryCode: "SE",
998
+ flag: "🇸🇪",
999
+ dialCode: "+46",
1000
+ nativeName: "Svenska",
1001
+ englishName: "Swedish",
1002
+ currencyCode: "SEK",
1003
+ dateFormat: "YYYY-MM-DD"
1004
+ },
1005
+ // 노르웨이어
1006
+ no: {
1007
+ locale: "no",
1008
+ countryCode: "NO",
1009
+ flag: "🇳🇴",
1010
+ dialCode: "+47",
1011
+ nativeName: "Norsk",
1012
+ englishName: "Norwegian",
1013
+ currencyCode: "NOK",
1014
+ dateFormat: "DD.MM.YYYY"
1015
+ },
1016
+ // 덴마크어
1017
+ da: {
1018
+ locale: "da",
1019
+ countryCode: "DK",
1020
+ flag: "🇩🇰",
1021
+ dialCode: "+45",
1022
+ nativeName: "Dansk",
1023
+ englishName: "Danish",
1024
+ currencyCode: "DKK",
1025
+ dateFormat: "DD-MM-YYYY"
1026
+ },
1027
+ // 핀란드어
1028
+ fi: {
1029
+ locale: "fi",
1030
+ countryCode: "FI",
1031
+ flag: "🇫🇮",
1032
+ dialCode: "+358",
1033
+ nativeName: "Suomi",
1034
+ englishName: "Finnish",
1035
+ currencyCode: "EUR",
1036
+ dateFormat: "DD.MM.YYYY"
1037
+ },
1038
+ // 우크라이나어
1039
+ uk: {
1040
+ locale: "uk",
1041
+ countryCode: "UA",
1042
+ flag: "🇺🇦",
1043
+ dialCode: "+380",
1044
+ nativeName: "\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430",
1045
+ englishName: "Ukrainian",
1046
+ currencyCode: "UAH",
1047
+ dateFormat: "DD.MM.YYYY"
1048
+ },
1049
+ // 체코어
1050
+ cs: {
1051
+ locale: "cs",
1052
+ countryCode: "CZ",
1053
+ flag: "🇨🇿",
1054
+ dialCode: "+420",
1055
+ nativeName: "\u010Ce\u0161tina",
1056
+ englishName: "Czech",
1057
+ currencyCode: "CZK",
1058
+ dateFormat: "DD.MM.YYYY"
1059
+ },
1060
+ // 헝가리어
1061
+ hu: {
1062
+ locale: "hu",
1063
+ countryCode: "HU",
1064
+ flag: "🇭🇺",
1065
+ dialCode: "+36",
1066
+ nativeName: "Magyar",
1067
+ englishName: "Hungarian",
1068
+ currencyCode: "HUF",
1069
+ dateFormat: "YYYY.MM.DD."
1070
+ },
1071
+ // 루마니아어
1072
+ ro: {
1073
+ locale: "ro",
1074
+ countryCode: "RO",
1075
+ flag: "🇷🇴",
1076
+ dialCode: "+40",
1077
+ nativeName: "Rom\xE2n\u0103",
1078
+ englishName: "Romanian",
1079
+ currencyCode: "RON",
1080
+ dateFormat: "DD.MM.YYYY"
1081
+ },
1082
+ // 불가리아어
1083
+ bg: {
1084
+ locale: "bg",
1085
+ countryCode: "BG",
1086
+ flag: "🇧🇬",
1087
+ dialCode: "+359",
1088
+ nativeName: "\u0411\u044A\u043B\u0433\u0430\u0440\u0441\u043A\u0438",
1089
+ englishName: "Bulgarian",
1090
+ currencyCode: "BGN",
1091
+ dateFormat: "DD.MM.YYYY"
1092
+ },
1093
+ // 크로아티아어
1094
+ hr: {
1095
+ locale: "hr",
1096
+ countryCode: "HR",
1097
+ flag: "🇭🇷",
1098
+ dialCode: "+385",
1099
+ nativeName: "Hrvatski",
1100
+ englishName: "Croatian",
1101
+ currencyCode: "HRK",
1102
+ dateFormat: "DD.MM.YYYY."
1103
+ },
1104
+ // 세르비아어
1105
+ sr: {
1106
+ locale: "sr",
1107
+ countryCode: "RS",
1108
+ flag: "🇷🇸",
1109
+ dialCode: "+381",
1110
+ nativeName: "\u0421\u0440\u043F\u0441\u043A\u0438",
1111
+ englishName: "Serbian",
1112
+ currencyCode: "RSD",
1113
+ dateFormat: "DD.MM.YYYY."
1114
+ },
1115
+ // 슬로바키아어
1116
+ sk: {
1117
+ locale: "sk",
1118
+ countryCode: "SK",
1119
+ flag: "🇸🇰",
1120
+ dialCode: "+421",
1121
+ nativeName: "Sloven\u010Dina",
1122
+ englishName: "Slovak",
1123
+ currencyCode: "EUR",
1124
+ dateFormat: "DD.MM.YYYY"
1125
+ },
1126
+ // 슬로베니아어
1127
+ sl: {
1128
+ locale: "sl",
1129
+ countryCode: "SI",
1130
+ flag: "🇸🇮",
1131
+ dialCode: "+386",
1132
+ nativeName: "Sloven\u0161\u010Dina",
1133
+ englishName: "Slovenian",
1134
+ currencyCode: "EUR",
1135
+ dateFormat: "DD.MM.YYYY"
1136
+ },
1137
+ // 리투아니아어
1138
+ lt: {
1139
+ locale: "lt",
1140
+ countryCode: "LT",
1141
+ flag: "🇱🇹",
1142
+ dialCode: "+370",
1143
+ nativeName: "Lietuvi\u0173",
1144
+ englishName: "Lithuanian",
1145
+ currencyCode: "EUR",
1146
+ dateFormat: "YYYY-MM-DD"
1147
+ },
1148
+ // 라트비아어
1149
+ lv: {
1150
+ locale: "lv",
1151
+ countryCode: "LV",
1152
+ flag: "🇱🇻",
1153
+ dialCode: "+371",
1154
+ nativeName: "Latvie\u0161u",
1155
+ englishName: "Latvian",
1156
+ currencyCode: "EUR",
1157
+ dateFormat: "DD.MM.YYYY."
1158
+ },
1159
+ // 에스토니아어
1160
+ et: {
1161
+ locale: "et",
1162
+ countryCode: "EE",
1163
+ flag: "🇪🇪",
1164
+ dialCode: "+372",
1165
+ nativeName: "Eesti",
1166
+ englishName: "Estonian",
1167
+ currencyCode: "EUR",
1168
+ dateFormat: "DD.MM.YYYY"
1169
+ },
1170
+ // 그리스어
1171
+ el: {
1172
+ locale: "el",
1173
+ countryCode: "GR",
1174
+ flag: "🇬🇷",
1175
+ dialCode: "+30",
1176
+ nativeName: "\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC",
1177
+ englishName: "Greek",
1178
+ currencyCode: "EUR",
1179
+ dateFormat: "DD/MM/YYYY"
1180
+ },
1181
+ // 페르시아어
1182
+ fa: {
1183
+ locale: "fa",
1184
+ countryCode: "IR",
1185
+ flag: "🇮🇷",
1186
+ dialCode: "+98",
1187
+ nativeName: "\u0641\u0627\u0631\u0633\u06CC",
1188
+ englishName: "Persian",
1189
+ rtl: true,
1190
+ currencyCode: "IRR",
1191
+ dateFormat: "YYYY/MM/DD"
1192
+ },
1193
+ // 히브리어
1194
+ he: {
1195
+ locale: "he",
1196
+ countryCode: "IL",
1197
+ flag: "🇮🇱",
1198
+ dialCode: "+972",
1199
+ nativeName: "\u05E2\u05D1\u05E8\u05D9\u05EA",
1200
+ englishName: "Hebrew",
1201
+ rtl: true,
1202
+ currencyCode: "ILS",
1203
+ dateFormat: "DD/MM/YYYY"
1204
+ },
1205
+ // 스와힐리어
1206
+ sw: {
1207
+ locale: "sw",
1208
+ countryCode: "KE",
1209
+ flag: "🇰🇪",
1210
+ dialCode: "+254",
1211
+ nativeName: "Kiswahili",
1212
+ englishName: "Swahili",
1213
+ currencyCode: "KES",
1214
+ dateFormat: "DD/MM/YYYY"
1215
+ }
1216
+ };
1217
+ function getLocaleInfo(locale) {
1218
+ return LOCALE_INFO_MAP[locale];
1219
+ }
1220
+ function getAllLocales() {
1221
+ return Object.keys(LOCALE_INFO_MAP);
1222
+ }
1223
+ function getSupportedLocales() {
1224
+ return getAllLocales();
1225
+ }
1226
+ function getFlag(locale) {
1227
+ return LOCALE_INFO_MAP[locale]?.flag ?? "";
1228
+ }
1229
+ function getDialCode(locale) {
1230
+ return LOCALE_INFO_MAP[locale]?.dialCode ?? "";
1231
+ }
1232
+ function isRTL(locale) {
1233
+ return LOCALE_INFO_MAP[locale]?.rtl ?? false;
1234
+ }
1235
+
1236
+ // src/server/helpers/locale.actions.ts
1237
+ async function detectBrowserLanguage() {
1238
+ try {
1239
+ const headersList = await headers();
1240
+ const acceptLanguage = headersList.get("accept-language");
1241
+ if (!acceptLanguage) {
1242
+ return null;
1243
+ }
1244
+ const languages = acceptLanguage.split(",").map((lang) => {
1245
+ const [code] = lang.split(";");
1246
+ return code.split("-")[0].trim();
1247
+ });
1248
+ const config = getCmsConfig();
1249
+ for (const lang of languages) {
1250
+ if (config.locales.includes(lang)) {
1251
+ return lang;
1252
+ }
1253
+ }
1254
+ return null;
1255
+ } catch (error) {
1256
+ return null;
1257
+ }
1258
+ }
1259
+ async function getLocale() {
1260
+ const config = getCmsConfig();
1261
+ const cookieStore = await cookies();
1262
+ const cookieLocale = cookieStore.get(LOCALE_COOKIE_KEY)?.value;
1263
+ if (cookieLocale && config.locales.includes(cookieLocale)) {
1264
+ return cookieLocale;
1265
+ }
1266
+ if (config.detectBrowserLanguage) {
1267
+ const browserLang = await detectBrowserLanguage();
1268
+ if (browserLang) {
1269
+ return browserLang;
1270
+ }
1271
+ }
1272
+ return config.defaultLocale;
1273
+ }
1274
+ async function setLocale(locale) {
1275
+ const config = getCmsConfig();
1276
+ if (!config.locales.includes(locale)) {
1277
+ throw new Error(
1278
+ `Unsupported locale: ${locale}. Supported locales: ${config.locales.join(", ")}`
1279
+ );
1280
+ }
1281
+ const cookieStore = await cookies();
1282
+ cookieStore.set(LOCALE_COOKIE_KEY, locale, {
1283
+ path: "/",
1284
+ maxAge: 60 * 60 * 24 * 365,
1285
+ // 1년
1286
+ sameSite: "lax"
1287
+ });
1288
+ }
1289
+ async function getLocales() {
1290
+ const config = getCmsConfig();
1291
+ return config.locales;
1292
+ }
1293
+ async function getLocaleWithInfo() {
1294
+ const locale = await getLocale();
1295
+ const info = getLocaleInfo(locale);
1296
+ return { locale, info };
1297
+ }
1298
+ async function getLocalesWithInfo() {
1299
+ const config = getCmsConfig();
1300
+ const locales = config.locales;
1301
+ return locales.map((locale) => getLocaleInfo(locale)).filter((info) => info !== void 0);
1302
+ }
1303
+ export {
1304
+ InitCms,
1305
+ LOCALE_COOKIE_KEY,
1306
+ LOCALE_INFO_MAP,
1307
+ getDialCode,
1308
+ getFlag,
1309
+ getLocale,
1310
+ getLocaleInfo,
1311
+ getLocaleWithInfo,
1312
+ getLocales,
1313
+ getLocalesWithInfo,
1314
+ getSupportedLocales,
1315
+ isRTL,
1316
+ setLocale,
1317
+ useCmsStore,
1318
+ useSection,
1319
+ useSections
57
1320
  };
58
- // Client-side Store & Hooks
59
- export { useCmsStore, useSection, useSections } from './store';
60
- // Client-side Initializer
61
- export { InitCms } from './init';
62
1321
  //# sourceMappingURL=client.js.map