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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/dist/actions.d.ts +140 -6
  2. package/dist/actions.js +97 -10
  3. package/dist/actions.js.map +1 -1
  4. package/dist/client.d.ts +43 -9
  5. package/dist/client.js +406 -56
  6. package/dist/client.js.map +1 -1
  7. package/dist/contracts/labels.d.ts +149 -0
  8. package/dist/contracts/labels.js +166 -0
  9. package/dist/contracts/labels.js.map +1 -0
  10. package/dist/contracts/published-cache.d.ts +25 -0
  11. package/dist/contracts/published-cache.js +32 -0
  12. package/dist/contracts/published-cache.js.map +1 -0
  13. package/dist/contracts/values.d.ts +69 -0
  14. package/dist/contracts/values.js +100 -0
  15. package/dist/contracts/values.js.map +1 -0
  16. package/dist/entities/cms-audit-logs.d.ts +15 -70
  17. package/dist/entities/cms-audit-logs.js +75 -100
  18. package/dist/entities/cms-audit-logs.js.map +1 -1
  19. package/dist/entities/cms-draft-cache.d.ts +13 -73
  20. package/dist/entities/cms-draft-cache.js +35 -109
  21. package/dist/entities/cms-draft-cache.js.map +1 -1
  22. package/dist/entities/cms-label-values.d.ts +14 -65
  23. package/dist/entities/cms-label-values.js +78 -102
  24. package/dist/entities/cms-label-values.js.map +1 -1
  25. package/dist/entities/cms-label-versions.d.ts +16 -49
  26. package/dist/entities/cms-label-versions.js +73 -77
  27. package/dist/entities/cms-label-versions.js.map +1 -1
  28. package/dist/entities/cms-labels.d.ts +17 -14
  29. package/dist/entities/cms-labels.js +39 -45
  30. package/dist/entities/cms-labels.js.map +1 -1
  31. package/dist/entities/cms-published-cache.d.ts +14 -69
  32. package/dist/entities/cms-published-cache.js +33 -100
  33. package/dist/entities/cms-published-cache.js.map +1 -1
  34. package/dist/entities/index.d.ts +7 -10
  35. package/dist/entities/index.js +217 -9
  36. package/dist/entities/index.js.map +1 -1
  37. package/dist/generators/index.d.ts +8 -7
  38. package/dist/generators/index.js +657 -17
  39. package/dist/generators/index.js.map +1 -1
  40. package/dist/index.d.ts +134 -20
  41. package/dist/index.js +1115 -23
  42. package/dist/index.js.map +1 -1
  43. package/dist/{generators/label-sync-generator.d.ts → label-sync-generator-lQrcVfja.d.ts} +9 -6
  44. package/dist/labels/index.d.ts +31 -4
  45. package/dist/labels/index.js +31 -6
  46. package/dist/labels/index.js.map +1 -1
  47. package/dist/repositories/index.d.ts +205 -6
  48. package/dist/repositories/index.js +435 -8
  49. package/dist/repositories/index.js.map +1 -1
  50. package/dist/routes/labels/[id]/index.js +499 -89
  51. package/dist/routes/labels/[id]/index.js.map +1 -1
  52. package/dist/routes/labels/{[id] → _id_}/index.d.ts +5 -3
  53. package/dist/routes/labels/by-key/[key]/index.js +453 -29
  54. package/dist/routes/labels/by-key/[key]/index.js.map +1 -1
  55. package/dist/routes/labels/by-key/_key_/index.d.ts +10 -0
  56. package/dist/routes/labels/index.d.ts +5 -3
  57. package/dist/routes/labels/index.js +488 -68
  58. package/dist/routes/labels/index.js.map +1 -1
  59. package/dist/routes/published-cache/index.d.ts +5 -3
  60. package/dist/routes/published-cache/index.js +325 -30
  61. package/dist/routes/published-cache/index.js.map +1 -1
  62. package/dist/routes/values/[labelId]/[version]/index.js +467 -41
  63. package/dist/routes/values/[labelId]/[version]/index.js.map +1 -1
  64. package/dist/routes/values/[labelId]/index.js +463 -39
  65. package/dist/routes/values/[labelId]/index.js.map +1 -1
  66. package/dist/routes/values/_labelId_/_version_/index.d.ts +10 -0
  67. package/dist/routes/values/_labelId_/index.d.ts +10 -0
  68. package/dist/server.d.ts +17 -7
  69. package/dist/server.js +263 -252
  70. package/dist/server.js.map +1 -1
  71. package/dist/store.d.ts +8 -14
  72. package/dist/store.js +396 -198
  73. package/dist/store.js.map +1 -1
  74. package/dist/types.d.ts +14 -7
  75. package/dist/types.js +0 -6
  76. package/dist/types.js.map +1 -1
  77. package/migrations/0000_condemned_centennial.sql +89 -0
  78. package/migrations/meta/0000_snapshot.json +687 -0
  79. package/migrations/meta/_journal.json +13 -0
  80. package/package.json +33 -16
  81. package/dist/actions.d.ts.map +0 -1
  82. package/dist/client.d.ts.map +0 -1
  83. package/dist/cms.config.d.ts +0 -77
  84. package/dist/cms.config.d.ts.map +0 -1
  85. package/dist/cms.config.js +0 -111
  86. package/dist/cms.config.js.map +0 -1
  87. package/dist/entities/cms-audit-logs.d.ts.map +0 -1
  88. package/dist/entities/cms-draft-cache.d.ts.map +0 -1
  89. package/dist/entities/cms-label-values.d.ts.map +0 -1
  90. package/dist/entities/cms-label-versions.d.ts.map +0 -1
  91. package/dist/entities/cms-labels.d.ts.map +0 -1
  92. package/dist/entities/cms-published-cache.d.ts.map +0 -1
  93. package/dist/entities/index.d.ts.map +0 -1
  94. package/dist/generators/index.d.ts.map +0 -1
  95. package/dist/generators/label-sync-generator.d.ts.map +0 -1
  96. package/dist/generators/label-sync-generator.js +0 -87
  97. package/dist/generators/label-sync-generator.js.map +0 -1
  98. package/dist/helpers/locale.actions.d.ts +0 -132
  99. package/dist/helpers/locale.actions.d.ts.map +0 -1
  100. package/dist/helpers/locale.actions.js +0 -210
  101. package/dist/helpers/locale.actions.js.map +0 -1
  102. package/dist/helpers/locale.constants.d.ts +0 -10
  103. package/dist/helpers/locale.constants.d.ts.map +0 -1
  104. package/dist/helpers/locale.constants.js +0 -10
  105. package/dist/helpers/locale.constants.js.map +0 -1
  106. package/dist/helpers/locale.d.ts +0 -17
  107. package/dist/helpers/locale.d.ts.map +0 -1
  108. package/dist/helpers/locale.js +0 -20
  109. package/dist/helpers/locale.js.map +0 -1
  110. package/dist/helpers/sync.d.ts +0 -41
  111. package/dist/helpers/sync.d.ts.map +0 -1
  112. package/dist/helpers/sync.js +0 -309
  113. package/dist/helpers/sync.js.map +0 -1
  114. package/dist/index.d.ts.map +0 -1
  115. package/dist/init.d.ts +0 -31
  116. package/dist/init.d.ts.map +0 -1
  117. package/dist/init.js +0 -36
  118. package/dist/init.js.map +0 -1
  119. package/dist/labels/helpers.d.ts +0 -31
  120. package/dist/labels/helpers.d.ts.map +0 -1
  121. package/dist/labels/helpers.js +0 -60
  122. package/dist/labels/helpers.js.map +0 -1
  123. package/dist/labels/index.d.ts.map +0 -1
  124. package/dist/repositories/cms-draft-cache.repository.d.ts +0 -62
  125. package/dist/repositories/cms-draft-cache.repository.d.ts.map +0 -1
  126. package/dist/repositories/cms-draft-cache.repository.js +0 -56
  127. package/dist/repositories/cms-draft-cache.repository.js.map +0 -1
  128. package/dist/repositories/cms-label-values.repository.d.ts +0 -32
  129. package/dist/repositories/cms-label-values.repository.d.ts.map +0 -1
  130. package/dist/repositories/cms-label-values.repository.js +0 -72
  131. package/dist/repositories/cms-label-values.repository.js.map +0 -1
  132. package/dist/repositories/cms-labels.repository.d.ts +0 -53
  133. package/dist/repositories/cms-labels.repository.d.ts.map +0 -1
  134. package/dist/repositories/cms-labels.repository.js +0 -77
  135. package/dist/repositories/cms-labels.repository.js.map +0 -1
  136. package/dist/repositories/cms-published-cache.repository.d.ts +0 -53
  137. package/dist/repositories/cms-published-cache.repository.d.ts.map +0 -1
  138. package/dist/repositories/cms-published-cache.repository.js +0 -54
  139. package/dist/repositories/cms-published-cache.repository.js.map +0 -1
  140. package/dist/repositories/index.d.ts.map +0 -1
  141. package/dist/routes/labels/[id]/contract.d.ts +0 -68
  142. package/dist/routes/labels/[id]/contract.d.ts.map +0 -1
  143. package/dist/routes/labels/[id]/contract.js +0 -84
  144. package/dist/routes/labels/[id]/contract.js.map +0 -1
  145. package/dist/routes/labels/[id]/index.d.ts.map +0 -1
  146. package/dist/routes/labels/by-key/[key]/contract.d.ts +0 -24
  147. package/dist/routes/labels/by-key/[key]/contract.d.ts.map +0 -1
  148. package/dist/routes/labels/by-key/[key]/contract.js +0 -28
  149. package/dist/routes/labels/by-key/[key]/contract.js.map +0 -1
  150. package/dist/routes/labels/by-key/[key]/index.d.ts +0 -8
  151. package/dist/routes/labels/by-key/[key]/index.d.ts.map +0 -1
  152. package/dist/routes/labels/contract.d.ts +0 -59
  153. package/dist/routes/labels/contract.d.ts.map +0 -1
  154. package/dist/routes/labels/contract.js +0 -75
  155. package/dist/routes/labels/contract.js.map +0 -1
  156. package/dist/routes/labels/index.d.ts.map +0 -1
  157. package/dist/routes/published-cache/contract.d.ts +0 -25
  158. package/dist/routes/published-cache/contract.d.ts.map +0 -1
  159. package/dist/routes/published-cache/contract.js +0 -35
  160. package/dist/routes/published-cache/contract.js.map +0 -1
  161. package/dist/routes/published-cache/index.d.ts.map +0 -1
  162. package/dist/routes/values/[labelId]/[version]/contract.d.ts +0 -29
  163. package/dist/routes/values/[labelId]/[version]/contract.d.ts.map +0 -1
  164. package/dist/routes/values/[labelId]/[version]/contract.js +0 -33
  165. package/dist/routes/values/[labelId]/[version]/contract.js.map +0 -1
  166. package/dist/routes/values/[labelId]/[version]/index.d.ts +0 -8
  167. package/dist/routes/values/[labelId]/[version]/index.d.ts.map +0 -1
  168. package/dist/routes/values/[labelId]/contract.d.ts +0 -38
  169. package/dist/routes/values/[labelId]/contract.d.ts.map +0 -1
  170. package/dist/routes/values/[labelId]/contract.js +0 -59
  171. package/dist/routes/values/[labelId]/contract.js.map +0 -1
  172. package/dist/routes/values/[labelId]/index.d.ts +0 -8
  173. package/dist/routes/values/[labelId]/index.d.ts.map +0 -1
  174. package/dist/server.d.ts.map +0 -1
  175. package/dist/store.d.ts.map +0 -1
  176. package/dist/types.d.ts.map +0 -1
