@spfn/cms 0.1.0-alpha.0

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 (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +490 -0
  3. package/dist/actions.d.ts +9 -0
  4. package/dist/actions.d.ts.map +1 -0
  5. package/dist/actions.js +11 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/client.d.ts +138 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +62 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/cms.config.d.ts +77 -0
  12. package/dist/cms.config.d.ts.map +1 -0
  13. package/dist/cms.config.js +111 -0
  14. package/dist/cms.config.js.map +1 -0
  15. package/dist/entities/cms-audit-logs.d.ts +213 -0
  16. package/dist/entities/cms-audit-logs.d.ts.map +1 -0
  17. package/dist/entities/cms-audit-logs.js +103 -0
  18. package/dist/entities/cms-audit-logs.js.map +1 -0
  19. package/dist/entities/cms-draft-cache.d.ts +188 -0
  20. package/dist/entities/cms-draft-cache.d.ts.map +1 -0
  21. package/dist/entities/cms-draft-cache.js +112 -0
  22. package/dist/entities/cms-draft-cache.js.map +1 -0
  23. package/dist/entities/cms-label-values.d.ts +192 -0
  24. package/dist/entities/cms-label-values.d.ts.map +1 -0
  25. package/dist/entities/cms-label-values.js +105 -0
  26. package/dist/entities/cms-label-values.js.map +1 -0
  27. package/dist/entities/cms-label-versions.d.ts +207 -0
  28. package/dist/entities/cms-label-versions.d.ts.map +1 -0
  29. package/dist/entities/cms-label-versions.js +80 -0
  30. package/dist/entities/cms-label-versions.js.map +1 -0
  31. package/dist/entities/cms-labels.d.ts +189 -0
  32. package/dist/entities/cms-labels.d.ts.map +1 -0
  33. package/dist/entities/cms-labels.js +48 -0
  34. package/dist/entities/cms-labels.js.map +1 -0
  35. package/dist/entities/cms-published-cache.d.ts +199 -0
  36. package/dist/entities/cms-published-cache.d.ts.map +1 -0
  37. package/dist/entities/cms-published-cache.js +103 -0
  38. package/dist/entities/cms-published-cache.js.map +1 -0
  39. package/dist/entities/index.d.ts +10 -0
  40. package/dist/entities/index.d.ts.map +1 -0
  41. package/dist/entities/index.js +10 -0
  42. package/dist/entities/index.js.map +1 -0
  43. package/dist/generators/index.d.ts +19 -0
  44. package/dist/generators/index.d.ts.map +1 -0
  45. package/dist/generators/index.js +19 -0
  46. package/dist/generators/index.js.map +1 -0
  47. package/dist/generators/label-sync-generator.d.ts +33 -0
  48. package/dist/generators/label-sync-generator.d.ts.map +1 -0
  49. package/dist/generators/label-sync-generator.js +86 -0
  50. package/dist/generators/label-sync-generator.js.map +1 -0
  51. package/dist/helpers/locale.actions.d.ts +132 -0
  52. package/dist/helpers/locale.actions.d.ts.map +1 -0
  53. package/dist/helpers/locale.actions.js +210 -0
  54. package/dist/helpers/locale.actions.js.map +1 -0
  55. package/dist/helpers/locale.constants.d.ts +10 -0
  56. package/dist/helpers/locale.constants.d.ts.map +1 -0
  57. package/dist/helpers/locale.constants.js +10 -0
  58. package/dist/helpers/locale.constants.js.map +1 -0
  59. package/dist/helpers/locale.d.ts +17 -0
  60. package/dist/helpers/locale.d.ts.map +1 -0
  61. package/dist/helpers/locale.js +20 -0
  62. package/dist/helpers/locale.js.map +1 -0
  63. package/dist/helpers/sync.d.ts +41 -0
  64. package/dist/helpers/sync.d.ts.map +1 -0
  65. package/dist/helpers/sync.js +309 -0
  66. package/dist/helpers/sync.js.map +1 -0
  67. package/dist/index.d.ts +20 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +24 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/init.d.ts +31 -0
  72. package/dist/init.d.ts.map +1 -0
  73. package/dist/init.js +36 -0
  74. package/dist/init.js.map +1 -0
  75. package/dist/labels/helpers.d.ts +31 -0
  76. package/dist/labels/helpers.d.ts.map +1 -0
  77. package/dist/labels/helpers.js +60 -0
  78. package/dist/labels/helpers.js.map +1 -0
  79. package/dist/labels/index.d.ts +7 -0
  80. package/dist/labels/index.d.ts.map +1 -0
  81. package/dist/labels/index.js +7 -0
  82. package/dist/labels/index.js.map +1 -0
  83. package/dist/repositories/cms-draft-cache.repository.d.ts +62 -0
  84. package/dist/repositories/cms-draft-cache.repository.d.ts.map +1 -0
  85. package/dist/repositories/cms-draft-cache.repository.js +56 -0
  86. package/dist/repositories/cms-draft-cache.repository.js.map +1 -0
  87. package/dist/repositories/cms-label-values.repository.d.ts +32 -0
  88. package/dist/repositories/cms-label-values.repository.d.ts.map +1 -0
  89. package/dist/repositories/cms-label-values.repository.js +72 -0
  90. package/dist/repositories/cms-label-values.repository.js.map +1 -0
  91. package/dist/repositories/cms-labels.repository.d.ts +53 -0
  92. package/dist/repositories/cms-labels.repository.d.ts.map +1 -0
  93. package/dist/repositories/cms-labels.repository.js +77 -0
  94. package/dist/repositories/cms-labels.repository.js.map +1 -0
  95. package/dist/repositories/cms-published-cache.repository.d.ts +53 -0
  96. package/dist/repositories/cms-published-cache.repository.d.ts.map +1 -0
  97. package/dist/repositories/cms-published-cache.repository.js +54 -0
  98. package/dist/repositories/cms-published-cache.repository.js.map +1 -0
  99. package/dist/repositories/index.d.ts +8 -0
  100. package/dist/repositories/index.d.ts.map +1 -0
  101. package/dist/repositories/index.js +9 -0
  102. package/dist/repositories/index.js.map +1 -0
  103. package/dist/routes/labels/[id]/contract.d.ts +68 -0
  104. package/dist/routes/labels/[id]/contract.d.ts.map +1 -0
  105. package/dist/routes/labels/[id]/contract.js +84 -0
  106. package/dist/routes/labels/[id]/contract.js.map +1 -0
  107. package/dist/routes/labels/[id]/index.d.ts +10 -0
  108. package/dist/routes/labels/[id]/index.d.ts.map +1 -0
  109. package/dist/routes/labels/[id]/index.js +96 -0
  110. package/dist/routes/labels/[id]/index.js.map +1 -0
  111. package/dist/routes/labels/by-key/[key]/contract.d.ts +24 -0
  112. package/dist/routes/labels/by-key/[key]/contract.d.ts.map +1 -0
  113. package/dist/routes/labels/by-key/[key]/contract.js +28 -0
  114. package/dist/routes/labels/by-key/[key]/contract.js.map +1 -0
  115. package/dist/routes/labels/by-key/[key]/index.d.ts +8 -0
  116. package/dist/routes/labels/by-key/[key]/index.d.ts.map +1 -0
  117. package/dist/routes/labels/by-key/[key]/index.js +32 -0
  118. package/dist/routes/labels/by-key/[key]/index.js.map +1 -0
  119. package/dist/routes/labels/contract.d.ts +59 -0
  120. package/dist/routes/labels/contract.d.ts.map +1 -0
  121. package/dist/routes/labels/contract.js +75 -0
  122. package/dist/routes/labels/contract.js.map +1 -0
  123. package/dist/routes/labels/index.d.ts +10 -0
  124. package/dist/routes/labels/index.d.ts.map +1 -0
  125. package/dist/routes/labels/index.js +73 -0
  126. package/dist/routes/labels/index.js.map +1 -0
  127. package/dist/routes/published-cache/contract.d.ts +25 -0
  128. package/dist/routes/published-cache/contract.d.ts.map +1 -0
  129. package/dist/routes/published-cache/contract.js +35 -0
  130. package/dist/routes/published-cache/contract.js.map +1 -0
  131. package/dist/routes/published-cache/index.d.ts +8 -0
  132. package/dist/routes/published-cache/index.d.ts.map +1 -0
  133. package/dist/routes/published-cache/index.js +33 -0
  134. package/dist/routes/published-cache/index.js.map +1 -0
  135. package/dist/routes/sync/contract.d.ts +33 -0
  136. package/dist/routes/sync/contract.d.ts.map +1 -0
  137. package/dist/routes/sync/contract.js +34 -0
  138. package/dist/routes/sync/contract.js.map +1 -0
  139. package/dist/routes/sync/index.d.ts +13 -0
  140. package/dist/routes/sync/index.d.ts.map +1 -0
  141. package/dist/routes/sync/index.js +241 -0
  142. package/dist/routes/sync/index.js.map +1 -0
  143. package/dist/routes/values/[labelId]/[version]/contract.d.ts +29 -0
  144. package/dist/routes/values/[labelId]/[version]/contract.d.ts.map +1 -0
  145. package/dist/routes/values/[labelId]/[version]/contract.js +33 -0
  146. package/dist/routes/values/[labelId]/[version]/contract.js.map +1 -0
  147. package/dist/routes/values/[labelId]/[version]/index.d.ts +8 -0
  148. package/dist/routes/values/[labelId]/[version]/index.d.ts.map +1 -0
  149. package/dist/routes/values/[labelId]/[version]/index.js +45 -0
  150. package/dist/routes/values/[labelId]/[version]/index.js.map +1 -0
  151. package/dist/routes/values/[labelId]/contract.d.ts +38 -0
  152. package/dist/routes/values/[labelId]/contract.d.ts.map +1 -0
  153. package/dist/routes/values/[labelId]/contract.js +59 -0
  154. package/dist/routes/values/[labelId]/contract.js.map +1 -0
  155. package/dist/routes/values/[labelId]/index.d.ts +8 -0
  156. package/dist/routes/values/[labelId]/index.d.ts.map +1 -0
  157. package/dist/routes/values/[labelId]/index.js +42 -0
  158. package/dist/routes/values/[labelId]/index.js.map +1 -0
  159. package/dist/server.d.ts +99 -0
  160. package/dist/server.d.ts.map +1 -0
  161. package/dist/server.js +256 -0
  162. package/dist/server.js.map +1 -0
  163. package/dist/store.d.ts +87 -0
  164. package/dist/store.d.ts.map +1 -0
  165. package/dist/store.js +205 -0
  166. package/dist/store.js.map +1 -0
  167. package/dist/sync.d.ts +11 -0
  168. package/dist/sync.d.ts.map +1 -0
  169. package/dist/sync.js +179 -0
  170. package/dist/sync.js.map +1 -0
  171. package/dist/types.d.ts +74 -0
  172. package/dist/types.d.ts.map +1 -0
  173. package/dist/types.js +7 -0
  174. package/dist/types.js.map +1 -0
  175. package/package.json +95 -0
@@ -0,0 +1,29 @@
1
+ /**
2
+ * GET /cms/values/:labelId/:version - 특정 버전의 값 조회
3
+ */
4
+ export declare const getValuesContract: {
5
+ readonly method: "GET";
6
+ readonly path: "/:labelId/:version";
7
+ readonly params: import("@sinclair/typebox").TObject<{
8
+ labelId: import("@sinclair/typebox").TString;
9
+ version: import("@sinclair/typebox").TString;
10
+ }>;
11
+ readonly query: import("@sinclair/typebox").TObject<{
12
+ locale: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
13
+ breakpoint: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
14
+ }>;
15
+ readonly response: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
16
+ labelId: import("@sinclair/typebox").TNumber;
17
+ version: import("@sinclair/typebox").TNumber;
18
+ values: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
19
+ id: import("@sinclair/typebox").TNumber;
20
+ locale: import("@sinclair/typebox").TString;
21
+ breakpoint: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNull]>;
22
+ value: import("@sinclair/typebox").TAny;
23
+ createdAt: import("@sinclair/typebox").TString;
24
+ }>>;
25
+ }>, import("@sinclair/typebox").TObject<{
26
+ error: import("@sinclair/typebox").TString;
27
+ }>]>;
28
+ };
29
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../../../src/routes/values/[labelId]/[version]/contract.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;CA6BI,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { Type } from '@sinclair/typebox';
2
+ /**
3
+ * GET /cms/values/:labelId/:version - 특정 버전의 값 조회
4
+ */
5
+ export const getValuesContract = {
6
+ method: 'GET',
7
+ path: '/:labelId/:version',
8
+ params: Type.Object({
9
+ labelId: Type.String({ description: '라벨 ID' }),
10
+ version: Type.String({ description: '버전 번호' })
11
+ }),
12
+ query: Type.Object({
13
+ locale: Type.Optional(Type.String({ description: '언어 코드 (ko, en, ja)' })),
14
+ breakpoint: Type.Optional(Type.String({ description: '반응형 브레이크포인트' }))
15
+ }),
16
+ response: Type.Union([
17
+ Type.Object({
18
+ labelId: Type.Number(),
19
+ version: Type.Number(),
20
+ values: Type.Array(Type.Object({
21
+ id: Type.Number(),
22
+ locale: Type.String(),
23
+ breakpoint: Type.Union([Type.String(), Type.Null()]),
24
+ value: Type.Any(),
25
+ createdAt: Type.String()
26
+ }))
27
+ }),
28
+ Type.Object({
29
+ error: Type.String()
30
+ })
31
+ ])
32
+ };
33
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../../../src/routes/values/[labelId]/[version]/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAGzC;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC7B,MAAM,EAAE,KAAc;IACtB,IAAI,EAAE,oBAAoB;IAC1B,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;QAChB,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;QAC9C,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;KACjD,CAAC;IACF,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC;QACf,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAC,CAAC;QACzE,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC,CAAC;KACzE,CAAC;IACF,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC;QACjB,IAAI,CAAC,MAAM,CAAC;YACR,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE;YACtB,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE;YACtB,MAAM,EAAE,IAAI,CAAC,KAAK,CACd,IAAI,CAAC,MAAM,CAAC;gBACR,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE;gBACjB,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;gBACrB,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;gBACpD,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE;gBACjB,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE;aAC3B,CAAC,CACL;SACJ,CAAC;QACF,IAAI,CAAC,MAAM,CAAC;YACR,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE;SACvB,CAAC;KACL,CAAC;CAC4B,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * CMS Label Values Detail Routes
3
+ *
4
+ * - GET /cms/values/:labelId/:version - 특정 버전의 값 조회
5
+ */
6
+ declare const app: import("@spfn/core/route").SPFNApp;
7
+ export default app;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/routes/values/[labelId]/[version]/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,QAAA,MAAM,GAAG,oCAAc,CAAC;AAiDxB,eAAe,GAAG,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * CMS Label Values Detail Routes
3
+ *
4
+ * - GET /cms/values/:labelId/:version - 특정 버전의 값 조회
5
+ */
6
+ import { createApp } from '@spfn/core/route';
7
+ import { cmsLabelsRepository, cmsLabelValuesRepository } from '../../../../repositories';
8
+ import { getValuesContract } from './contract.js';
9
+ const app = createApp();
10
+ /**
11
+ * GET /cms/values/:labelId/:version
12
+ * 특정 버전의 값 조회
13
+ */
14
+ app.bind(getValuesContract, async (c) => {
15
+ const { labelId: labelIdStr, version: versionStr } = c.params;
16
+ const labelId = parseInt(labelIdStr, 10);
17
+ const version = parseInt(versionStr, 10);
18
+ if (isNaN(labelId) || isNaN(version)) {
19
+ return c.json({ error: 'Invalid label ID or version' }, 400);
20
+ }
21
+ const { locale, breakpoint } = c.query;
22
+ // 라벨 존재 확인
23
+ const label = await cmsLabelsRepository.findById(labelId);
24
+ if (!label) {
25
+ return c.json({ error: 'Label not found' }, 404);
26
+ }
27
+ // 값 조회
28
+ const values = await cmsLabelValuesRepository.findByLabelIdAndVersion(labelId, version, {
29
+ locale,
30
+ breakpoint: breakpoint === 'null' ? null : breakpoint,
31
+ });
32
+ return c.json({
33
+ labelId,
34
+ version,
35
+ values: values.map((v) => ({
36
+ id: v.id,
37
+ locale: v.locale,
38
+ breakpoint: v.breakpoint,
39
+ value: v.value,
40
+ createdAt: v.createdAt.toISOString(),
41
+ })),
42
+ });
43
+ });
44
+ export default app;
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/routes/values/[labelId]/[version]/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;AAExB;;;GAGG;AACH,GAAG,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAEpC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9D,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAEzC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,EACpC,CAAC;QACG,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,6BAA6B,EAAE,EAAE,GAAG,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC;IAEvC,WAAW;IACX,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC,KAAK,EACV,CAAC;QACG,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,GAAG,CAAC,CAAC;IACrD,CAAC;IAED,OAAO;IACP,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC,uBAAuB,CACjE,OAAO,EACP,OAAO,EACP;QACI,MAAM;QACN,UAAU,EAAE,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU;KACxD,CACJ,CAAC;IAEF,OAAO,CAAC,CAAC,IAAI,CAAC;QACV,OAAO;QACP,OAAO;QACP,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvB,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE;SACvC,CAAC,CAAC;KACN,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAEH,eAAe,GAAG,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * POST /cms/values/:labelId - 라벨 값 저장
3
+ */
4
+ export declare const saveValuesContract: {
5
+ readonly method: "POST";
6
+ readonly path: "/:labelId";
7
+ readonly params: import("@sinclair/typebox").TObject<{
8
+ labelId: import("@sinclair/typebox").TString;
9
+ }>;
10
+ readonly body: import("@sinclair/typebox").TObject<{
11
+ version: import("@sinclair/typebox").TNumber;
12
+ values: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
13
+ locale: import("@sinclair/typebox").TString;
14
+ breakpoint: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"sm">, import("@sinclair/typebox").TLiteral<"md">, import("@sinclair/typebox").TLiteral<"lg">, import("@sinclair/typebox").TLiteral<"xl">, import("@sinclair/typebox").TLiteral<"2xl">, import("@sinclair/typebox").TNull]>>;
15
+ value: import("@sinclair/typebox").TObject<{
16
+ type: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"text">, import("@sinclair/typebox").TLiteral<"image">, import("@sinclair/typebox").TLiteral<"video">, import("@sinclair/typebox").TLiteral<"file">, import("@sinclair/typebox").TLiteral<"object">]>;
17
+ content: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
18
+ url: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
19
+ alt: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
20
+ width: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
21
+ height: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
22
+ thumbnail: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
23
+ duration: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
24
+ filename: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
25
+ size: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
26
+ fields: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TAny>;
27
+ }>;
28
+ }>>;
29
+ }>;
30
+ readonly response: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
31
+ success: import("@sinclair/typebox").TBoolean;
32
+ saved: import("@sinclair/typebox").TNumber;
33
+ version: import("@sinclair/typebox").TNumber;
34
+ }>, import("@sinclair/typebox").TObject<{
35
+ error: import("@sinclair/typebox").TString;
36
+ }>]>;
37
+ };
38
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../../src/routes/values/[labelId]/contract.ts"],"names":[],"mappings":"AA0BA;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCG,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { Type } from '@sinclair/typebox';
2
+ /**
3
+ * Label Value 타입 정의
4
+ */
5
+ const LabelValueSchema = Type.Object({
6
+ type: Type.Union([
7
+ Type.Literal('text'),
8
+ Type.Literal('image'),
9
+ Type.Literal('video'),
10
+ Type.Literal('file'),
11
+ Type.Literal('object')
12
+ ]),
13
+ content: Type.Optional(Type.String()), // text type
14
+ url: Type.Optional(Type.String()), // image, video, file types
15
+ alt: Type.Optional(Type.String()), // image type
16
+ width: Type.Optional(Type.Number()), // image type
17
+ height: Type.Optional(Type.Number()), // image type
18
+ thumbnail: Type.Optional(Type.String()), // video type
19
+ duration: Type.Optional(Type.Number()), // video type
20
+ filename: Type.Optional(Type.String()), // file type
21
+ size: Type.Optional(Type.Number()), // file type
22
+ fields: Type.Optional(Type.Any()) // object type - recursive structure
23
+ });
24
+ /**
25
+ * POST /cms/values/:labelId - 라벨 값 저장
26
+ */
27
+ export const saveValuesContract = {
28
+ method: 'POST',
29
+ path: '/:labelId',
30
+ params: Type.Object({
31
+ labelId: Type.String({ description: '라벨 ID' })
32
+ }),
33
+ body: Type.Object({
34
+ version: Type.Number({ description: '버전 번호', minimum: 1 }),
35
+ values: Type.Array(Type.Object({
36
+ locale: Type.String({ description: '언어 코드 (ko, en, ja)', default: 'ko' }),
37
+ breakpoint: Type.Optional(Type.Union([
38
+ Type.Literal('sm'),
39
+ Type.Literal('md'),
40
+ Type.Literal('lg'),
41
+ Type.Literal('xl'),
42
+ Type.Literal('2xl'),
43
+ Type.Null()
44
+ ], { description: '반응형 브레이크포인트' })),
45
+ value: LabelValueSchema
46
+ }))
47
+ }),
48
+ response: Type.Union([
49
+ Type.Object({
50
+ success: Type.Boolean(),
51
+ saved: Type.Number(),
52
+ version: Type.Number()
53
+ }),
54
+ Type.Object({
55
+ error: Type.String()
56
+ })
57
+ ])
58
+ };
59
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../../src/routes/values/[labelId]/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * CMS Label Values Routes
3
+ *
4
+ * - POST /cms/values/:labelId - 라벨 값 저장
5
+ */
6
+ declare const app: import("@spfn/core/route").SPFNApp;
7
+ export default app;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/routes/values/[labelId]/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,QAAA,MAAM,GAAG,oCAAc,CAAC;AA2CxB,eAAe,GAAG,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * CMS Label Values Routes
3
+ *
4
+ * - POST /cms/values/:labelId - 라벨 값 저장
5
+ */
6
+ import { createApp } from '@spfn/core/route';
7
+ import { Transactional } from '@spfn/core/db';
8
+ import { cmsLabelsRepository, cmsLabelValuesRepository } from '../../../repositories';
9
+ import { saveValuesContract } from './contract.js';
10
+ const app = createApp();
11
+ /**
12
+ * POST /cms/values/:labelId
13
+ * 라벨 값 저장 (upsert)
14
+ */
15
+ app.bind(saveValuesContract, [Transactional()], async (c) => {
16
+ const { labelId: labelIdStr } = c.params;
17
+ const labelId = parseInt(labelIdStr, 10);
18
+ if (isNaN(labelId)) {
19
+ return c.json({ error: 'Invalid label ID' }, 400);
20
+ }
21
+ const body = await c.data();
22
+ // 라벨 존재 확인
23
+ const label = await cmsLabelsRepository.findById(labelId);
24
+ if (!label) {
25
+ return c.json({ error: 'Label not found' }, 404);
26
+ }
27
+ // 값 저장
28
+ const savedValues = await cmsLabelValuesRepository.upsertMany(body.values.map((v) => ({
29
+ labelId,
30
+ version: body.version,
31
+ locale: v.locale,
32
+ breakpoint: v.breakpoint ?? null,
33
+ value: v.value,
34
+ })));
35
+ return c.json({
36
+ success: true,
37
+ saved: savedValues.length,
38
+ version: body.version,
39
+ });
40
+ });
41
+ export default app;
42
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/routes/values/[labelId]/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;AAExB;;;GAGG;AACH,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,aAAa,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAExD,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAEzC,IAAI,KAAK,CAAC,OAAO,CAAC,EAClB,CAAC;QACG,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAE5B,WAAW;IACX,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC1D,IAAI,CAAC,KAAK,EACV,CAAC;QACG,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,GAAG,CAAC,CAAC;IACrD,CAAC;IAED,OAAO;IACP,MAAM,WAAW,GAAG,MAAM,wBAAwB,CAAC,UAAU,CACzD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACpB,OAAO;QACP,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,IAAI;QAChC,KAAK,EAAE,CAAC,CAAC,KAAK;KACjB,CAAC,CAAC,CACN,CAAC;IAEF,OAAO,CAAC,CAAC,IAAI,CAAC;QACV,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,WAAW,CAAC,MAAM;QACzB,OAAO,EAAE,IAAI,CAAC,OAAO;KACxB,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAEH,eAAe,GAAG,CAAC"}
@@ -0,0 +1,99 @@
1
+ import "server-only";
2
+ /**
3
+ * Section Data Type
4
+ */
5
+ export type SectionData = {
6
+ section: string;
7
+ locale: string;
8
+ content: Record<string, any>;
9
+ version: number;
10
+ publishedAt: string | null;
11
+ };
12
+ /**
13
+ * Translation Function Type (runtime version)
14
+ */
15
+ type ServerTranslationFunction = (key: string, defaultValue?: any, replace?: Record<string, string | number>) => any;
16
+ /**
17
+ * Section API Return Type
18
+ */
19
+ export type SectionAPI = {
20
+ /**
21
+ * 라벨 값 가져오기 (변수 치환 지원)
22
+ *
23
+ * @param key - 라벨 키 (섹션 제외, 예: 'hero.title')
24
+ * @param defaultValue - 기본값
25
+ * @param replace - 변수 치환 맵 (예: { name: 'John' })
26
+ * @returns 라벨 값 (문자열인 경우 변수 치환됨)
27
+ */
28
+ t: ServerTranslationFunction;
29
+ /**
30
+ * 섹션 데이터
31
+ */
32
+ data: SectionData;
33
+ };
34
+ /**
35
+ * 섹션 데이터 로드 (React cache 적용)
36
+ *
37
+ * 동일한 요청 내에서 같은 섹션을 여러 번 요청해도 한 번만 API 호출
38
+ *
39
+ * @param section - 섹션 이름 (예: 'home', 'why-futureplay')
40
+ * @param locale - 언어 코드 (선택, 미지정시 쿠키에서 자동 조회)
41
+ * @returns Section API ({ t, data })
42
+ *
43
+ * @example
44
+ * ```tsx
45
+ * // Server Component
46
+ * import { getSection } from '@spfn/cms/server';
47
+ *
48
+ * export default async function HomePage()
49
+ * {
50
+ * // locale을 지정하지 않으면 쿠키에서 자동으로 가져옴
51
+ * const { t } = await getSection('home');
52
+ *
53
+ * // 또는 명시적으로 locale 지정
54
+ * const { t: tEn } = await getSection('home', 'en');
55
+ *
56
+ * return (
57
+ * <div>
58
+ * <h1>{t('hero.title')}</h1>
59
+ * <p>{t('hero.subtitle', 'Default Subtitle')}</p>
60
+ * <p>{t('hero.greeting', 'Hello {name}!', { name: 'World' })}</p>
61
+ * </div>
62
+ * );
63
+ * }
64
+ * ```
65
+ */
66
+ export declare const getSection: (section: string, locale?: string) => Promise<SectionAPI>;
67
+ /**
68
+ * 여러 섹션 한번에 로드 (React cache 적용)
69
+ * 단일 API 호출로 여러 섹션을 효율적으로 가져옵니다
70
+ *
71
+ * @param sections - 섹션 이름 배열
72
+ * @param locale - 언어 코드 (선택, 미지정시 쿠키에서 자동 조회)
73
+ * @returns Section API 맵 ({ home: { t, data }, ... })
74
+ *
75
+ * @example
76
+ * ```tsx
77
+ * // Server Component
78
+ * import { getSections } from '@spfn/cms/server';
79
+ *
80
+ * export default async function Page()
81
+ * {
82
+ * // locale을 지정하지 않으면 쿠키에서 자동으로 가져옴
83
+ * const sections = await getSections(['home', 'why-futureplay']);
84
+ *
85
+ * // 또는 명시적으로 locale 지정
86
+ * const sectionsEn = await getSections(['home', 'why-futureplay'], 'en');
87
+ *
88
+ * return (
89
+ * <div>
90
+ * <h1>{sections.home.t('hero.title')}</h1>
91
+ * <p>{sections['why-futureplay'].t('intro.text')}</p>
92
+ * </div>
93
+ * );
94
+ * }
95
+ * ```
96
+ */
97
+ export declare const getSections: (sections: string[], locale?: string) => Promise<Record<string, SectionAPI>>;
98
+ export {};
99
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAiBrB;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEF;;GAEG;AACH,KAAK,yBAAyB,GAAG,CAC7B,GAAG,EAAE,MAAM,EACX,YAAY,CAAC,EAAE,GAAG,EAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KACxC,GAAG,CAAC;AAET;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACrB;;;;;;;OAOG;IACH,CAAC,EAAE,yBAAyB,CAAC;IAE7B;;OAEG;IACH,IAAI,EAAE,WAAW,CAAC;CACrB,CAAC;AAkBF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,UAAU,YACV,MAAM,WACN,MAAM,KAChB,OAAO,CAAC,UAAU,CAqGnB,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,WAAW,aACV,MAAM,EAAE,WACT,MAAM,KAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAoHnC,CAAC"}