@spfn/cms 0.1.0-alpha.0 → 0.1.0-alpha.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spfn/cms",
3
- "version": "0.1.0-alpha.0",
3
+ "version": "0.1.0-alpha.1",
4
4
  "description": "SPFN CMS - Content Management System with type-safe labels and Next.js integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -45,6 +45,14 @@
45
45
  "./codegen/generators": {
46
46
  "types": "./dist/generators/index.d.ts",
47
47
  "import": "./dist/generators/index.js"
48
+ },
49
+ "./repositories": {
50
+ "types": "./dist/repositories/index.d.ts",
51
+ "import": "./dist/repositories/index.js"
52
+ },
53
+ "./repositories/*": {
54
+ "types": "./dist/repositories/*.d.ts",
55
+ "import": "./dist/repositories/*.js"
48
56
  }
49
57
  },
50
58
  "files": [
@@ -61,6 +69,11 @@
61
69
  ],
62
70
  "author": "SPFN Team",
63
71
  "license": "MIT",
72
+ "repository": {
73
+ "type": "git",
74
+ "url": "https://github.com/spfn/spfn.git",
75
+ "directory": "packages/cms"
76
+ },
64
77
  "spfn": {
65
78
  "schemas": [
66
79
  "./dist/entities/*.js"
@@ -1,33 +0,0 @@
1
- /**
2
- * CMS Label Sync Contract
3
- *
4
- * 라벨 정의 파일을 DB와 동기화
5
- */
6
- /**
7
- * POST /cms/sync - 라벨 동기화 실행
8
- */
9
- export declare const syncLabelsContract: {
10
- readonly method: "POST";
11
- readonly path: "/";
12
- readonly body: import("@sinclair/typebox").TObject<{
13
- dryRun: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
14
- updateExisting: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
15
- removeUnused: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
16
- verbose: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
17
- }>;
18
- readonly response: import("@sinclair/typebox").TObject<{
19
- success: import("@sinclair/typebox").TBoolean;
20
- results: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
21
- section: import("@sinclair/typebox").TString;
22
- created: import("@sinclair/typebox").TNumber;
23
- updated: import("@sinclair/typebox").TNumber;
24
- deleted: import("@sinclair/typebox").TNumber;
25
- unchanged: import("@sinclair/typebox").TNumber;
26
- errors: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
27
- key: import("@sinclair/typebox").TString;
28
- error: import("@sinclair/typebox").TString;
29
- }>>;
30
- }>>;
31
- }>;
32
- };
33
- //# sourceMappingURL=contract.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/routes/sync/contract.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;CAuBG,CAAC"}
@@ -1,34 +0,0 @@
1
- import { Type } from '@sinclair/typebox';
2
- /**
3
- * CMS Label Sync Contract
4
- *
5
- * 라벨 정의 파일을 DB와 동기화
6
- */
7
- /**
8
- * POST /cms/sync - 라벨 동기화 실행
9
- */
10
- export const syncLabelsContract = {
11
- method: 'POST',
12
- path: '/',
13
- body: Type.Object({
14
- dryRun: Type.Optional(Type.Boolean({ description: 'Dry run - 변경사항만 확인', default: false })),
15
- updateExisting: Type.Optional(Type.Boolean({ description: '기존 라벨 defaultValue 업데이트', default: false })),
16
- removeUnused: Type.Optional(Type.Boolean({ description: '사용되지 않는 라벨 삭제', default: false })),
17
- verbose: Type.Optional(Type.Boolean({ description: '상세 로그 출력', default: false })),
18
- }),
19
- response: Type.Object({
20
- success: Type.Boolean({ description: '성공 여부' }),
21
- results: Type.Array(Type.Object({
22
- section: Type.String({ description: '섹션 이름' }),
23
- created: Type.Number({ description: '생성된 라벨 수' }),
24
- updated: Type.Number({ description: '업데이트된 라벨 수' }),
25
- deleted: Type.Number({ description: '삭제된 라벨 수' }),
26
- unchanged: Type.Number({ description: '변경되지 않은 라벨 수' }),
27
- errors: Type.Array(Type.Object({
28
- key: Type.String({ description: '에러가 발생한 라벨 키' }),
29
- error: Type.String({ description: '에러 메시지' }),
30
- })),
31
- })),
32
- }),
33
- };
34
- //# sourceMappingURL=contract.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/routes/sync/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAGzC;;;;GAIG;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAC9B,MAAM,EAAE,MAAe;IACvB,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;QACd,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,oBAAoB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1F,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,yBAAyB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACvG,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3F,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;KACpF,CAAC;IACF,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC;QAClB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;QAC/C,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;YAC5B,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;YAC9C,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;YACjD,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;YACnD,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;YACjD,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC;YACvD,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;gBAC3B,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC;gBACjD,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;aAChD,CAAC,CAAC;SACN,CAAC,CAAC;KACN,CAAC;CAC4B,CAAC"}
@@ -1,13 +0,0 @@
1
- /**
2
- * CMS Label Sync Route
3
- *
4
- * POST /cms/sync - 라벨 정의를 DB와 동기화
5
- *
6
- * 사용 시나리오:
7
- * 1. 로컬 개발: npm run cms:sync (CLI가 이 API 호출)
8
- * 2. CI/CD: 배포 후 curl -X POST https://api.com/cms/sync
9
- * 3. Admin UI: Sync 버튼 클릭
10
- */
11
- declare const app: import("@spfn/core/route").SPFNApp;
12
- export default app;
13
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/routes/sync/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAcH,QAAA,MAAM,GAAG,oCAAc,CAAC;AA8SxB,eAAe,GAAG,CAAC"}
@@ -1,241 +0,0 @@
1
- /**
2
- * CMS Label Sync Route
3
- *
4
- * POST /cms/sync - 라벨 정의를 DB와 동기화
5
- *
6
- * 사용 시나리오:
7
- * 1. 로컬 개발: npm run cms:sync (CLI가 이 API 호출)
8
- * 2. CI/CD: 배포 후 curl -X POST https://api.com/cms/sync
9
- * 3. Admin UI: Sync 버튼 클릭
10
- */
11
- import { createApp } from '@spfn/core/route';
12
- import { Transactional } from '@spfn/core/db';
13
- import { cmsLabelsRepository, cmsPublishedCacheRepository } from '../../repositories';
14
- import { extractLabels } from '../../labels';
15
- import { syncLabelsContract } from './contract.js';
16
- // TODO: layoutLabels should be imported from the project using this library
17
- // For now, this is a placeholder that needs to be configured by the consuming project
18
- // When integrating into futureplay, import from: import { layoutLabels } from '@/lib/cms/labels/layout.labels';
19
- const layoutLabels = { section: 'layout', labels: {} };
20
- const app = createApp();
21
- /**
22
- * POST /cms/sync
23
- * 라벨 동기화 실행
24
- */
25
- app.bind(syncLabelsContract, [Transactional()], async (c) => {
26
- const body = await c.data();
27
- // 동기화할 섹션 정의
28
- const sections = [
29
- layoutLabels,
30
- // 추후 다른 섹션 추가
31
- // homeLabels,
32
- // whyFutureplayLabels,
33
- ];
34
- const options = {
35
- dryRun: body.dryRun ?? false,
36
- updateExisting: body.updateExisting ?? false,
37
- removeUnused: body.removeUnused ?? false,
38
- verbose: body.verbose ?? false,
39
- };
40
- // Sync 실행
41
- const results = [];
42
- for (const definition of sections) {
43
- const result = await syncSection(definition, options);
44
- results.push(result);
45
- }
46
- // 에러 체크
47
- const hasErrors = results.some((r) => r.errors.length > 0);
48
- return c.json({
49
- success: !hasErrors,
50
- results,
51
- });
52
- });
53
- /**
54
- * 섹션 라벨 동기화
55
- */
56
- async function syncSection(definition, options) {
57
- const { dryRun = false, updateExisting = false, removeUnused = false, verbose = false, } = options;
58
- const { section } = definition;
59
- const result = {
60
- section,
61
- created: 0,
62
- updated: 0,
63
- deleted: 0,
64
- unchanged: 0,
65
- errors: [],
66
- };
67
- try {
68
- // 정의 파일에서 라벨 추출
69
- const definedLabels = extractLabels(definition);
70
- const definedKeys = new Set(definedLabels.map((l) => l.key));
71
- // DB에서 기존 라벨 조회
72
- const existingLabels = await cmsLabelsRepository.findBySection(section);
73
- const existingMap = new Map(existingLabels.map((l) => [l.key, l]));
74
- if (verbose) {
75
- console.log(`\n[${section}] Found ${definedLabels.length} labels in definition`);
76
- console.log(`[${section}] Found ${existingLabels.length} labels in DB`);
77
- }
78
- // 생성 및 업데이트
79
- for (const label of definedLabels) {
80
- const existing = existingMap.get(label.key);
81
- if (!existing) {
82
- // 새로운 라벨 생성
83
- if (verbose) {
84
- console.log(` [CREATE] ${label.key}`);
85
- }
86
- if (!dryRun) {
87
- try {
88
- // Handle multilingual defaultValue
89
- const defaultValue = typeof label.defaultValue === 'object'
90
- ? JSON.stringify(label.defaultValue)
91
- : label.defaultValue;
92
- await cmsLabelsRepository.create({
93
- section,
94
- key: label.key,
95
- type: 'text', // Default type for synced labels
96
- defaultValue,
97
- description: label.description,
98
- });
99
- }
100
- catch (error) {
101
- result.errors.push({
102
- key: label.key,
103
- error: error instanceof Error ? error.message : String(error),
104
- });
105
- continue;
106
- }
107
- }
108
- result.created++;
109
- }
110
- else if (updateExisting) {
111
- // Normalize both values for comparison
112
- const newDefaultValue = typeof label.defaultValue === 'object'
113
- ? JSON.stringify(label.defaultValue)
114
- : label.defaultValue;
115
- const hasChanged = existing.defaultValue !== newDefaultValue;
116
- if (hasChanged) {
117
- // 기존 라벨 업데이트
118
- if (verbose) {
119
- console.log(` [UPDATE] ${label.key}`);
120
- console.log(` Old: "${existing.defaultValue}"`);
121
- console.log(` New: "${newDefaultValue}"`);
122
- }
123
- if (!dryRun) {
124
- try {
125
- await cmsLabelsRepository.updateById(existing.id, {
126
- defaultValue: newDefaultValue,
127
- description: label.description,
128
- });
129
- }
130
- catch (error) {
131
- result.errors.push({
132
- key: label.key,
133
- error: error instanceof Error ? error.message : String(error),
134
- });
135
- continue;
136
- }
137
- }
138
- result.updated++;
139
- }
140
- else {
141
- result.unchanged++;
142
- }
143
- }
144
- else {
145
- result.unchanged++;
146
- }
147
- }
148
- // 사용되지 않는 라벨 삭제
149
- if (removeUnused) {
150
- for (const existing of existingLabels) {
151
- if (!definedKeys.has(existing.key)) {
152
- if (verbose) {
153
- console.log(` [DELETE] ${existing.key}`);
154
- }
155
- if (!dryRun) {
156
- try {
157
- await cmsLabelsRepository.deleteById(existing.id);
158
- }
159
- catch (error) {
160
- result.errors.push({
161
- key: existing.key,
162
- error: error instanceof Error ? error.message : String(error),
163
- });
164
- continue;
165
- }
166
- }
167
- result.deleted++;
168
- }
169
- }
170
- }
171
- // Published cache 업데이트 (변경사항이 있을 경우)
172
- if (!dryRun && (result.created > 0 || result.updated > 0 || result.deleted > 0)) {
173
- if (verbose) {
174
- console.log(` [CACHE] Updating published cache for section: ${section}`);
175
- }
176
- await updatePublishedCache(section);
177
- }
178
- }
179
- catch (error) {
180
- result.errors.push({
181
- key: '__section__',
182
- error: error instanceof Error ? error.message : String(error),
183
- });
184
- }
185
- return result;
186
- }
187
- /**
188
- * Published Cache 업데이트
189
- */
190
- async function updatePublishedCache(section) {
191
- // 섹션의 모든 라벨 조회
192
- const labels = await cmsLabelsRepository.findBySection(section);
193
- // 지원하는 로케일 추출
194
- const localesSet = new Set();
195
- const labelsByLocale = {};
196
- labels.forEach((label) => {
197
- try {
198
- // Try to parse as JSON (multilingual)
199
- const parsed = JSON.parse(label.defaultValue || '{}');
200
- if (typeof parsed === 'object' && !Array.isArray(parsed)) {
201
- // Multilingual: { ko: '...', en: '...' }
202
- Object.keys(parsed).forEach((locale) => localesSet.add(locale));
203
- Object.entries(parsed).forEach(([locale, value]) => {
204
- if (!labelsByLocale[locale]) {
205
- labelsByLocale[locale] = {};
206
- }
207
- labelsByLocale[locale][label.key] = value;
208
- });
209
- }
210
- else {
211
- // Single value stored as JSON
212
- if (!labelsByLocale.ko) {
213
- labelsByLocale.ko = {};
214
- }
215
- labelsByLocale.ko[label.key] = label.defaultValue;
216
- localesSet.add('ko');
217
- }
218
- }
219
- catch {
220
- // Not JSON, plain string - default to 'ko'
221
- if (!labelsByLocale.ko) {
222
- labelsByLocale.ko = {};
223
- }
224
- labelsByLocale.ko[label.key] = label.defaultValue;
225
- localesSet.add('ko');
226
- }
227
- });
228
- // 각 로케일별로 캐시 업데이트
229
- const timestamp = new Date();
230
- for (const locale of localesSet) {
231
- await cmsPublishedCacheRepository.upsert({
232
- section,
233
- locale,
234
- content: labelsByLocale[locale] || {},
235
- publishedAt: timestamp,
236
- publishedBy: 'system',
237
- });
238
- }
239
- }
240
- export default app;
241
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/routes/sync/index.ts"],"names":[],"mappings":"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"}
package/dist/sync.d.ts DELETED
@@ -1,11 +0,0 @@
1
- /**
2
- * CMS Sync Utilities
3
- *
4
- * 라벨 동기화를 위한 헬퍼 함수들
5
- */
6
- import type { SectionDefinition, SyncOptions, SyncResult } from './types';
7
- /**
8
- * 섹션 라벨 동기화
9
- */
10
- export declare function syncSection(definition: SectionDefinition, options?: SyncOptions): Promise<SyncResult>;
11
- //# sourceMappingURL=sync.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1E;;GAEG;AACH,wBAAsB,WAAW,CAC7B,UAAU,EAAE,iBAAiB,EAC7B,OAAO,GAAE,WAAgB,GAC1B,OAAO,CAAC,UAAU,CAAC,CAoKrB"}
package/dist/sync.js DELETED
@@ -1,179 +0,0 @@
1
- /**
2
- * CMS Sync Utilities
3
- *
4
- * 라벨 동기화를 위한 헬퍼 함수들
5
- */
6
- import { cmsLabelsRepository, cmsPublishedCacheRepository } from './repositories';
7
- import { extractLabels } from './labels';
8
- /**
9
- * 섹션 라벨 동기화
10
- */
11
- export async function syncSection(definition, options = {}) {
12
- const { dryRun = false, updateExisting = false, removeUnused = false, verbose = false, } = options;
13
- const { section } = definition;
14
- const result = {
15
- section,
16
- created: 0,
17
- updated: 0,
18
- deleted: 0,
19
- unchanged: 0,
20
- errors: [],
21
- };
22
- try {
23
- const definedLabels = extractLabels(definition);
24
- const definedKeys = new Set(definedLabels.map((l) => l.key));
25
- const existingLabels = await cmsLabelsRepository.findBySection(section);
26
- const existingMap = new Map(existingLabels.map((l) => [l.key, l]));
27
- if (verbose) {
28
- console.log(`\n[${section}] Found ${definedLabels.length} labels in definition`);
29
- console.log(`[${section}] Found ${existingLabels.length} labels in DB`);
30
- }
31
- // 생성 및 업데이트
32
- for (const label of definedLabels) {
33
- const existing = existingMap.get(label.key);
34
- if (!existing) {
35
- if (verbose)
36
- console.log(` [CREATE] ${label.key}`);
37
- if (!dryRun) {
38
- try {
39
- const defaultValue = typeof label.defaultValue === 'object'
40
- ? JSON.stringify(label.defaultValue)
41
- : label.defaultValue;
42
- await cmsLabelsRepository.create({
43
- section,
44
- key: label.key,
45
- type: 'text',
46
- defaultValue,
47
- description: label.description,
48
- });
49
- }
50
- catch (error) {
51
- result.errors.push({
52
- key: label.key,
53
- error: error instanceof Error ? error.message : String(error),
54
- });
55
- continue;
56
- }
57
- }
58
- result.created++;
59
- }
60
- else if (updateExisting) {
61
- const newDefaultValue = typeof label.defaultValue === 'object'
62
- ? JSON.stringify(label.defaultValue)
63
- : label.defaultValue;
64
- const hasChanged = existing.defaultValue !== newDefaultValue;
65
- if (hasChanged) {
66
- if (verbose) {
67
- console.log(` [UPDATE] ${label.key}`);
68
- console.log(` Old: "${existing.defaultValue}"`);
69
- console.log(` New: "${newDefaultValue}"`);
70
- }
71
- if (!dryRun) {
72
- try {
73
- await cmsLabelsRepository.updateById(existing.id, {
74
- defaultValue: newDefaultValue,
75
- description: label.description,
76
- });
77
- }
78
- catch (error) {
79
- result.errors.push({
80
- key: label.key,
81
- error: error instanceof Error ? error.message : String(error),
82
- });
83
- continue;
84
- }
85
- }
86
- result.updated++;
87
- }
88
- else {
89
- result.unchanged++;
90
- }
91
- }
92
- else {
93
- result.unchanged++;
94
- }
95
- }
96
- // 사용되지 않는 라벨 삭제
97
- if (removeUnused) {
98
- for (const existing of existingLabels) {
99
- if (!definedKeys.has(existing.key)) {
100
- if (verbose)
101
- console.log(` [DELETE] ${existing.key}`);
102
- if (!dryRun) {
103
- try {
104
- await cmsLabelsRepository.deleteById(existing.id);
105
- }
106
- catch (error) {
107
- result.errors.push({
108
- key: existing.key,
109
- error: error instanceof Error ? error.message : String(error),
110
- });
111
- continue;
112
- }
113
- }
114
- result.deleted++;
115
- }
116
- }
117
- }
118
- // Published cache 업데이트
119
- if (!dryRun && (result.created > 0 || result.updated > 0 || result.deleted > 0)) {
120
- if (verbose)
121
- console.log(` [CACHE] Updating published cache for section: ${section}`);
122
- await updatePublishedCache(section);
123
- }
124
- }
125
- catch (error) {
126
- result.errors.push({
127
- key: '__section__',
128
- error: error instanceof Error ? error.message : String(error),
129
- });
130
- }
131
- return result;
132
- }
133
- /**
134
- * Published Cache 업데이트
135
- */
136
- async function updatePublishedCache(section) {
137
- const labels = await cmsLabelsRepository.findBySection(section);
138
- const localesSet = new Set();
139
- const labelsByLocale = {};
140
- labels.forEach((label) => {
141
- try {
142
- const parsed = JSON.parse(label.defaultValue || '{}');
143
- if (typeof parsed === 'object' && !Array.isArray(parsed)) {
144
- // Multilingual
145
- Object.keys(parsed).forEach((locale) => localesSet.add(locale));
146
- Object.entries(parsed).forEach(([locale, value]) => {
147
- if (!labelsByLocale[locale])
148
- labelsByLocale[locale] = {};
149
- labelsByLocale[locale][label.key] = value;
150
- });
151
- }
152
- else {
153
- // Single value
154
- if (!labelsByLocale.ko)
155
- labelsByLocale.ko = {};
156
- labelsByLocale.ko[label.key] = label.defaultValue;
157
- localesSet.add('ko');
158
- }
159
- }
160
- catch {
161
- // Plain string
162
- if (!labelsByLocale.ko)
163
- labelsByLocale.ko = {};
164
- labelsByLocale.ko[label.key] = label.defaultValue;
165
- localesSet.add('ko');
166
- }
167
- });
168
- const timestamp = new Date();
169
- for (const locale of localesSet) {
170
- await cmsPublishedCacheRepository.upsert({
171
- section,
172
- locale,
173
- content: labelsByLocale[locale] || {},
174
- publishedAt: timestamp,
175
- publishedBy: 'system',
176
- });
177
- }
178
- }
179
- //# sourceMappingURL=sync.js.map
package/dist/sync.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"sync.js","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"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"}