@yartsun/chat-widget-types 1.0.2 → 1.0.5
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/README.md +214 -115
- package/dist/config.types.d.ts +111 -44
- package/dist/config.types.d.ts.map +1 -1
- package/dist/config.types.js +2 -67
- package/dist/config.types.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/migration/commands.d.ts +59 -0
- package/dist/migration/commands.d.ts.map +1 -0
- package/dist/migration/commands.js +286 -0
- package/dist/migration/commands.js.map +1 -0
- package/dist/migration/examples.d.ts +198 -0
- package/dist/migration/examples.d.ts.map +1 -0
- package/dist/migration/examples.js +439 -0
- package/dist/migration/examples.js.map +1 -0
- package/dist/migration/facade.d.ts +85 -0
- package/dist/migration/facade.d.ts.map +1 -0
- package/dist/migration/facade.js +168 -0
- package/dist/migration/facade.js.map +1 -0
- package/dist/migration/migrator.d.ts +49 -0
- package/dist/migration/migrator.d.ts.map +1 -0
- package/dist/migration/migrator.js +245 -0
- package/dist/migration/migrator.js.map +1 -0
- package/dist/migration/strategies.d.ts +85 -0
- package/dist/migration/strategies.d.ts.map +1 -0
- package/dist/migration/strategies.js +217 -0
- package/dist/migration/strategies.js.map +1 -0
- package/dist/migration/types.d.ts +196 -0
- package/dist/migration/types.d.ts.map +1 -0
- package/dist/migration/types.js +5 -0
- package/dist/migration/types.js.map +1 -0
- package/dist/utils.d.ts +1 -11
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +3 -127
- package/dist/utils.js.map +1 -1
- package/package.json +13 -4
- package/src/config.types.ts +132 -118
- package/src/index.ts +26 -0
- package/src/migration/commands.ts +314 -0
- package/src/migration/examples.ts +471 -0
- package/src/migration/facade.ts +196 -0
- package/src/migration/migrator.ts +361 -0
- package/src/migration/strategies.ts +249 -0
- package/src/migration/types.ts +182 -0
- package/src/utils.ts +3 -143
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Примеры использования системы миграции конфигураций
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
quickMigrateV1toV2,
|
|
7
|
+
MigrationFacade,
|
|
8
|
+
MigrationPresets,
|
|
9
|
+
ConfigHelpers
|
|
10
|
+
} from './facade'
|
|
11
|
+
import { ConfigV1, ConfigV2 } from './types'
|
|
12
|
+
|
|
13
|
+
/** Пример простой миграции V1 -> V2 */
|
|
14
|
+
export async function exampleSimpleMigration() {
|
|
15
|
+
const configV1: ConfigV1 = {
|
|
16
|
+
settings: {
|
|
17
|
+
widgetTitle: "HyperShadow",
|
|
18
|
+
welcomeMessage: "🖖 Hi there — I'm your assistant for finding documents, tracking access, and making sense of your files. \n\nHow can I help?",
|
|
19
|
+
bgChat: "rgba(47, 47, 49, 0.90)",
|
|
20
|
+
gapMessageLine: 12,
|
|
21
|
+
paddingChat: 8,
|
|
22
|
+
fontFamily: "MacPaw Fixel",
|
|
23
|
+
borderRadius: "lg",
|
|
24
|
+
launchView: "closed",
|
|
25
|
+
letterSpacing: 0,
|
|
26
|
+
logo: "",
|
|
27
|
+
fontWeight: 400
|
|
28
|
+
},
|
|
29
|
+
sections: {
|
|
30
|
+
top: {
|
|
31
|
+
params: { size: "md" },
|
|
32
|
+
chipWidgetTitle: { color: "#BEB6E9", bgColor: "#5E4AC6" },
|
|
33
|
+
btnClose: { color: "#BBBBBD", bgColor: "#2F2F31" }
|
|
34
|
+
},
|
|
35
|
+
inside: {
|
|
36
|
+
params: { size: "md" },
|
|
37
|
+
messageUser: { color: "#F9F8F8", bgColor: "#F8F8F933" },
|
|
38
|
+
messageBot: { color: "#fff", bgColor: "#5E4AC6" },
|
|
39
|
+
welcomeMessage: { color: "#fff" }
|
|
40
|
+
},
|
|
41
|
+
bottom: {
|
|
42
|
+
params: { size: "sm" },
|
|
43
|
+
inputSend: { color: "#EEECEC", bgColor: "#1E1E1E" },
|
|
44
|
+
btnSend: { color: "#1E1E1E", bgColor: "rgba(255, 255, 255, 0.50)", type: "both" },
|
|
45
|
+
activeBtn: { color: "#fff", bgColor: "#F8F8F933" }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log('🔄 Миграция V1 -> V2...')
|
|
51
|
+
|
|
52
|
+
// Быстрая миграция
|
|
53
|
+
const migratedConfig = await quickMigrateV1toV2(configV1)
|
|
54
|
+
|
|
55
|
+
if (migratedConfig) {
|
|
56
|
+
console.log('✅ Миграция успешна!')
|
|
57
|
+
console.log('📋 Добавленные поля V2:')
|
|
58
|
+
console.log('- settings.loader:', migratedConfig.settings.loader)
|
|
59
|
+
console.log('- sections.top.params.buttonStyle:', migratedConfig.sections.top.params.buttonStyle)
|
|
60
|
+
console.log('- sections.top.params.buttonType:', migratedConfig.sections.top.params.buttonType)
|
|
61
|
+
console.log('- sections.top.params.chipStyle:', migratedConfig.sections.top.params.chipStyle)
|
|
62
|
+
console.log('- sections.bottom.warningAlert:', migratedConfig.sections.bottom.warningAlert)
|
|
63
|
+
console.log('- texts.disclaimer:', migratedConfig.texts.disclaimer)
|
|
64
|
+
} else {
|
|
65
|
+
console.log('❌ Ошибка миграции')
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return migratedConfig
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Пример детальной миграции с отчетами */
|
|
72
|
+
export async function exampleDetailedMigration() {
|
|
73
|
+
const facade = new MigrationFacade(true) // включаем подробные логи
|
|
74
|
+
|
|
75
|
+
const configV1: ConfigV1 = {
|
|
76
|
+
settings: {
|
|
77
|
+
widgetTitle: "Test Widget",
|
|
78
|
+
welcomeMessage: "Welcome!",
|
|
79
|
+
bgChat: "#000000",
|
|
80
|
+
gapMessageLine: 10,
|
|
81
|
+
paddingChat: 5,
|
|
82
|
+
fontFamily: "Arial",
|
|
83
|
+
borderRadius: "md",
|
|
84
|
+
launchView: "compact",
|
|
85
|
+
letterSpacing: 1,
|
|
86
|
+
logo: "logo.png",
|
|
87
|
+
fontWeight: 300
|
|
88
|
+
},
|
|
89
|
+
sections: {
|
|
90
|
+
top: {
|
|
91
|
+
params: { size: "lg" },
|
|
92
|
+
chipWidgetTitle: { color: "#111", bgColor: "#222" },
|
|
93
|
+
btnClose: { color: "#333", bgColor: "#444" }
|
|
94
|
+
},
|
|
95
|
+
inside: {
|
|
96
|
+
params: { size: "sm" },
|
|
97
|
+
messageUser: { color: "#555", bgColor: "#666" },
|
|
98
|
+
messageBot: { color: "#777", bgColor: "#888" },
|
|
99
|
+
welcomeMessage: { color: "#999" }
|
|
100
|
+
},
|
|
101
|
+
bottom: {
|
|
102
|
+
params: { size: "md" },
|
|
103
|
+
inputSend: { color: "#AAA", bgColor: "#BBB" },
|
|
104
|
+
btnSend: { color: "#CCC", bgColor: "#DDD", type: "icon" },
|
|
105
|
+
activeBtn: { color: "#EEE", bgColor: "#FFF" }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log('\n🔍 Предварительный просмотр миграции...')
|
|
111
|
+
|
|
112
|
+
// Предварительный просмотр
|
|
113
|
+
const preview = await facade.preview(configV1, '2.0', MigrationPresets.DEBUG)
|
|
114
|
+
console.log('📊 Отчет о планируемой миграции:')
|
|
115
|
+
console.log(`- Исходная версия: ${preview.fromVersion}`)
|
|
116
|
+
console.log(`- Целевая версия: ${preview.toVersion}`)
|
|
117
|
+
console.log(`- Стратегий будет применено: ${preview.appliedStrategies.length}`)
|
|
118
|
+
console.log(`- Ожидаемое время выполнения: ${preview.duration}ms`)
|
|
119
|
+
console.log(`- Описание: ${preview.summary}`)
|
|
120
|
+
|
|
121
|
+
console.log('\n🔄 Выполняем миграцию...')
|
|
122
|
+
|
|
123
|
+
// Полная миграция
|
|
124
|
+
const result = await facade.migrateV1toV2(configV1, MigrationPresets.DEBUG)
|
|
125
|
+
|
|
126
|
+
if (result.success) {
|
|
127
|
+
console.log('✅ Миграция завершена успешно!')
|
|
128
|
+
console.log(`📈 Применено стратегий: ${result.appliedStrategies.length}`)
|
|
129
|
+
console.log(`⚠️ Предупреждений: ${result.warnings.length}`)
|
|
130
|
+
|
|
131
|
+
if (result.warnings.length > 0) {
|
|
132
|
+
console.log('⚠️ Предупреждения:')
|
|
133
|
+
result.warnings.forEach(warning => console.log(` - ${warning}`))
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return result.data
|
|
137
|
+
} else {
|
|
138
|
+
console.log('❌ Ошибки при миграции:')
|
|
139
|
+
result.errors.forEach(error => console.log(` - ${error}`))
|
|
140
|
+
return null
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Пример пакетной миграции нескольких конфигураций */
|
|
145
|
+
export async function exampleBatchMigration() {
|
|
146
|
+
const configs = [
|
|
147
|
+
// Конфигурация 1 - V1
|
|
148
|
+
{
|
|
149
|
+
id: 'config1',
|
|
150
|
+
data: {
|
|
151
|
+
settings: {
|
|
152
|
+
widgetTitle: "Config 1",
|
|
153
|
+
welcomeMessage: "Hello from config 1",
|
|
154
|
+
bgChat: "#111",
|
|
155
|
+
gapMessageLine: 5,
|
|
156
|
+
paddingChat: 10,
|
|
157
|
+
fontFamily: "Roboto",
|
|
158
|
+
borderRadius: "sm",
|
|
159
|
+
launchView: "closed",
|
|
160
|
+
letterSpacing: 0,
|
|
161
|
+
logo: "",
|
|
162
|
+
fontWeight: 400
|
|
163
|
+
},
|
|
164
|
+
sections: {
|
|
165
|
+
top: {
|
|
166
|
+
params: { size: "md" },
|
|
167
|
+
chipWidgetTitle: { color: "#AAA", bgColor: "#BBB" },
|
|
168
|
+
btnClose: { color: "#CCC", bgColor: "#DDD" }
|
|
169
|
+
},
|
|
170
|
+
inside: {
|
|
171
|
+
params: { size: "md" },
|
|
172
|
+
messageUser: { color: "#EEE", bgColor: "#FFF" },
|
|
173
|
+
messageBot: { color: "#000", bgColor: "#111" },
|
|
174
|
+
welcomeMessage: { color: "#222" }
|
|
175
|
+
},
|
|
176
|
+
bottom: {
|
|
177
|
+
params: { size: "sm" },
|
|
178
|
+
inputSend: { color: "#333", bgColor: "#444" },
|
|
179
|
+
btnSend: { color: "#555", bgColor: "#666", type: "text" },
|
|
180
|
+
activeBtn: { color: "#777", bgColor: "#888" }
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
// Конфигурация 2 - уже V2
|
|
186
|
+
{
|
|
187
|
+
id: 'config2',
|
|
188
|
+
data: {
|
|
189
|
+
settings: {
|
|
190
|
+
widgetTitle: "Config 2",
|
|
191
|
+
welcomeMessage: "Hello from config 2",
|
|
192
|
+
bgChat: "#222",
|
|
193
|
+
gapMessageLine: 8,
|
|
194
|
+
paddingChat: 12,
|
|
195
|
+
fontFamily: "Inter",
|
|
196
|
+
borderRadius: "lg",
|
|
197
|
+
launchView: "compact",
|
|
198
|
+
letterSpacing: 1,
|
|
199
|
+
logo: "logo2.png",
|
|
200
|
+
fontWeight: 500,
|
|
201
|
+
loader: "circle-pulse",
|
|
202
|
+
buttonStyle: "outlined",
|
|
203
|
+
buttonType: "icon"
|
|
204
|
+
},
|
|
205
|
+
sections: {
|
|
206
|
+
top: {
|
|
207
|
+
params: { size: "lg", chipStyle: "outlined" },
|
|
208
|
+
chipWidgetTitle: { color: "#999", bgColor: "#AAA" },
|
|
209
|
+
btnClose: { color: "#BBB", bgColor: "#CCC" }
|
|
210
|
+
},
|
|
211
|
+
inside: {
|
|
212
|
+
params: { size: "lg" },
|
|
213
|
+
messageUser: { color: "#DDD", bgColor: "#EEE", bgType: "bubble" },
|
|
214
|
+
messageBot: { color: "#FFF", bgColor: "#000", bgType: "plain" },
|
|
215
|
+
welcomeMessage: { color: "#111" },
|
|
216
|
+
aprooveButton: { color: "#222", bgColor: "#333" },
|
|
217
|
+
rejectButton: { color: "#444", bgColor: "#555" }
|
|
218
|
+
},
|
|
219
|
+
bottom: {
|
|
220
|
+
params: { size: "md" },
|
|
221
|
+
inputSend: {
|
|
222
|
+
color: "#666",
|
|
223
|
+
bgColor: "#777",
|
|
224
|
+
borderStyle: { borderColor: "#888", borderWidth: 2 },
|
|
225
|
+
inputStyle: "stacked",
|
|
226
|
+
bgType: "bubble"
|
|
227
|
+
},
|
|
228
|
+
btnSend: { color: "#999", bgColor: "#AAA", type: "both" },
|
|
229
|
+
activeBtn: { color: "#BBB", bgColor: "#CCC" },
|
|
230
|
+
warningAlert: { color: "#DDD", bgColor: "#EEE" },
|
|
231
|
+
disclaimer: "Custom disclaimer"
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
]
|
|
237
|
+
|
|
238
|
+
console.log('\n🔄 Пакетная миграция нескольких конфигураций...')
|
|
239
|
+
|
|
240
|
+
const results = []
|
|
241
|
+
|
|
242
|
+
for (const config of configs) {
|
|
243
|
+
console.log(`\n📋 Обрабатываем ${config.id}...`)
|
|
244
|
+
|
|
245
|
+
// Определяем версию
|
|
246
|
+
const version = ConfigHelpers.getConfigVersion(config.data)
|
|
247
|
+
console.log(` Версия: ${version || 'неизвестна'}`)
|
|
248
|
+
|
|
249
|
+
if (version === '1.0') {
|
|
250
|
+
console.log(' 🔄 Миграция V1 -> V2...')
|
|
251
|
+
const migrated = await quickMigrateV1toV2(config.data as ConfigV1)
|
|
252
|
+
results.push({
|
|
253
|
+
id: config.id,
|
|
254
|
+
originalVersion: version,
|
|
255
|
+
migrated: !!migrated,
|
|
256
|
+
result: migrated
|
|
257
|
+
})
|
|
258
|
+
} else if (version === '2.0') {
|
|
259
|
+
console.log(' ✅ Уже V2, пропускаем')
|
|
260
|
+
results.push({
|
|
261
|
+
id: config.id,
|
|
262
|
+
originalVersion: version,
|
|
263
|
+
migrated: false,
|
|
264
|
+
result: config.data
|
|
265
|
+
})
|
|
266
|
+
} else {
|
|
267
|
+
console.log(' ❌ Неизвестная версия')
|
|
268
|
+
results.push({
|
|
269
|
+
id: config.id,
|
|
270
|
+
originalVersion: version,
|
|
271
|
+
migrated: false,
|
|
272
|
+
result: null
|
|
273
|
+
})
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
console.log('\n📊 Результаты пакетной миграции:')
|
|
278
|
+
results.forEach(result => {
|
|
279
|
+
console.log(`- ${result.id}: ${result.originalVersion} -> ${result.migrated ? 'V2 (мигрировано)' : 'без изменений'}`)
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
return results
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** Пример с обработкой ошибок */
|
|
286
|
+
export async function exampleErrorHandling() {
|
|
287
|
+
console.log('\n🧪 Тестирование обработки ошибок...')
|
|
288
|
+
|
|
289
|
+
// Некорректная конфигурация
|
|
290
|
+
const brokenConfig = {
|
|
291
|
+
settings: {
|
|
292
|
+
// Отсутствуют обязательные поля
|
|
293
|
+
fontFamily: "Arial"
|
|
294
|
+
},
|
|
295
|
+
// Отсутствует sections
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const facade = new MigrationFacade(true)
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
console.log('🔄 Попытка миграции некорректной конфигурации...')
|
|
302
|
+
const result = await facade.migrate(brokenConfig, '2.0', MigrationPresets.STRICT)
|
|
303
|
+
|
|
304
|
+
if (result.success) {
|
|
305
|
+
console.log('✅ Неожиданно успешно')
|
|
306
|
+
} else {
|
|
307
|
+
console.log('❌ Ожидаемые ошибки:')
|
|
308
|
+
result.errors.forEach(error => console.log(` - ${error}`))
|
|
309
|
+
}
|
|
310
|
+
} catch (error) {
|
|
311
|
+
console.log('💥 Критическая ошибка:', error)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Тестируем мягкий режим
|
|
315
|
+
console.log('\n🔄 Повторная попытка в мягком режиме...')
|
|
316
|
+
const softResult = await facade.migrate(brokenConfig, '2.0', MigrationPresets.SOFT)
|
|
317
|
+
|
|
318
|
+
if (softResult.success) {
|
|
319
|
+
console.log('✅ Успешно в мягком режиме')
|
|
320
|
+
} else {
|
|
321
|
+
console.log('❌ Ошибки даже в мягком режиме:')
|
|
322
|
+
softResult.errors.forEach(error => console.log(` - ${error}`))
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/** Демонстрация всех примеров */
|
|
327
|
+
export async function runAllExamples() {
|
|
328
|
+
console.log('🚀 Запуск всех примеров миграции...\n')
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
await exampleSimpleMigration()
|
|
332
|
+
await exampleDetailedMigration()
|
|
333
|
+
await exampleBatchMigration()
|
|
334
|
+
await exampleErrorHandling()
|
|
335
|
+
|
|
336
|
+
console.log('\n🎉 Все примеры выполнены!')
|
|
337
|
+
} catch (error) {
|
|
338
|
+
console.error('💥 Критическая ошибка в примерах:', error)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Экспортируем готовые конфигурации для тестирования
|
|
343
|
+
export const SAMPLE_CONFIGS = {
|
|
344
|
+
V1_BASIC: {
|
|
345
|
+
settings: {
|
|
346
|
+
widgetTitle: "Sample V1",
|
|
347
|
+
welcomeMessage: "Welcome to V1",
|
|
348
|
+
bgChat: "#000",
|
|
349
|
+
gapMessageLine: 10,
|
|
350
|
+
paddingChat: 8,
|
|
351
|
+
fontFamily: "Arial",
|
|
352
|
+
borderRadius: "md",
|
|
353
|
+
launchView: "closed",
|
|
354
|
+
letterSpacing: 0,
|
|
355
|
+
logo: "",
|
|
356
|
+
fontWeight: 400
|
|
357
|
+
},
|
|
358
|
+
sections: {
|
|
359
|
+
top: {
|
|
360
|
+
params: { size: "md" },
|
|
361
|
+
chipWidgetTitle: { color: "#FFF", bgColor: "#000" },
|
|
362
|
+
btnClose: { color: "#000", bgColor: "#FFF" }
|
|
363
|
+
},
|
|
364
|
+
inside: {
|
|
365
|
+
params: { size: "md" },
|
|
366
|
+
messageUser: { color: "#333", bgColor: "#EEE" },
|
|
367
|
+
messageBot: { color: "#FFF", bgColor: "#007AFF" },
|
|
368
|
+
welcomeMessage: { color: "#333" }
|
|
369
|
+
},
|
|
370
|
+
bottom: {
|
|
371
|
+
params: { size: "sm" },
|
|
372
|
+
inputSend: { color: "#333", bgColor: "#FFF" },
|
|
373
|
+
btnSend: { color: "#FFF", bgColor: "#007AFF", type: "both" },
|
|
374
|
+
activeBtn: { color: "#007AFF", bgColor: "#EEE" }
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
} as ConfigV1,
|
|
378
|
+
|
|
379
|
+
V2_COMPLETE: {
|
|
380
|
+
schema: {
|
|
381
|
+
version: "2.0",
|
|
382
|
+
required: ["settings", "texts", "sections"]
|
|
383
|
+
},
|
|
384
|
+
settings: {
|
|
385
|
+
bgChat: "#111",
|
|
386
|
+
gapMessageLine: 12,
|
|
387
|
+
fontFamily: "Inter",
|
|
388
|
+
borderRadius: "lg",
|
|
389
|
+
launchView: "compact",
|
|
390
|
+
letterSpacing: 1,
|
|
391
|
+
logo: "logo.svg",
|
|
392
|
+
fontWeight: 500,
|
|
393
|
+
loader: "dots-pulse"
|
|
394
|
+
},
|
|
395
|
+
texts: {
|
|
396
|
+
widgetTitle: "Sample V2",
|
|
397
|
+
welcomeMessage: "Welcome to V2",
|
|
398
|
+
launchIssueTitle: "Launch Issue",
|
|
399
|
+
launchIssueText: "Please restart",
|
|
400
|
+
issueText: "Something went wrong",
|
|
401
|
+
reconnectText: "Reconnecting...",
|
|
402
|
+
inputPlaceholder: "Type your message",
|
|
403
|
+
disableInputText: "Please wait",
|
|
404
|
+
disclaimer: "This is a sample V2 configuration"
|
|
405
|
+
},
|
|
406
|
+
sections: {
|
|
407
|
+
warnings: {
|
|
408
|
+
launchIssue: {
|
|
409
|
+
params: { warningStyle: "gradient", showIcon: true, icon: "⚠️" },
|
|
410
|
+
iconColor: "#FFF",
|
|
411
|
+
bgColor: "#FF3B30",
|
|
412
|
+
headlineColor: "#FFF",
|
|
413
|
+
color: "#FFF",
|
|
414
|
+
resetButton: { color: "#FFF", bgColor: "#FF3B30" }
|
|
415
|
+
},
|
|
416
|
+
connectionIssue: {
|
|
417
|
+
params: { warningStyle: "gradient", showIcon: true, icon: "📡" },
|
|
418
|
+
iconColor: "#FFF",
|
|
419
|
+
bgColor: "#FF9500",
|
|
420
|
+
color: "#FFF",
|
|
421
|
+
resetButton: { color: "#FFF", bgColor: "#FF9500" }
|
|
422
|
+
},
|
|
423
|
+
reconnectIssue: {
|
|
424
|
+
params: { warningStyle: "gradient", showIcon: true, icon: "🔄" },
|
|
425
|
+
iconColor: "#FFF",
|
|
426
|
+
bgColor: "#007AFF",
|
|
427
|
+
color: "#FFF"
|
|
428
|
+
},
|
|
429
|
+
disableInputIssue: {
|
|
430
|
+
iconColor: "#FFF",
|
|
431
|
+
bgColor: "#8E8E93",
|
|
432
|
+
color: "#FFF"
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
loader: {
|
|
436
|
+
completeStep: "#34C759",
|
|
437
|
+
activeStep: "#007AFF"
|
|
438
|
+
},
|
|
439
|
+
top: {
|
|
440
|
+
params: {
|
|
441
|
+
size: "lg",
|
|
442
|
+
chipStyle: "filled",
|
|
443
|
+
chipType: "both",
|
|
444
|
+
buttonStyle: "filled",
|
|
445
|
+
buttonType: "both"
|
|
446
|
+
},
|
|
447
|
+
chipWidgetTitle: { color: "#FFF", bgColor: "#007AFF" },
|
|
448
|
+
buttons: { color: "#666", bgColor: "#EEE" }
|
|
449
|
+
},
|
|
450
|
+
inside: {
|
|
451
|
+
params: { size: "md" },
|
|
452
|
+
messageUser: { color: "#333", bgColor: "#F0F0F0", bgType: "bubble" },
|
|
453
|
+
messageBot: { color: "#FFF", bgColor: "#007AFF", bgType: "plain" },
|
|
454
|
+
welcomeMessage: { color: "#333" }
|
|
455
|
+
},
|
|
456
|
+
bottom: {
|
|
457
|
+
params: { size: "md", disclaimerShow: true },
|
|
458
|
+
inputSend: {
|
|
459
|
+
color: "#333",
|
|
460
|
+
bgColor: "#FFF",
|
|
461
|
+
borderStyle: { borderColor: "#DDD", borderWidth: 1 },
|
|
462
|
+
inputStyle: "inside",
|
|
463
|
+
bgType: "plain"
|
|
464
|
+
},
|
|
465
|
+
btnSend: { color: "#FFF", bgColor: "#007AFF", type: "both" },
|
|
466
|
+
activeBtn: { color: "#007AFF", bgColor: "#E3F2FD" },
|
|
467
|
+
warningAlert: { color: "#FFF", bgColor: "#FF9500" }
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
} as ConfigV2
|
|
471
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Фасад для удобного использования системы миграции
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
ConfigVersion,
|
|
7
|
+
MigrationResult,
|
|
8
|
+
MigrationOptions,
|
|
9
|
+
MigrationReport,
|
|
10
|
+
ConfigV1,
|
|
11
|
+
ConfigV2
|
|
12
|
+
} from './types'
|
|
13
|
+
import { ConfigMigrator, DefaultMigrationLogger } from './migrator'
|
|
14
|
+
import { WidgetConfig } from '../config.types'
|
|
15
|
+
|
|
16
|
+
/** Простой API для миграции конфигураций */
|
|
17
|
+
export class MigrationFacade {
|
|
18
|
+
private migrator: ConfigMigrator
|
|
19
|
+
|
|
20
|
+
constructor(verbose: boolean = false) {
|
|
21
|
+
const logger = new DefaultMigrationLogger(verbose)
|
|
22
|
+
this.migrator = new ConfigMigrator(logger)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Мигрировать конфигурацию V1 в V2
|
|
27
|
+
*/
|
|
28
|
+
async migrateV1toV2(config: ConfigV1, options?: MigrationOptions): Promise<MigrationResult<ConfigV2>> {
|
|
29
|
+
return this.migrator.migrate<ConfigV2>(config, '2.0', options)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Мигрировать конфигурацию в последнюю версию
|
|
34
|
+
*/
|
|
35
|
+
async migrateToLatest(config: any, options?: MigrationOptions): Promise<MigrationResult<WidgetConfig>> {
|
|
36
|
+
return this.migrator.migrate<WidgetConfig>(config, '2.0', options) // пока V2 - последняя
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Автоматически определить версию и мигрировать в указанную
|
|
41
|
+
*/
|
|
42
|
+
async migrate(config: any, targetVersion: ConfigVersion, options?: MigrationOptions): Promise<MigrationResult> {
|
|
43
|
+
return this.migrator.migrate(config, targetVersion, options)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Предварительный просмотр миграции без её выполнения
|
|
48
|
+
*/
|
|
49
|
+
async preview(config: any, targetVersion: ConfigVersion, options?: MigrationOptions): Promise<MigrationReport> {
|
|
50
|
+
return this.migrator.dryRun(config, targetVersion, options)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Быстрая проверка - можно ли мигрировать конфигурацию
|
|
55
|
+
*/
|
|
56
|
+
async canMigrate(config: any, targetVersion: ConfigVersion): Promise<boolean> {
|
|
57
|
+
try {
|
|
58
|
+
const report = await this.preview(config, targetVersion)
|
|
59
|
+
return report.success
|
|
60
|
+
} catch {
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Глобальный экземпляр фасада */
|
|
67
|
+
export const migrationFacade = new MigrationFacade()
|
|
68
|
+
|
|
69
|
+
/** Утилитарные функции для быстрого использования */
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Быстрая миграция V1 -> V2
|
|
73
|
+
*/
|
|
74
|
+
export async function quickMigrateV1toV2(config: ConfigV1, options?: MigrationOptions): Promise<ConfigV2 | null> {
|
|
75
|
+
try {
|
|
76
|
+
const result = await migrationFacade.migrateV1toV2(config, options)
|
|
77
|
+
return result.success ? result.data! : null
|
|
78
|
+
} catch {
|
|
79
|
+
return null
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Быстрая миграция в последнюю версию
|
|
85
|
+
*/
|
|
86
|
+
export async function quickMigrateToLatest(config: any, options?: MigrationOptions): Promise<WidgetConfig | null> {
|
|
87
|
+
try {
|
|
88
|
+
const result = await migrationFacade.migrateToLatest(config, options)
|
|
89
|
+
return result.success ? result.data! : null
|
|
90
|
+
} catch {
|
|
91
|
+
return null
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Синхронная функция миграции V1 -> V2 (без async/await)
|
|
97
|
+
* Использует только стратегии без побочных эффектов
|
|
98
|
+
*/
|
|
99
|
+
export function syncMigrateV1toV2(_config: ConfigV1): ConfigV2 | null {
|
|
100
|
+
// Синхронная миграция пока не поддерживается, используйте async версию
|
|
101
|
+
console.warn('syncMigrateV1toV2 не поддерживается, используйте quickMigrateV1toV2')
|
|
102
|
+
return null
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Набор предустановленных опций миграции */
|
|
106
|
+
export const MigrationPresets = {
|
|
107
|
+
/** Строгий режим - останавливается на любой ошибке */
|
|
108
|
+
STRICT: {
|
|
109
|
+
strict: true,
|
|
110
|
+
preserveUnknown: false,
|
|
111
|
+
verbose: false
|
|
112
|
+
} as MigrationOptions,
|
|
113
|
+
|
|
114
|
+
/** Мягкий режим - продолжает при ошибках, сохраняет неизвестные поля */
|
|
115
|
+
SOFT: {
|
|
116
|
+
strict: false,
|
|
117
|
+
preserveUnknown: true,
|
|
118
|
+
verbose: false
|
|
119
|
+
} as MigrationOptions,
|
|
120
|
+
|
|
121
|
+
/** Режим отладки - подробные логи */
|
|
122
|
+
DEBUG: {
|
|
123
|
+
strict: false,
|
|
124
|
+
preserveUnknown: true,
|
|
125
|
+
verbose: true
|
|
126
|
+
} as MigrationOptions,
|
|
127
|
+
|
|
128
|
+
/** Производственный режим - без логов, строгий */
|
|
129
|
+
PRODUCTION: {
|
|
130
|
+
strict: true,
|
|
131
|
+
preserveUnknown: false,
|
|
132
|
+
verbose: false
|
|
133
|
+
} as MigrationOptions
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Хелперы для работы с конфигурациями */
|
|
137
|
+
export class ConfigHelpers {
|
|
138
|
+
/**
|
|
139
|
+
* Проверить является ли конфигурация V1
|
|
140
|
+
*/
|
|
141
|
+
static isV1Config(config: any): config is ConfigV1 {
|
|
142
|
+
return config &&
|
|
143
|
+
config.settings &&
|
|
144
|
+
config.sections &&
|
|
145
|
+
config.settings.loader === undefined && // V1 не имеет loader
|
|
146
|
+
config.sections.inside?.aprooveButton === undefined // V1 не имеет approve кнопок
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Проверить является ли конфигурация V2
|
|
151
|
+
*/
|
|
152
|
+
static isV2Config(config: any): config is ConfigV2 {
|
|
153
|
+
return config &&
|
|
154
|
+
config.settings &&
|
|
155
|
+
config.sections &&
|
|
156
|
+
config.settings.loader !== undefined && // V2 имеет loader
|
|
157
|
+
config.sections.inside?.aprooveButton !== undefined // V2 имеет approve кнопки
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Безопасно получить версию конфигурации
|
|
162
|
+
*/
|
|
163
|
+
static getConfigVersion(config: any): ConfigVersion | null {
|
|
164
|
+
if (ConfigHelpers.isV2Config(config)) return '2.0'
|
|
165
|
+
if (ConfigHelpers.isV1Config(config)) return '1.0'
|
|
166
|
+
return null
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Создать резервную копию конфигурации
|
|
171
|
+
*/
|
|
172
|
+
static backup(config: any): { config: any; timestamp: number; version: ConfigVersion | null } {
|
|
173
|
+
return {
|
|
174
|
+
config: JSON.parse(JSON.stringify(config)),
|
|
175
|
+
timestamp: Date.now(),
|
|
176
|
+
version: ConfigHelpers.getConfigVersion(config)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Валидировать основную структуру конфигурации
|
|
182
|
+
*/
|
|
183
|
+
static isValidStructure(config: any): boolean {
|
|
184
|
+
return !!(
|
|
185
|
+
config &&
|
|
186
|
+
typeof config === 'object' &&
|
|
187
|
+
config.settings &&
|
|
188
|
+
typeof config.settings === 'object' &&
|
|
189
|
+
config.sections &&
|
|
190
|
+
typeof config.sections === 'object' &&
|
|
191
|
+
config.sections.top &&
|
|
192
|
+
config.sections.inside &&
|
|
193
|
+
config.sections.bottom
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
}
|