package/dist/client.js CHANGED
@@ -1,62 +1,412 @@
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 = {
1
+ // src/client.ts
2
+ import { client } from "@spfn/core/client";
3
+
4
+ // src/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
+ limit: Type.Optional(Type.Number({ minimum: 1, maximum: 100, default: 20, description: "\uD398\uC774\uC9C0\uB2F9 \uD56D\uBAA9 \uC218" })),
12
+ offset: Type.Optional(Type.Number({ minimum: 0, default: 0, description: "\uC2DC\uC791 \uC624\uD504\uC14B" }))
13
+ }),
14
+ response: Type.Object({
15
+ labels: Type.Array(Type.Object({
16
+ id: Type.Number(),
17
+ key: Type.String(),
18
+ section: Type.String(),
19
+ type: Type.String(),
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
+ })),
25
+ total: Type.Number(),
26
+ limit: Type.Number(),
27
+ offset: Type.Number()
28
+ })
29
+ };
30
+ var createLabelContract = {
31
+ method: "POST",
32
+ path: "/cms/labels",
33
+ body: Type.Object({
34
+ key: Type.String({
35
+ description: "\uACE0\uC720 \uD0A4 (\uC608: home.hero.title)",
36
+ pattern: "^[a-z0-9-]+\\.[a-z0-9-]+\\.[a-z0-9-]+$"
37
+ }),
38
+ section: Type.String({
39
+ description: "\uC139\uC158 \uC774\uB984 (\uC608: home, why-futureplay)",
40
+ pattern: "^[a-z0-9-]+$"
41
+ }),
42
+ type: Type.Union([
43
+ Type.Literal("text"),
44
+ Type.Literal("image"),
45
+ Type.Literal("video"),
46
+ Type.Literal("file"),
47
+ Type.Literal("object")
48
+ ], { description: "\uAC12 \uD0C0\uC785" }),
49
+ createdBy: Type.Optional(Type.String({ description: "\uC0DD\uC131\uC790 ID" }))
50
+ }),
51
+ response: Type.Union([
52
+ Type.Object({
53
+ id: Type.Number(),
54
+ key: Type.String(),
55
+ section: Type.String(),
56
+ type: Type.String(),
57
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
58
+ createdBy: Type.Union([Type.String(), Type.Null()]),
59
+ createdAt: Type.String(),
60
+ updatedAt: Type.String()
61
+ }),
62
+ Type.Object({
63
+ error: Type.String(),
64
+ key: Type.Optional(Type.String())
65
+ })
66
+ ])
67
+ };
68
+ var getLabelContract = {
69
+ method: "GET",
70
+ path: "/cms/labels/:id",
71
+ params: Type.Object({
72
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
73
+ }),
74
+ response: Type.Union([
75
+ Type.Object({
76
+ id: Type.Number(),
77
+ key: Type.String(),
78
+ section: Type.String(),
79
+ type: Type.String(),
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
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
113
+ createdBy: Type.Union([Type.String(), Type.Null()]),
114
+ createdAt: Type.String(),
115
+ updatedAt: Type.String()
116
+ }),
117
+ Type.Object({
118
+ error: Type.String()
119
+ })
120
+ ])
121
+ };
122
+ var deleteLabelContract = {
123
+ method: "DELETE",
124
+ path: "/cms/labels/:id",
125
+ params: Type.Object({
126
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
127
+ }),
128
+ response: Type.Union([
129
+ Type.Object({
130
+ success: Type.Boolean(),
131
+ id: Type.Number()
132
+ }),
133
+ Type.Object({
134
+ error: Type.String()
135
+ })
136
+ ])
137
+ };
138
+ var getLabelByKeyContract = {
139
+ method: "GET",
140
+ path: "/cms/labels/by-key/:key",
141
+ params: Type.Object({
142
+ key: Type.String({ description: "\uB77C\uBCA8 Key (\uC608: home.hero.title)" })
143
+ }),
144
+ response: Type.Union([
145
+ Type.Object({
146
+ id: Type.Number(),
147
+ key: Type.String(),
148
+ section: Type.String(),
149
+ type: Type.String(),
150
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
151
+ createdBy: Type.Union([Type.String(), Type.Null()]),
152
+ createdAt: Type.String(),
153
+ updatedAt: Type.String()
154
+ }),
155
+ Type.Object({
156
+ error: Type.String(),
157
+ key: Type.Optional(Type.String())
158
+ })
159
+ ])
160
+ };
161
+
162
+ // src/contracts/published-cache.ts
163
+ import { Type as Type2 } from "@sinclair/typebox";
164
+ var SectionData = Type2.Object({
165
+ section: Type2.String(),
166
+ locale: Type2.String(),
167
+ content: Type2.Record(Type2.String(), Type2.Any()),
168
+ version: Type2.Number(),
169
+ publishedAt: Type2.Union([Type2.String(), Type2.Null()])
170
+ });
171
+ var getPublishedCacheContract = {
172
+ method: "GET",
173
+ path: "/cms/published-cache",
174
+ query: Type2.Object({
175
+ sections: Type2.Union([
176
+ Type2.String({ description: "\uB2E8\uC77C \uC139\uC158 \uC774\uB984 (\uC608: home)" }),
177
+ Type2.Array(Type2.String(), { description: '\uC5EC\uB7EC \uC139\uC158 \uC774\uB984 (\uC608: ["home", "footer"])' })
178
+ ]),
179
+ locale: Type2.Optional(Type2.String({ default: "ko", description: "\uC5B8\uC5B4 \uCF54\uB4DC" }))
180
+ }),
181
+ response: Type2.Union([
182
+ // 성공: 항상 배열로 반환
183
+ Type2.Array(SectionData),
184
+ // 에러
185
+ Type2.Object({
186
+ error: Type2.String()
187
+ })
188
+ ])
189
+ };
190
+
191
+ // src/store.ts
192
+ import React from "react";
193
+ import { create } from "zustand";
194
+ function replaceVariables(text, replace) {
195
+ return text.replace(/\{(\w+)}/g, (match, key) => {
196
+ const value = replace[key];
197
+ return value !== void 0 ? String(value) : match;
198
+ });
199
+ }
200
+ var useCmsStore = create((set, get) => ({
201
+ sections: {},
202
+ loading: {},
203
+ setSection: (section, data) => {
204
+ set((state) => ({
205
+ sections: {
206
+ ...state.sections,
207
+ [section]: data
208
+ }
209
+ }));
210
+ },
211
+ setSections: (sections) => {
212
+ set((state) => ({
213
+ sections: {
214
+ ...state.sections,
215
+ ...sections
216
+ }
217
+ }));
218
+ },
219
+ loadSection: async (section, locale = "ko") => {
220
+ const state = get();
221
+ if (state.loading[section]) {
222
+ return;
223
+ }
224
+ if (state.sections[section]) {
225
+ return;
226
+ }
227
+ set((state2) => ({
228
+ loading: { ...state2.loading, [section]: true }
229
+ }));
230
+ try {
231
+ const response = await cmsApi.publishedCache.get({
232
+ query: { sections: section, locale }
233
+ });
234
+ if ("error" in response) {
235
+ console.error(`Failed to load section ${section}:`, response.error);
236
+ return;
237
+ }
238
+ const data = response[0];
239
+ if (!data) {
240
+ console.warn(`Section ${section} not found`);
241
+ return;
242
+ }
243
+ const sectionData = {
244
+ section: data.section,
245
+ locale: data.locale,
246
+ content: data.content || {},
247
+ version: data.version || 0,
248
+ publishedAt: data.publishedAt || null
249
+ };
250
+ set((state2) => ({
251
+ sections: {
252
+ ...state2.sections,
253
+ [section]: sectionData
254
+ },
255
+ loading: { ...state2.loading, [section]: false }
256
+ }));
257
+ } catch (error) {
258
+ console.error(`Error loading CMS section ${section}:`, error);
259
+ set((state2) => ({
260
+ loading: { ...state2.loading, [section]: false }
261
+ }));
262
+ }
263
+ },
264
+ updateLabel: (section, key, value) => {
265
+ set((state) => ({
266
+ sections: {
267
+ ...state.sections,
268
+ [section]: {
269
+ ...state.sections[section],
270
+ content: {
271
+ ...state.sections[section]?.content,
272
+ [`${section}.${key}`]: value
273
+ }
274
+ }
275
+ }
276
+ }));
277
+ },
278
+ reset: () => {
279
+ set({
280
+ sections: {},
281
+ loading: {}
282
+ });
283
+ }
284
+ }));
285
+ function useSection(section, options = {}) {
286
+ const { autoLoad = false, locale = "ko" } = options;
287
+ const sectionData = useCmsStore((state) => state.sections[section]);
288
+ const loading = useCmsStore((state) => state.loading[section] ?? false);
289
+ const loadSection = useCmsStore((state) => state.loadSection);
290
+ React.useEffect(() => {
291
+ if (autoLoad && !sectionData && !loading) {
292
+ loadSection(section, locale);
293
+ }
294
+ }, [autoLoad, section, locale, sectionData, loading, loadSection]);
295
+ const t = React.useCallback(
296
+ (key, defaultValue, replace) => {
297
+ if (!sectionData) {
298
+ return defaultValue;
299
+ }
300
+ const fullKey = `${section}.${key}`;
301
+ let value = sectionData.content[fullKey];
302
+ if (value === void 0) {
303
+ value = defaultValue;
304
+ }
305
+ if (typeof value === "string" && replace) {
306
+ value = replaceVariables(value, replace);
307
+ }
308
+ return value;
309
+ },
310
+ [section, sectionData]
311
+ );
312
+ return {
313
+ t,
314
+ data: sectionData,
315
+ loading
316
+ };
317
+ }
318
+ function useSections(sectionNames) {
319
+ const allSections = useCmsStore((state) => state.sections);
320
+ const allLoading = useCmsStore((state) => state.loading);
321
+ const result = {};
322
+ sectionNames.forEach((section) => {
323
+ const sectionData = allSections[section];
324
+ const loading = allLoading[section] ?? false;
325
+ const t = (key, defaultValue, replace) => {
326
+ if (!sectionData) {
327
+ return defaultValue;
328
+ }
329
+ const fullKey = `${section}.${key}`;
330
+ let value = sectionData.content[fullKey];
331
+ if (value === void 0) {
332
+ value = defaultValue;
333
+ }
334
+ if (typeof value === "string" && replace) {
335
+ value = replaceVariables(value, replace);
336
+ }
337
+ return value;
338
+ };
339
+ result[section] = {
340
+ t,
341
+ data: sectionData,
342
+ loading
343
+ };
344
+ });
345
+ return result;
346
+ }
347
+
348
+ // src/init.tsx
349
+ import { useEffect } from "react";
350
+ function InitCms({ sections }) {
351
+ const setSections = useCmsStore((state) => state.setSections);
352
+ useEffect(() => {
353
+ const sectionsData = {};
354
+ Object.entries(sections).forEach(([key, { data }]) => {
355
+ sectionsData[key] = data;
356
+ });
357
+ setSections(sectionsData);
358
+ }, [sections, setSections]);
359
+ return null;
360
+ }
361
+
362
+ // src/client.ts
363
+ var cmsApi = {
364
+ /**
365
+ * Labels API
366
+ */
367
+ labels: {
17
368
  /**
18
- * Labels API
369
+ * GET /cms/labels
370
+ * 라벨 목록 조회 (섹션 필터, 페이지네이션)
19
371
  */
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
- },
372
+ list: (options) => client.call(getLabelsContract, options),
47
373
  /**
48
- * Published Cache API
374
+ * GET /cms/labels/:id
375
+ * 특정 라벨 조회
49
376
  */
50
- publishedCache: {
51
- /**
52
- * GET /cms/published-cache
53
- * 발행된 콘텐츠 캐시 조회
54
- */
55
- get: (options) => client.call('/cms/published-cache', getPublishedCacheContract, options),
56
- },
377
+ getById: (options) => client.call(getLabelContract, options),
378
+ /**
379
+ * POST /cms/labels
380
+ * 라벨 생성
381
+ */
382
+ create: (options) => client.call(createLabelContract, options),
383
+ /**
384
+ * PATCH /cms/labels/:id
385
+ * 라벨 업데이트
386
+ */
387
+ update: (options) => client.call(updateLabelContract, options),
388
+ /**
389
+ * DELETE /cms/labels/:id
390
+ * 라벨 삭제
391
+ */
392
+ delete: (options) => client.call(deleteLabelContract, options)
393
+ },
394
+ /**
395
+ * Published Cache API
396
+ */
397
+ publishedCache: {
398
+ /**
399
+ * GET /cms/published-cache
400
+ * 발행된 콘텐츠 캐시 조회
401
+ */
402
+ get: (options) => client.call(getPublishedCacheContract, options)
403
+ }
404
+ };
405
+ export {
406
+ InitCms,
407
+ cmsApi,
408
+ useCmsStore,
409
+ useSection,
410
+ useSections
57
411
  };
