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

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 +731 -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 +1747 -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
@@ -0,0 +1,720 @@
1
+ // src/server/routes/labels/[id]/publish/index.ts
2
+ import { createApp } from "@spfn/core/route";
3
+
4
+ // src/lib/contracts/labels.ts
5
+ import { Type } from "@sinclair/typebox";
6
+ var getLabelsContract = {
7
+ method: "GET",
8
+ path: "/_cms/labels",
9
+ query: Type.Object({
10
+ section: Type.Optional(Type.String({ description: "\uC139\uC158\uC73C\uB85C \uD544\uD130\uB9C1 (\uC608: home, why-futureplay)" })),
11
+ includeDefaultValues: Type.Optional(Type.Boolean({ description: "\uAE30\uBCF8\uAC12 \uD3EC\uD568 \uC5EC\uBD80" }))
12
+ }),
13
+ response: Type.Object({
14
+ labels: Type.Array(Type.Object({
15
+ id: Type.Number(),
16
+ key: Type.String(),
17
+ section: Type.String(),
18
+ type: Type.String(),
19
+ description: Type.Union([Type.String(), Type.Null()], { description: "\uB77C\uBCA8 \uC124\uBA85" }),
20
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
21
+ createdBy: Type.Union([Type.String(), Type.Null()]),
22
+ createdAt: Type.String(),
23
+ updatedAt: Type.String(),
24
+ defaultValue: Type.Optional(Type.Any({ description: "\uB77C\uBCA8 \uC815\uC758 \uD30C\uC77C\uC758 \uAE30\uBCF8\uAC12" }))
25
+ })),
26
+ total: Type.Number()
27
+ })
28
+ };
29
+ var createLabelContract = {
30
+ method: "POST",
31
+ path: "/_cms/labels",
32
+ body: Type.Object({
33
+ key: Type.String({
34
+ description: "\uACE0\uC720 \uD0A4 (\uC608: home.hero.title)",
35
+ pattern: "^[a-z0-9-]+\\.[a-z0-9-]+\\.[a-z0-9-]+$"
36
+ }),
37
+ section: Type.String({
38
+ description: "\uC139\uC158 \uC774\uB984 (\uC608: home, why-futureplay)",
39
+ pattern: "^[a-z0-9-]+$"
40
+ }),
41
+ type: Type.Union([
42
+ Type.Literal("text"),
43
+ Type.Literal("image"),
44
+ Type.Literal("video"),
45
+ Type.Literal("file"),
46
+ Type.Literal("object")
47
+ ], { description: "\uAC12 \uD0C0\uC785" }),
48
+ createdBy: Type.Optional(Type.String({ description: "\uC0DD\uC131\uC790 ID" }))
49
+ }),
50
+ response: Type.Union([
51
+ Type.Object({
52
+ id: Type.Number(),
53
+ key: Type.String(),
54
+ section: Type.String(),
55
+ type: Type.String(),
56
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
57
+ createdBy: Type.Union([Type.String(), Type.Null()]),
58
+ createdAt: Type.String(),
59
+ updatedAt: Type.String()
60
+ }),
61
+ Type.Object({
62
+ error: Type.String(),
63
+ key: Type.Optional(Type.String())
64
+ })
65
+ ])
66
+ };
67
+ var getLabelContract = {
68
+ method: "GET",
69
+ path: "/_cms/labels/:id",
70
+ params: Type.Object({
71
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
72
+ }),
73
+ response: Type.Union([
74
+ Type.Object({
75
+ id: Type.Number(),
76
+ key: Type.String(),
77
+ section: Type.String(),
78
+ type: Type.String(),
79
+ description: Type.Union([Type.String(), Type.Null()]),
80
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
81
+ createdBy: Type.Union([Type.String(), Type.Null()]),
82
+ createdAt: Type.String(),
83
+ updatedAt: Type.String()
84
+ }),
85
+ Type.Object({
86
+ error: Type.String()
87
+ })
88
+ ])
89
+ };
90
+ var updateLabelContract = {
91
+ method: "PATCH",
92
+ path: "/_cms/labels/:id",
93
+ params: Type.Object({
94
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
95
+ }),
96
+ body: Type.Object({
97
+ section: Type.Optional(Type.String({ description: "\uC139\uC158 \uBCC0\uACBD" })),
98
+ type: Type.Optional(Type.Union([
99
+ Type.Literal("text"),
100
+ Type.Literal("image"),
101
+ Type.Literal("video"),
102
+ Type.Literal("file"),
103
+ Type.Literal("object")
104
+ ]))
105
+ }),
106
+ response: Type.Union([
107
+ Type.Object({
108
+ id: Type.Number(),
109
+ key: Type.String(),
110
+ section: Type.String(),
111
+ type: Type.String(),
112
+ description: Type.Union([Type.String(), Type.Null()]),
113
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
114
+ createdBy: Type.Union([Type.String(), Type.Null()]),
115
+ createdAt: Type.String(),
116
+ updatedAt: Type.String()
117
+ }),
118
+ Type.Object({
119
+ error: Type.String()
120
+ })
121
+ ])
122
+ };
123
+ var deleteLabelContract = {
124
+ method: "DELETE",
125
+ path: "/_cms/labels/:id",
126
+ params: Type.Object({
127
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
128
+ }),
129
+ response: Type.Union([
130
+ Type.Object({
131
+ success: Type.Boolean(),
132
+ id: Type.Number()
133
+ }),
134
+ Type.Object({
135
+ error: Type.String()
136
+ })
137
+ ])
138
+ };
139
+ var getLabelByKeyContract = {
140
+ method: "GET",
141
+ path: "/_cms/labels/by-key/:key",
142
+ params: Type.Object({
143
+ key: Type.String({ description: "\uB77C\uBCA8 Key (\uC608: home.hero.title)" })
144
+ }),
145
+ response: Type.Union([
146
+ Type.Object({
147
+ id: Type.Number(),
148
+ key: Type.String(),
149
+ section: Type.String(),
150
+ type: Type.String(),
151
+ description: Type.Union([Type.String(), Type.Null()]),
152
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
153
+ createdBy: Type.Union([Type.String(), Type.Null()]),
154
+ createdAt: Type.String(),
155
+ updatedAt: Type.String()
156
+ }),
157
+ Type.Object({
158
+ error: Type.String(),
159
+ key: Type.Optional(Type.String())
160
+ })
161
+ ])
162
+ };
163
+ var publishLabelContract = {
164
+ method: "POST",
165
+ path: "/_cms/labels/:id/publish",
166
+ params: Type.Object({
167
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
168
+ }),
169
+ body: Type.Object({
170
+ notes: Type.Optional(Type.String({ description: "\uBC1C\uD589 \uB178\uD2B8 (\uBC84\uC804 \uC124\uBA85)" })),
171
+ publishedBy: Type.Optional(Type.String({ description: "\uBC1C\uD589\uC790 ID" }))
172
+ }),
173
+ response: Type.Union([
174
+ Type.Object({
175
+ success: Type.Boolean(),
176
+ id: Type.Number(),
177
+ version: Type.Number(),
178
+ message: Type.String()
179
+ }),
180
+ Type.Object({
181
+ error: Type.String()
182
+ })
183
+ ])
184
+ };
185
+ var getAdminLabelContract = {
186
+ method: "GET",
187
+ path: "/_cms/labels/:id/admin",
188
+ params: Type.Object({
189
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
190
+ }),
191
+ response: Type.Union([
192
+ Type.Object({
193
+ label: Type.Object({
194
+ id: Type.Number(),
195
+ key: Type.String(),
196
+ section: Type.String(),
197
+ type: Type.String(),
198
+ description: Type.Union([Type.String(), Type.Null()]),
199
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
200
+ createdBy: Type.Union([Type.String(), Type.Null()]),
201
+ createdAt: Type.String(),
202
+ updatedAt: Type.String()
203
+ }),
204
+ draft: Type.Array(Type.Object({
205
+ id: Type.Number(),
206
+ labelId: Type.Number(),
207
+ version: Type.Null(),
208
+ locale: Type.String(),
209
+ breakpoint: Type.Union([Type.String(), Type.Null()]),
210
+ value: Type.Any(),
211
+ createdAt: Type.String()
212
+ })),
213
+ published: Type.Array(Type.Object({
214
+ id: Type.Number(),
215
+ labelId: Type.Number(),
216
+ version: Type.Number(),
217
+ locale: Type.String(),
218
+ breakpoint: Type.Union([Type.String(), Type.Null()]),
219
+ value: Type.Any(),
220
+ createdAt: Type.String()
221
+ })),
222
+ status: Type.Union([
223
+ Type.Literal("default-only"),
224
+ Type.Literal("unpublished"),
225
+ Type.Literal("published"),
226
+ Type.Literal("modified")
227
+ ])
228
+ }),
229
+ Type.Object({
230
+ error: Type.String()
231
+ })
232
+ ])
233
+ };
234
+ var getLabelVersionsContract = {
235
+ method: "GET",
236
+ path: "/_cms/labels/:id/versions",
237
+ params: Type.Object({
238
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
239
+ }),
240
+ response: Type.Union([
241
+ Type.Object({
242
+ versions: Type.Array(Type.Object({
243
+ version: Type.Number({ description: "\uBC84\uC804 \uBC88\uD638" }),
244
+ publishedAt: Type.String({ description: "\uBC1C\uD589 \uC2DC\uAC01 (ISO 8601)" }),
245
+ publishedBy: Type.Union([Type.String(), Type.Null()], { description: "\uBC1C\uD589\uC790 ID" }),
246
+ notes: Type.Union([Type.String(), Type.Null()], { description: "\uBC1C\uD589 \uB178\uD2B8" }),
247
+ values: Type.Array(Type.Object({
248
+ id: Type.Number(),
249
+ locale: Type.String(),
250
+ breakpoint: Type.Union([Type.String(), Type.Null()]),
251
+ value: Type.Any(),
252
+ createdAt: Type.String()
253
+ }))
254
+ }))
255
+ }),
256
+ Type.Object({
257
+ error: Type.String()
258
+ })
259
+ ])
260
+ };
261
+
262
+ // src/server/repositories/cms-labels.repository.ts
263
+ import { findOne, findMany as findManyHelper, create as createHelper, updateOne, deleteOne, count as countHelper } from "@spfn/core/db";
264
+ import { asc } from "drizzle-orm";
265
+
266
+ // src/server/entities/cms-labels.ts
267
+ import { index, integer, serial, text, timestamp } from "drizzle-orm/pg-core";
268
+ import { createFunctionSchema } from "@spfn/core/db";
269
+ var schema = createFunctionSchema("@spfn/cms");
270
+ var cmsLabels = schema.table("labels", {
271
+ // Primary Key
272
+ id: serial("id").primaryKey(),
273
+ // 라벨 식별자
274
+ key: text("key").notNull().unique(),
275
+ // 예: "home.hero.title", "why-futureplay.hero.subtitle"
276
+ // 구조: {section}.{component}.{property}
277
+ // 섹션 분류 (페이지 단위)
278
+ section: text("section").notNull(),
279
+ // 예: "home", "why-futureplay", "team"
280
+ // 값 타입
281
+ type: text("type").notNull(),
282
+ // "text" | "image" | "video" | "file" | "object"
283
+ // 기본값
284
+ defaultValue: text("default_value"),
285
+ // 라벨의 기본값 (sync 시 설정)
286
+ // 설명
287
+ description: text("description"),
288
+ // 라벨에 대한 설명 (optional)
289
+ // 현재 발행된 버전 번호
290
+ publishedVersion: integer("published_version"),
291
+ // null = 미발행 상태
292
+ // 1, 2, 3... = 발행된 버전 번호
293
+ // 생성자 추적
294
+ createdBy: text("created_by"),
295
+ // 타임스탬프
296
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
297
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
298
+ }, (table) => [
299
+ // 인덱스: 섹션별 조회 최적화
300
+ index("cms_labels_section_idx").on(table.section),
301
+ // 인덱스: key로 조회 최적화 (unique 제약으로 자동 생성되지만 명시)
302
+ index("cms_labels_key_idx").on(table.key)
303
+ ]);
304
+
305
+ // src/server/entities/cms-label-values.ts
306
+ import { serial as serial2, integer as integer2, text as text2, jsonb, timestamp as timestamp2, index as index2, unique } from "drizzle-orm/pg-core";
307
+ import { createFunctionSchema as createFunctionSchema2 } from "@spfn/core/db";
308
+ var schema2 = createFunctionSchema2("@spfn/cms");
309
+ var cmsLabelValues = schema2.table("label_values", {
310
+ // Primary Key
311
+ id: serial2("id").primaryKey(),
312
+ // Foreign Key: cms_labels
313
+ labelId: integer2("label_id").notNull().references(() => cmsLabels.id, { onDelete: "cascade" }),
314
+ // 버전 번호 (null = draft, number = published version)
315
+ version: integer2("version"),
316
+ // 언어 코드
317
+ locale: text2("locale").notNull().default("ko"),
318
+ // "ko" | "en" | "ja"
319
+ // 반응형 브레이크포인트
320
+ breakpoint: text2("breakpoint"),
321
+ // null = 기본값 (모든 화면 크기)
322
+ // "sm" | "md" | "lg" | "xl" | "2xl"
323
+ // 실제 값 (JSONB)
324
+ value: jsonb("value").notNull(),
325
+ // LabelValue 타입:
326
+ // - TextValue: { type: "text", content: string }
327
+ // - ImageValue: { type: "image", url: string, alt?: string, width?: number, height?: number }
328
+ // - VideoValue: { type: "video", url: string, thumbnail?: string, duration?: number }
329
+ // - FileValue: { type: "file", url: string, filename: string, size?: number }
330
+ // - ObjectValue: { type: "object", fields: Record<string, LabelValue> }
331
+ // 생성 시각
332
+ createdAt: timestamp2("created_at", { withTimezone: true }).notNull().defaultNow()
333
+ }, (table) => [
334
+ // UNIQUE 제약: 같은 버전에서 locale + breakpoint 조합은 유일
335
+ unique("cms_label_values_locale_breakpoint_unique").on(table.labelId, table.version, table.locale, table.breakpoint),
336
+ // 인덱스: labelId + version 복합 조회 최적화
337
+ index2("cms_label_values_label_version_idx").on(table.labelId, table.version),
338
+ // 인덱스: locale 필터링 최적화
339
+ index2("cms_label_values_locale_idx").on(table.locale)
340
+ ]);
341
+
342
+ // src/server/entities/cms-draft-cache.ts
343
+ import { serial as serial3, text as text3, jsonb as jsonb2, timestamp as timestamp3, index as index3, unique as unique2 } from "drizzle-orm/pg-core";
344
+ import { createFunctionSchema as createFunctionSchema3 } from "@spfn/core/db";
345
+ var schema3 = createFunctionSchema3("@spfn/cms");
346
+ var cmsDraftCache = schema3.table("draft_cache", {
347
+ // Primary Key
348
+ id: serial3("id").primaryKey(),
349
+ // 섹션 (페이지 단위)
350
+ section: text3("section").notNull(),
351
+ // "home" | "why-futureplay" | "team" | "our-companies" | "apply"
352
+ // 언어
353
+ locale: text3("locale").notNull(),
354
+ // "ko" | "en" | "ja"
355
+ // 사용자 ID (핵심 필드!)
356
+ userId: text3("user_id").notNull(),
357
+ // 각 관리자의 독립적인 작업 공간
358
+ // Draft 콘텐츠 (JSONB)
359
+ content: jsonb2("content").notNull(),
360
+ // Record<string, LabelValue>
361
+ // {
362
+ // "home.hero.title": { type: "text", content: "수정 중..." },
363
+ // "home.hero.subtitle": { type: "text", content: "새로운 문구" },
364
+ // ...
365
+ // }
366
+ // 최종 수정 시각
367
+ updatedAt: timestamp3("updated_at", { withTimezone: true }).notNull().defaultNow()
368
+ }, (table) => [
369
+ // UNIQUE 제약: section + locale + userId 조합은 유일
370
+ unique2("cms_draft_cache_unique").on(table.section, table.locale, table.userId),
371
+ // 인덱스: section으로 조회 최적화
372
+ index3("cms_draft_cache_section_idx").on(table.section),
373
+ // 인덱스: userId로 사용자의 모든 draft 조회 최적화
374
+ index3("cms_draft_cache_user_idx").on(table.userId)
375
+ ]);
376
+
377
+ // src/server/entities/cms-published-cache.ts
378
+ import { serial as serial4, text as text4, jsonb as jsonb3, integer as integer3, timestamp as timestamp4, index as index4, unique as unique3 } from "drizzle-orm/pg-core";
379
+ import { createFunctionSchema as createFunctionSchema4 } from "@spfn/core/db";
380
+ var schema4 = createFunctionSchema4("@spfn/cms");
381
+ var cmsPublishedCache = schema4.table("published_cache", {
382
+ // Primary Key
383
+ id: serial4("id").primaryKey(),
384
+ // 섹션 (페이지 단위)
385
+ section: text4("section").notNull(),
386
+ // "home" | "why-futureplay" | "team" | "our-companies" | "apply"
387
+ // 언어
388
+ locale: text4("locale").notNull(),
389
+ // "ko" | "en" | "ja"
390
+ // 캐시된 콘텐츠 (JSONB)
391
+ content: jsonb3("content").notNull(),
392
+ // Record<string, LabelValue>
393
+ // {
394
+ // "home.hero.title": { type: "text", content: "..." },
395
+ // "home.hero.image": { type: "image", url: "...", alt: "..." },
396
+ // ...
397
+ // }
398
+ // 발행 정보
399
+ publishedAt: timestamp4("published_at", { withTimezone: true }).notNull(),
400
+ publishedBy: text4("published_by"),
401
+ // 캐시 버전 (클라이언트 캐싱용)
402
+ version: integer3("version").notNull().default(1)
403
+ }, (table) => [
404
+ // UNIQUE 제약: section + locale 조합은 유일
405
+ unique3("cms_published_cache_unique").on(table.section, table.locale),
406
+ // 인덱스: section으로 조회 최적화
407
+ index4("cms_published_cache_section_idx").on(table.section)
408
+ ]);
409
+
410
+ // src/server/entities/cms-audit-logs.ts
411
+ import { serial as serial5, integer as integer4, text as text5, jsonb as jsonb4, timestamp as timestamp5, index as index5 } from "drizzle-orm/pg-core";
412
+ import { createFunctionSchema as createFunctionSchema5 } from "@spfn/core/db";
413
+ var schema5 = createFunctionSchema5("@spfn/cms");
414
+ var cmsAuditLogs = schema5.table("audit_logs", {
415
+ // Primary Key
416
+ id: serial5("id").primaryKey(),
417
+ // Foreign Key: cms_labels (nullable - 라벨 삭제 시 로그는 유지)
418
+ labelId: integer4("label_id").references(() => cmsLabels.id, { onDelete: "set null" }),
419
+ // 작업 유형
420
+ action: text5("action").notNull(),
421
+ // "create" | "update" | "publish" | "unpublish" | "archive" | "delete" | "rollback" | "duplicate"
422
+ // 사용자 정보
423
+ userId: text5("user_id").notNull(),
424
+ userName: text5("user_name"),
425
+ // 변경 내용 (before/after)
426
+ changes: jsonb4("changes"),
427
+ // { before: {...}, after: {...} }
428
+ // 추가 메타데이터
429
+ metadata: jsonb4("metadata"),
430
+ // { version: number, ip: string, userAgent: string, ... }
431
+ // 작업 시각
432
+ createdAt: timestamp5("created_at", { withTimezone: true }).notNull().defaultNow()
433
+ }, (table) => [
434
+ // 인덱스: labelId로 이력 조회 최적화
435
+ index5("cms_audit_logs_label_id_idx").on(table.labelId),
436
+ // 인덱스: userId로 사용자 활동 조회 최적화
437
+ index5("cms_audit_logs_user_id_idx").on(table.userId),
438
+ // 인덱스: action 필터링 최적화
439
+ index5("cms_audit_logs_action_idx").on(table.action),
440
+ // 인덱스: 시간순 조회 최적화
441
+ index5("cms_audit_logs_created_at_idx").on(table.createdAt)
442
+ ]);
443
+
444
+ // src/server/repositories/cms-labels.repository.ts
445
+ async function findMany(options) {
446
+ const { section } = options || {};
447
+ return findManyHelper(cmsLabels, {
448
+ where: section ? { section } : void 0,
449
+ orderBy: asc(cmsLabels.key)
450
+ // key 오름차순 정렬 (JSON 파일의 순서 유지)
451
+ });
452
+ }
453
+ async function count(section) {
454
+ return countHelper(cmsLabels, section ? { section } : void 0);
455
+ }
456
+ async function findById(id) {
457
+ return findOne(cmsLabels, { id });
458
+ }
459
+ async function findByKey(key) {
460
+ return findOne(cmsLabels, { key });
461
+ }
462
+ async function findBySection(section) {
463
+ return findManyHelper(cmsLabels, {
464
+ where: { section },
465
+ orderBy: asc(cmsLabels.key)
466
+ // key 오름차순 정렬 (JSON 파일의 순서 유지)
467
+ });
468
+ }
469
+ async function create(data) {
470
+ return createHelper(cmsLabels, data);
471
+ }
472
+ async function updateById(id, data) {
473
+ return updateOne(cmsLabels, { id }, { ...data, updatedAt: /* @__PURE__ */ new Date() });
474
+ }
475
+ async function deleteById(id) {
476
+ return deleteOne(cmsLabels, { id });
477
+ }
478
+ var cmsLabelsRepository = {
479
+ findMany,
480
+ count,
481
+ findById,
482
+ findByKey,
483
+ findBySection,
484
+ create,
485
+ updateById,
486
+ deleteById
487
+ };
488
+
489
+ // src/server/repositories/cms-label-values.repository.ts
490
+ import { findOne as findOne2, findMany as findMany2, create as create2, updateOne as updateOne2, deleteMany } from "@spfn/core/db";
491
+ import { eq, and, isNull } from "drizzle-orm";
492
+ async function findByLabelIdAndVersion(labelId, version, options) {
493
+ const { locale, breakpoint } = options || {};
494
+ const conditions = [
495
+ eq(cmsLabelValues.labelId, labelId),
496
+ eq(cmsLabelValues.version, version)
497
+ ];
498
+ if (locale) {
499
+ conditions.push(eq(cmsLabelValues.locale, locale));
500
+ }
501
+ if (breakpoint !== void 0) {
502
+ conditions.push(
503
+ breakpoint === null ? isNull(cmsLabelValues.breakpoint) : eq(cmsLabelValues.breakpoint, breakpoint)
504
+ );
505
+ }
506
+ return findMany2(cmsLabelValues, {
507
+ where: and(...conditions)
508
+ });
509
+ }
510
+ async function upsert(data) {
511
+ const versionCondition = data.version === null || data.version === void 0 ? isNull(cmsLabelValues.version) : eq(cmsLabelValues.version, data.version);
512
+ const existing = await findOne2(
513
+ cmsLabelValues,
514
+ and(
515
+ eq(cmsLabelValues.labelId, data.labelId),
516
+ versionCondition,
517
+ eq(cmsLabelValues.locale, data.locale || "ko"),
518
+ data.breakpoint ? eq(cmsLabelValues.breakpoint, data.breakpoint) : isNull(cmsLabelValues.breakpoint)
519
+ )
520
+ );
521
+ if (existing) {
522
+ if (data.version === null || data.version === void 0) {
523
+ const updated = await updateOne2(
524
+ cmsLabelValues,
525
+ { id: existing.id },
526
+ { value: data.value }
527
+ );
528
+ return updated;
529
+ } else {
530
+ throw new Error(`Published version ${data.version} already exists and cannot be overwritten`);
531
+ }
532
+ } else {
533
+ return create2(cmsLabelValues, data);
534
+ }
535
+ }
536
+ async function findDraftsByLabelId(labelId) {
537
+ return findMany2(cmsLabelValues, {
538
+ where: and(
539
+ eq(cmsLabelValues.labelId, labelId),
540
+ isNull(cmsLabelValues.version)
541
+ )
542
+ });
543
+ }
544
+ async function upsertMany(values) {
545
+ const results = [];
546
+ for (const value of values) {
547
+ const result = await upsert(value);
548
+ results.push(result);
549
+ }
550
+ return results;
551
+ }
552
+ async function deleteByVersion(labelId, version) {
553
+ return deleteMany(
554
+ cmsLabelValues,
555
+ and(
556
+ eq(cmsLabelValues.labelId, labelId),
557
+ eq(cmsLabelValues.version, version)
558
+ )
559
+ );
560
+ }
561
+ var cmsLabelValuesRepository = {
562
+ findByLabelIdAndVersion,
563
+ findDraftsByLabelId,
564
+ upsert,
565
+ upsertMany,
566
+ deleteByVersion
567
+ };
568
+
569
+ // src/server/repositories/cms-published-cache.repository.ts
570
+ import { findOne as findOne3, findMany as findMany3, deleteOne as deleteOne2, deleteMany as deleteMany2, upsert as upsertHelper } from "@spfn/core/db";
571
+ import { eq as eq2, and as and2, sql } from "drizzle-orm";
572
+ async function findBySection2(section, locale = "ko") {
573
+ return findOne3(
574
+ cmsPublishedCache,
575
+ and2(
576
+ eq2(cmsPublishedCache.section, section),
577
+ eq2(cmsPublishedCache.locale, locale)
578
+ )
579
+ );
580
+ }
581
+ async function upsert2(data) {
582
+ return upsertHelper(cmsPublishedCache, data, {
583
+ target: [cmsPublishedCache.section, cmsPublishedCache.locale],
584
+ set: {
585
+ content: data.content,
586
+ publishedAt: data.publishedAt,
587
+ publishedBy: data.publishedBy,
588
+ version: sql`${cmsPublishedCache.version} + 1`
589
+ // 버전 증가로 클라이언트 캐시 무효화
590
+ }
591
+ });
592
+ }
593
+ async function findAllLanguages(section) {
594
+ return findMany3(cmsPublishedCache, {
595
+ where: eq2(cmsPublishedCache.section, section)
596
+ });
597
+ }
598
+ async function deleteBySection(section, locale) {
599
+ if (locale) {
600
+ await deleteOne2(
601
+ cmsPublishedCache,
602
+ and2(
603
+ eq2(cmsPublishedCache.section, section),
604
+ eq2(cmsPublishedCache.locale, locale)
605
+ )
606
+ );
607
+ } else {
608
+ await deleteMany2(
609
+ cmsPublishedCache,
610
+ eq2(cmsPublishedCache.section, section)
611
+ );
612
+ }
613
+ }
614
+ var cmsPublishedCacheRepository = {
615
+ findBySection: findBySection2,
616
+ upsert: upsert2,
617
+ findAllLanguages,
618
+ deleteBySection
619
+ };
620
+
621
+ // src/server/helpers/publish.ts
622
+ async function publishLabel(labelId, options) {
623
+ const label = await cmsLabelsRepository.findById(labelId);
624
+ if (!label) {
625
+ throw new Error(`Label with id ${labelId} not found`);
626
+ }
627
+ const drafts = await cmsLabelValuesRepository.findDraftsByLabelId(labelId);
628
+ if (drafts.length === 0) {
629
+ throw new Error(`No draft values found for label ${labelId}`);
630
+ }
631
+ const nextVersion = (label.publishedVersion ?? 0) + 1;
632
+ for (const draft of drafts) {
633
+ await cmsLabelValuesRepository.upsert({
634
+ labelId: draft.labelId,
635
+ version: nextVersion,
636
+ locale: draft.locale,
637
+ breakpoint: draft.breakpoint,
638
+ value: draft.value
639
+ });
640
+ }
641
+ await cmsLabelsRepository.updateById(labelId, {
642
+ publishedVersion: nextVersion
643
+ });
644
+ await updatePublishedCache(label.section, options?.publishedBy);
645
+ return {
646
+ version: nextVersion,
647
+ message: `Label published as version ${nextVersion}`
648
+ };
649
+ }
650
+ async function updatePublishedCache(section, publishedBy) {
651
+ const labels = await cmsLabelsRepository.findBySection(section);
652
+ const locales = process.env.SPFN_CMS_SUPPORTED_LOCALES?.split(",") || ["ko", "en", "ja"];
653
+ for (const locale of locales) {
654
+ const content = {};
655
+ for (const label of labels) {
656
+ if (label.publishedVersion !== null) {
657
+ const values = await cmsLabelValuesRepository.findByLabelIdAndVersion(
658
+ label.id,
659
+ label.publishedVersion,
660
+ { locale }
661
+ );
662
+ if (values.length > 0) {
663
+ content[label.key] = values[0].value;
664
+ continue;
665
+ }
666
+ }
667
+ if (label.defaultValue) {
668
+ try {
669
+ const parsed = JSON.parse(label.defaultValue);
670
+ if (typeof parsed === "object" && !Array.isArray(parsed)) {
671
+ if (parsed[locale]) {
672
+ content[label.key] = parsed[locale];
673
+ }
674
+ } else {
675
+ content[label.key] = parsed;
676
+ }
677
+ } catch {
678
+ content[label.key] = label.defaultValue;
679
+ }
680
+ }
681
+ }
682
+ await cmsPublishedCacheRepository.upsert({
683
+ section,
684
+ locale,
685
+ content,
686
+ publishedAt: /* @__PURE__ */ new Date(),
687
+ publishedBy: publishedBy || "system"
688
+ });
689
+ }
690
+ }
691
+
692
+ // src/server/routes/labels/[id]/publish/index.ts
693
+ var app = createApp();
694
+ app.bind(publishLabelContract, async (c) => {
695
+ const { id } = c.params;
696
+ const body = await c.data();
697
+ try {
698
+ const result = await publishLabel(parseInt(id), {
699
+ notes: body.notes,
700
+ publishedBy: body.publishedBy
701
+ });
702
+ return c.json({
703
+ success: true,
704
+ id: parseInt(id),
705
+ version: result.version,
706
+ message: result.message
707
+ });
708
+ } catch (error) {
709
+ const err = error;
710
+ return c.json(
711
+ { error: err.message },
712
+ 400
713
+ );
714
+ }
715
+ });
716
+ var publish_default = app;
717
+ export {
718
+ publish_default as default
719
+ };
720
+ //# sourceMappingURL=index.js.map