58
- // Client-side Store & Hooks
59
- export { useCmsStore, useSection, useSections } from './store';
60
- // Client-side Initializer
61
- export { InitCms } from './init';
62
412
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,SAAS;AACT,OAAO,EACH,iBAAiB,EACjB,mBAAmB,EACtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACH,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACtB,MAAM,+BAA+B,CAAC;AAEvC,kBAAkB;AAClB,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAE9E;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IAClB;;OAEG;IACH,MAAM,EAAE;QACJ;;;WAGG;QACH,IAAI,EAAE,CAAC,OAAsE,EAAE,EAAE,CAC7E,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,iBAAiB,EAAE,OAAO,CAAC;QAE1D;;;WAGG;QACH,OAAO,EAAE,CAAC,OAAqE,EAAE,EAAE,CAC/E,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,EAAE,OAAO,CAAC;QAE7D;;;WAGG;QACH,MAAM,EAAE,CAAC,OAAoE,EAAE,EAAE,CAC7E,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,mBAAmB,EAAE,OAAO,CAAC;QAE5D;;;WAGG;QACH,MAAM,EAAE,CAAC,OAGR,EAAE,EAAE,CACD,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,mBAAmB,EAAE,OAAO,CAAC;QAEhE;;;WAGG;QACH,MAAM,EAAE,CAAC,OAAwE,EAAE,EAAE,CACjF,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,mBAAmB,EAAE,OAAO,CAAC;KACnE;IAED;;OAEG;IACH,cAAc,EAAE;QACZ;;;WAGG;QACH,GAAG,EAAE,CAAC,OAA4E,EAAE,EAAE,CAClF,MAAM,CAAC,IAAI,CAAC,sBAAsB,EAAE,yBAAyB,EAAE,OAAO,CAAC;KAC9E;CACK,CAAC;AAOX,4BAA4B;AAC5B,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE/D,0BAA0B;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"sources":["../src/client.ts","../src/contracts/labels.ts","../src/contracts/published-cache.ts","../src/store.ts","../src/init.tsx"],"sourcesContent":["/**\n * @spfn/cms/client\n *\n * Client Components Only\n * 클라이언트 컴포넌트 전용 (브라우저에서 실행)\n */\n\nimport { client } from '@spfn/core/client';\nimport type { InferContract } from '@spfn/core';\n\n// Labels\nimport {\n getLabelsContract,\n createLabelContract,\n getLabelContract,\n updateLabelContract,\n deleteLabelContract\n} from './contracts/labels';\n\n// Published Cache\nimport { getPublishedCacheContract } from './contracts/published-cache';\n\n/**\n * CMS API Client\n */\nexport const cmsApi = {\n /**\n * Labels API\n */\n labels: {\n /**\n * GET /cms/labels\n * 라벨 목록 조회 (섹션 필터, 페이지네이션)\n */\n list: (options?: { query?: InferContract<typeof getLabelsContract>['query'] }) =>\n client.call(getLabelsContract, options),\n\n /**\n * GET /cms/labels/:id\n * 특정 라벨 조회\n */\n getById: (options: { params: InferContract<typeof getLabelContract>['params'] }) =>\n client.call(getLabelContract, options),\n\n /**\n * POST /cms/labels\n * 새 라벨 생성\n */\n create: (options: { body: InferContract<typeof createLabelContract>['body'] }) =>\n client.call(createLabelContract, options),\n\n /**\n * PATCH /cms/labels/:id\n * 라벨 업데이트\n */\n update: (options: {\n params: InferContract<typeof updateLabelContract>['params'];\n body: InferContract<typeof updateLabelContract>['body'];\n }) =>\n client.call(updateLabelContract, options),\n\n /**\n * DELETE /cms/labels/:id\n * 라벨 삭제\n */\n delete: (options: { params: InferContract<typeof deleteLabelContract>['params'] }) =>\n client.call(deleteLabelContract, options),\n },\n\n /**\n * Published Cache API\n */\n publishedCache: {\n /**\n * GET /cms/published-cache\n * 발행된 콘텐츠 캐시 조회\n */\n get: (options: { query: InferContract<typeof getPublishedCacheContract>['query'] }) =>\n client.call(getPublishedCacheContract, options),\n },\n} as const;\n\n/**\n * Type exports\n */\nexport type CmsApi = typeof cmsApi;\n\n// Client-side Store & Hooks\nexport { useCmsStore, useSection, useSections } from './store';\n\n// Client-side Initializer\nexport { InitCms } from './init';","import { Type } from '@sinclair/typebox';\nimport type { RouteContract } from '@spfn/core/route';\n\n/**\n * CMS Labels Contracts\n *\n * 라벨 메타데이터 관리 API\n */\n\n/**\n * GET /cms/labels - 라벨 목록 조회\n */\nexport const getLabelsContract = {\n method: 'GET' as const,\n path: '/cms/labels',\n query: Type.Object({\n section: Type.Optional(Type.String({ description: '섹션으로 필터링 (예: home, why-futureplay)' })),\n limit: Type.Optional(Type.Number({ minimum: 1, maximum: 100, default: 20, description: '페이지당 항목 수' })),\n offset: Type.Optional(Type.Number({ minimum: 0, default: 0, description: '시작 오프셋' }))\n }),\n response: Type.Object({\n labels: Type.Array(Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n })),\n total: Type.Number(),\n limit: Type.Number(),\n offset: Type.Number()\n })\n} as const satisfies RouteContract;\n\n/**\n * POST /cms/labels - 새 라벨 생성\n */\nexport const createLabelContract = {\n method: 'POST' as const,\n path: '/cms/labels',\n body: Type.Object({\n key: Type.String({\n description: '고유 키 (예: home.hero.title)',\n pattern: '^[a-z0-9-]+\\\\.[a-z0-9-]+\\\\.[a-z0-9-]+$'\n }),\n section: Type.String({\n description: '섹션 이름 (예: home, why-futureplay)',\n pattern: '^[a-z0-9-]+$'\n }),\n type: Type.Union([\n Type.Literal('text'),\n Type.Literal('image'),\n Type.Literal('video'),\n Type.Literal('file'),\n Type.Literal('object')\n ], { description: '값 타입' }),\n createdBy: Type.Optional(Type.String({ description: '생성자 ID' }))\n }),\n response: Type.Union([\n Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n Type.Object({\n error: Type.String(),\n key: Type.Optional(Type.String())\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * GET /cms/labels/:id - 라벨 단건 조회\n */\nexport const getLabelContract = {\n method: 'GET' as const,\n path: '/cms/labels/:id',\n params: Type.Object({\n id: Type.String({ description: '라벨 ID' })\n }),\n response: Type.Union([\n Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * PATCH /cms/labels/:id - 라벨 메타데이터 수정\n */\nexport const updateLabelContract = {\n method: 'PATCH' as const,\n path: '/cms/labels/:id',\n params: Type.Object({\n id: Type.String({ description: '라벨 ID' })\n }),\n body: Type.Object({\n section: Type.Optional(Type.String({ description: '섹션 변경' })),\n type: Type.Optional(Type.Union([\n Type.Literal('text'),\n Type.Literal('image'),\n Type.Literal('video'),\n Type.Literal('file'),\n Type.Literal('object')\n ]))\n }),\n response: Type.Union([\n Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * DELETE /cms/labels/:id - 라벨 삭제\n */\nexport const deleteLabelContract = {\n method: 'DELETE' as const,\n path: '/cms/labels/:id',\n params: Type.Object({\n id: Type.String({ description: '라벨 ID' })\n }),\n response: Type.Union([\n Type.Object({\n success: Type.Boolean(),\n id: Type.Number()\n }),\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;\n\n/**\n * GET /cms/labels/by-key/:key - Key로 라벨 조회\n */\nexport const getLabelByKeyContract = {\n method: 'GET' as const,\n path: '/cms/labels/by-key/:key',\n params: Type.Object({\n key: Type.String({ description: '라벨 Key (예: home.hero.title)' })\n }),\n response: Type.Union([\n Type.Object({\n id: Type.Number(),\n key: Type.String(),\n section: Type.String(),\n type: Type.String(),\n publishedVersion: Type.Union([Type.Number(), Type.Null()]),\n createdBy: Type.Union([Type.String(), Type.Null()]),\n createdAt: Type.String(),\n updatedAt: Type.String()\n }),\n Type.Object({\n error: Type.String(),\n key: Type.Optional(Type.String())\n })\n ])\n} as const satisfies RouteContract;","import { Type } from '@sinclair/typebox';\nimport type { RouteContract } from '@spfn/core/route';\n\nconst SectionData = Type.Object({\n section: Type.String(),\n locale: Type.String(),\n content: Type.Record(Type.String(), Type.Any()),\n version: Type.Number(),\n publishedAt: Type.Union([Type.String(), Type.Null()]),\n});\n\n/**\n * GET /cms/published-cache\n * 발행된 콘텐츠 캐시 조회 (단일 또는 여러 섹션)\n */\nexport const getPublishedCacheContract = {\n method: 'GET' as const,\n path: '/cms/published-cache',\n query: Type.Object({\n sections: Type.Union([\n Type.String({ description: '단일 섹션 이름 (예: home)' }),\n Type.Array(Type.String(), { description: '여러 섹션 이름 (예: [\"home\", \"footer\"])' })\n ]),\n locale: Type.Optional(Type.String({ default: 'ko', description: '언어 코드' })),\n }),\n response: Type.Union([\n // 성공: 항상 배열로 반환\n Type.Array(SectionData),\n // 에러\n Type.Object({\n error: Type.String()\n })\n ])\n} as const satisfies RouteContract;","/**\n * CMS Zustand Store\n *\n * 클라이언트 컴포넌트에서 CMS 사용을 위한 상태 관리\n * - 서버에서 초기화된 데이터를 클라이언트로 전달\n * - 클라이언트에서 비동기로 로드 가능\n * - 서버 API와 동일한 패턴 ({ t } 사용)\n */\n\n'use client';\n\nimport React from 'react';\nimport { create } from 'zustand';\nimport { cmsApi } from './client';\nimport type { SectionData } from './server';\n\n/**\n * 변수 치환 헬퍼 (서버와 동일)\n */\nfunction replaceVariables(text: string, replace: Record<string, string | number>): string\n{\n return text.replace(/\\{(\\w+)}/g, (match, key) =>\n {\n const value = replace[key];\n return value !== undefined ? String(value) : match;\n });\n}\n\ninterface CmsState\n{\n /**\n * 섹션별 데이터\n * { 'home': { section: 'home', content: {...}, version: 1, ... }, ... }\n */\n sections: Record<string, SectionData>;\n\n /**\n * 로딩 상태\n */\n loading: Record<string, boolean>;\n\n /**\n * 섹션 데이터 설정 (서버에서 초기화용)\n */\n setSection: (section: string, data: SectionData) => void;\n\n /**\n * 여러 섹션 한번에 설정\n */\n setSections: (sections: Record<string, SectionData>) => void;\n\n /**\n * 섹션 비동기 로드\n */\n loadSection: (section: string, locale?: string) => Promise<void>;\n\n /**\n * 라벨 업데이트 (Draft Mode용)\n */\n updateLabel: (section: string, key: string, value: any) => void;\n\n /**\n * 초기화\n */\n reset: () => void;\n}\n\nexport const useCmsStore = create<CmsState>((set, get) => ({\n sections: {},\n loading: {},\n\n setSection: (section, data) =>\n {\n set((state) => ({\n sections: {\n ...state.sections,\n [section]: data,\n },\n }));\n },\n\n setSections: (sections) =>\n {\n set((state) => ({\n sections: {\n ...state.sections,\n ...sections,\n },\n }));\n },\n\n loadSection: async (section, locale = 'ko') =>\n {\n const state = get();\n\n // 이미 로드 중이면 스킵\n if (state.loading[section])\n {\n return;\n }\n\n // 이미 로드되어 있으면 스킵\n if (state.sections[section])\n {\n return;\n }\n\n set((state) => ({\n loading: { ...state.loading, [section]: true },\n }));\n\n try\n {\n const response = await cmsApi.publishedCache.get({\n query: { sections: section, locale },\n });\n\n // Check for error response\n if ('error' in response)\n {\n console.error(`Failed to load section ${section}:`, response.error);\n return;\n }\n\n // Response is array, get first element\n const data = response[0];\n\n if (!data)\n {\n console.warn(`Section ${section} not found`);\n return;\n }\n\n const sectionData: SectionData = {\n section: data.section,\n locale: data.locale,\n content: (data.content as Record<string, any>) || {},\n version: data.version || 0,\n publishedAt: data.publishedAt || null,\n };\n\n set((state) => ({\n sections: {\n ...state.sections,\n [section]: sectionData,\n },\n loading: { ...state.loading, [section]: false },\n }));\n }\n catch (error)\n {\n console.error(`Error loading CMS section ${section}:`, error);\n set((state) => ({\n loading: { ...state.loading, [section]: false },\n }));\n }\n },\n\n updateLabel: (section, key, value) =>\n {\n set((state) => ({\n sections: {\n ...state.sections,\n [section]: {\n ...state.sections[section],\n content: {\n ...state.sections[section]?.content,\n [`${section}.${key}`]: value,\n },\n },\n },\n }));\n },\n\n reset: () =>\n {\n set({\n sections: {},\n loading: {},\n });\n },\n}));\n\n/**\n * 섹션 Hook (서버 API와 동일한 패턴)\n *\n * @param section - 섹션 이름\n * @param options - 옵션 (autoLoad: 자동 로드 여부)\n * @returns { t, data, loading }\n *\n * @example\n * ```tsx\n * 'use client';\n * import { useSection } from '@/lib/cms';\n *\n * export function ClientComponent()\n * {\n * const { t } = useSection('home');\n * return <h1>{t('hero.title')}</h1>;\n * }\n * ```\n */\nexport function useSection(\n section: string,\n options: { autoLoad?: boolean; locale?: string } = {}\n)\n{\n const { autoLoad = false, locale = 'ko' } = options;\n\n const sectionData = useCmsStore((state) => state.sections[section]);\n const loading = useCmsStore((state) => state.loading[section] ?? false);\n const loadSection = useCmsStore((state) => state.loadSection);\n\n // 자동 로드 옵션이 켜져있고 데이터가 없으면 로드\n React.useEffect(() =>\n {\n if (autoLoad && !sectionData && !loading)\n {\n loadSection(section, locale);\n }\n }, [autoLoad, section, locale, sectionData, loading, loadSection]);\n\n // Translation function (서버와 동일)\n const t = React.useCallback(\n (key: string, defaultValue?: any, replace?: Record<string, string | number>) =>\n {\n if (!sectionData)\n {\n return defaultValue;\n }\n\n const fullKey = `${section}.${key}`;\n let value = sectionData.content[fullKey];\n\n if (value === undefined)\n {\n value = defaultValue;\n }\n\n // 문자열이고 치환 맵이 있으면 변수 치환\n if (typeof value === 'string' && replace)\n {\n value = replaceVariables(value, replace);\n }\n\n return value;\n },\n [section, sectionData]\n );\n\n return {\n t,\n data: sectionData,\n loading,\n };\n}\n\n/**\n * 여러 섹션 Hook\n *\n * @param sectionNames - 섹션 이름 배열\n * @returns { [section]: { t, data, loading }, ... }\n *\n * @example\n * ```tsx\n * const sections = useSections(['home', 'why-futureplay']);\n * sections.home.t('hero.title');\n * ```\n */\nexport function useSections(sectionNames: string[])\n{\n const allSections = useCmsStore((state) => state.sections);\n const allLoading = useCmsStore((state) => state.loading);\n\n const result: Record<string, ReturnType<typeof useSection>> = {};\n\n sectionNames.forEach((section) =>\n {\n const sectionData = allSections[section];\n const loading = allLoading[section] ?? false;\n\n const t = (key: string, defaultValue?: any, replace?: Record<string, string | number>) =>\n {\n if (!sectionData)\n {\n return defaultValue;\n }\n\n const fullKey = `${section}.${key}`;\n let value = sectionData.content[fullKey];\n\n if (value === undefined)\n {\n value = defaultValue;\n }\n\n if (typeof value === 'string' && replace)\n {\n value = replaceVariables(value, replace);\n }\n\n return value;\n };\n\n result[section] = {\n t,\n data: sectionData,\n loading,\n };\n });\n\n return result;\n}","/**\n * CMS Store Initializer\n *\n * 서버 컴포넌트에서 로드한 섹션 데이터를 클라이언트 store에 초기화\n */\n\n'use client';\n\nimport { useEffect } from 'react';\nimport { useCmsStore } from './store';\nimport type { SectionAPI } from './server';\n\ninterface InitCmsProps\n{\n /**\n * 서버에서 로드한 섹션 데이터\n * { home: { t, data }, ... }\n */\n sections: Record<string, SectionAPI>;\n}\n\n/**\n * CMS Store 초기화 컴포넌트\n *\n * 서버 컴포넌트에서 로드한 데이터를 클라이언트 store에 주입\n * 이후 하위 클라이언트 컴포넌트에서 useSection() 사용 가능\n *\n * @param props - InitCmsProps\n * @param props.sections - 서버에서 로드한 섹션 데이터\n *\n * @example\n * // Server Component\n * const home = await getSection('home');\n * <InitCms sections={{ home }} />\n * // 이후 하위 클라이언트 컴포넌트에서 useSection('home') 사용 가능\n */\nexport function InitCms({ sections }: InitCmsProps)\n{\n const setSections = useCmsStore((state) => state.setSections);\n\n useEffect(() =>\n {\n // SectionAPI → SectionData 변환\n const sectionsData: Record<string, any> = {};\n Object.entries(sections).forEach(([key, { data }]) =>\n {\n sectionsData[key] = data;\n });\n\n setSections(sectionsData);\n }, [sections, setSections]);\n\n return null;\n}"],"mappings":"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","names":["Type","state"]}
@@ -0,0 +1,149 @@
1
+ import * as _sinclair_typebox from '@sinclair/typebox';
2
+
3
+ /**
4
+ * CMS Labels Contracts
5
+ *
6
+ * 라벨 메타데이터 관리 API
7
+ */
8
+ /**
9
+ * GET /cms/labels - 라벨 목록 조회
10
+ */
11
+ declare const getLabelsContract: {
12
+ readonly method: "GET";
13
+ readonly path: "/cms/labels";
14
+ readonly query: _sinclair_typebox.TObject<{
15
+ section: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
16
+ limit: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
17
+ offset: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
18
+ }>;
19
+ readonly response: _sinclair_typebox.TObject<{
20
+ labels: _sinclair_typebox.TArray<_sinclair_typebox.TObject<{
21
+ id: _sinclair_typebox.TNumber;
22
+ key: _sinclair_typebox.TString;
23
+ section: _sinclair_typebox.TString;
24
+ type: _sinclair_typebox.TString;
25
+ publishedVersion: _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TNull]>;
26
+ createdBy: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
27
+ createdAt: _sinclair_typebox.TString;
28
+ updatedAt: _sinclair_typebox.TString;
29
+ }>>;
30
+ total: _sinclair_typebox.TNumber;
31
+ limit: _sinclair_typebox.TNumber;
32
+ offset: _sinclair_typebox.TNumber;
33
+ }>;
34
+ };
35
+ /**
36
+ * POST /cms/labels - 새 라벨 생성
37
+ */
38
+ declare const createLabelContract: {
39
+ readonly method: "POST";
40
+ readonly path: "/cms/labels";
41
+ readonly body: _sinclair_typebox.TObject<{
42
+ key: _sinclair_typebox.TString;
43
+ section: _sinclair_typebox.TString;
44
+ type: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"text">, _sinclair_typebox.TLiteral<"image">, _sinclair_typebox.TLiteral<"video">, _sinclair_typebox.TLiteral<"file">, _sinclair_typebox.TLiteral<"object">]>;
45
+ createdBy: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
46
+ }>;
47
+ readonly response: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
48
+ id: _sinclair_typebox.TNumber;
49
+ key: _sinclair_typebox.TString;
50
+ section: _sinclair_typebox.TString;
51
+ type: _sinclair_typebox.TString;
52
+ publishedVersion: _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TNull]>;
53
+ createdBy: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
54
+ createdAt: _sinclair_typebox.TString;
55
+ updatedAt: _sinclair_typebox.TString;
56
+ }>, _sinclair_typebox.TObject<{
57
+ error: _sinclair_typebox.TString;
58
+ key: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
59
+ }>]>;
60
+ };
61
+ /**
62
+ * GET /cms/labels/:id - 라벨 단건 조회
63
+ */
64
+ declare const getLabelContract: {
65
+ readonly method: "GET";
66
+ readonly path: "/cms/labels/:id";
67
+ readonly params: _sinclair_typebox.TObject<{
68
+ id: _sinclair_typebox.TString;
69
+ }>;
70
+ readonly response: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
71
+ id: _sinclair_typebox.TNumber;
72
+ key: _sinclair_typebox.TString;
73
+ section: _sinclair_typebox.TString;
74
+ type: _sinclair_typebox.TString;
75
+ publishedVersion: _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TNull]>;
76
+ createdBy: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
77
+ createdAt: _sinclair_typebox.TString;
78
+ updatedAt: _sinclair_typebox.TString;
79
+ }>, _sinclair_typebox.TObject<{
80
+ error: _sinclair_typebox.TString;
81
+ }>]>;
82
+ };
83
+ /**
84
+ * PATCH /cms/labels/:id - 라벨 메타데이터 수정
85
+ */
86
+ declare const updateLabelContract: {
87
+ readonly method: "PATCH";
88
+ readonly path: "/cms/labels/:id";
89
+ readonly params: _sinclair_typebox.TObject<{
90
+ id: _sinclair_typebox.TString;
91
+ }>;
92
+ readonly body: _sinclair_typebox.TObject<{
93
+ section: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
94
+ type: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"text">, _sinclair_typebox.TLiteral<"image">, _sinclair_typebox.TLiteral<"video">, _sinclair_typebox.TLiteral<"file">, _sinclair_typebox.TLiteral<"object">]>>;
95
+ }>;
96
+ readonly response: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
97
+ id: _sinclair_typebox.TNumber;
98
+ key: _sinclair_typebox.TString;
99
+ section: _sinclair_typebox.TString;
100
+ type: _sinclair_typebox.TString;
101
+ publishedVersion: _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TNull]>;
102
+ createdBy: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
103
+ createdAt: _sinclair_typebox.TString;
104
+ updatedAt: _sinclair_typebox.TString;
105
+ }>, _sinclair_typebox.TObject<{
106
+ error: _sinclair_typebox.TString;
107
+ }>]>;
108
+ };
109
+ /**
110
+ * DELETE /cms/labels/:id - 라벨 삭제
111
+ */
112
+ declare const deleteLabelContract: {
113
+ readonly method: "DELETE";
114
+ readonly path: "/cms/labels/:id";
115
+ readonly params: _sinclair_typebox.TObject<{
116
+ id: _sinclair_typebox.TString;
117
+ }>;
118
+ readonly response: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
119
+ success: _sinclair_typebox.TBoolean;
120
+ id: _sinclair_typebox.TNumber;
121
+ }>, _sinclair_typebox.TObject<{
122
+ error: _sinclair_typebox.TString;
123
+ }>]>;
124
+ };
125
+ /**
126
+ * GET /cms/labels/by-key/:key - Key로 라벨 조회
127
+ */
128
+ declare const getLabelByKeyContract: {
129
+ readonly method: "GET";
130
+ readonly path: "/cms/labels/by-key/:key";
131
+ readonly params: _sinclair_typebox.TObject<{
132
+ key: _sinclair_typebox.TString;
133
+ }>;
134
+ readonly response: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
135
+ id: _sinclair_typebox.TNumber;
136
+ key: _sinclair_typebox.TString;
137
+ section: _sinclair_typebox.TString;
138
+ type: _sinclair_typebox.TString;
139
+ publishedVersion: _sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TNull]>;
140
+ createdBy: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
141
+ createdAt: _sinclair_typebox.TString;
142
+ updatedAt: _sinclair_typebox.TString;
143
+ }>, _sinclair_typebox.TObject<{
144
+ error: _sinclair_typebox.TString;
145
+ key: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
146
+ }>]>;
147
+ };
148
+
149
+ export { createLabelContract, deleteLabelContract, getLabelByKeyContract, getLabelContract, getLabelsContract, updateLabelContract };