@yartsun/chat-widget-types 1.0.3 → 1.0.6

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 (52) hide show
  1. package/README.md +214 -115
  2. package/dist/config.types.d.ts +111 -46
  3. package/dist/config.types.d.ts.map +1 -1
  4. package/dist/config.types.js +2 -66
  5. package/dist/config.types.js.map +1 -1
  6. package/dist/default-config.d.ts +3 -0
  7. package/dist/default-config.d.ts.map +1 -0
  8. package/dist/default-config.js +3 -0
  9. package/dist/default-config.js.map +1 -0
  10. package/dist/index.d.ts +6 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +5 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/migration/commands.d.ts +59 -0
  15. package/dist/migration/commands.d.ts.map +1 -0
  16. package/dist/migration/commands.js +286 -0
  17. package/dist/migration/commands.js.map +1 -0
  18. package/dist/migration/examples.d.ts +198 -0
  19. package/dist/migration/examples.d.ts.map +1 -0
  20. package/dist/migration/examples.js +439 -0
  21. package/dist/migration/examples.js.map +1 -0
  22. package/dist/migration/facade.d.ts +85 -0
  23. package/dist/migration/facade.d.ts.map +1 -0
  24. package/dist/migration/facade.js +168 -0
  25. package/dist/migration/facade.js.map +1 -0
  26. package/dist/migration/migrator.d.ts +49 -0
  27. package/dist/migration/migrator.d.ts.map +1 -0
  28. package/dist/migration/migrator.js +245 -0
  29. package/dist/migration/migrator.js.map +1 -0
  30. package/dist/migration/strategies.d.ts +85 -0
  31. package/dist/migration/strategies.d.ts.map +1 -0
  32. package/dist/migration/strategies.js +217 -0
  33. package/dist/migration/strategies.js.map +1 -0
  34. package/dist/migration/types.d.ts +196 -0
  35. package/dist/migration/types.d.ts.map +1 -0
  36. package/dist/migration/types.js +5 -0
  37. package/dist/migration/types.js.map +1 -0
  38. package/dist/utils.d.ts +1 -11
  39. package/dist/utils.d.ts.map +1 -1
  40. package/dist/utils.js +3 -129
  41. package/dist/utils.js.map +1 -1
  42. package/package.json +13 -4
  43. package/src/config.types.ts +131 -121
  44. package/src/default-config.ts +6 -0
  45. package/src/index.ts +26 -0
  46. package/src/migration/commands.ts +314 -0
  47. package/src/migration/examples.ts +471 -0
  48. package/src/migration/facade.ts +196 -0
  49. package/src/migration/migrator.ts +361 -0
  50. package/src/migration/strategies.ts +249 -0
  51. package/src/migration/types.ts +182 -0
  52. package/src/utils.ts +3 -145
@@ -0,0 +1,314 @@
1
+ /**
2
+ * Команды для системы миграции конфигураций
3
+ */
4
+
5
+ import {
6
+ MigrationCommand,
7
+ MigrationStepResult,
8
+ ConfigVersion,
9
+ VersionDetector,
10
+ ConfigValidator
11
+ } from './types'
12
+ // Команды для системы миграции конфигураций
13
+
14
+ /** Команда детекции версии конфигурации */
15
+ export class DetectVersionCommand implements MigrationCommand {
16
+ name = 'DetectVersion'
17
+ description = 'Определяет версию конфигурации'
18
+
19
+ execute(config: any): MigrationStepResult {
20
+ try {
21
+ const detector = new DefaultVersionDetector()
22
+ const version = detector.detect(config)
23
+
24
+ if (!version) {
25
+ return {
26
+ success: false,
27
+ errors: ['Не удалось определить версию конфигурации'],
28
+ warnings: [],
29
+ modified: false
30
+ }
31
+ }
32
+
33
+ return {
34
+ success: true,
35
+ data: { version, config },
36
+ errors: [],
37
+ warnings: [],
38
+ modified: false
39
+ }
40
+ } catch (error) {
41
+ return {
42
+ success: false,
43
+ errors: [`Ошибка при детекции версии: ${error}`],
44
+ warnings: [],
45
+ modified: false
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ /** Команда валидации конфигурации */
52
+ export class ValidateConfigCommand implements MigrationCommand {
53
+ name = 'ValidateConfig'
54
+ description = 'Валидирует конфигурацию для указанной версии'
55
+
56
+ execute(config: any, options: { version: ConfigVersion }): MigrationStepResult {
57
+ try {
58
+ const validator = new DefaultConfigValidator()
59
+ const result = validator.validate(config, options.version)
60
+
61
+ return {
62
+ success: result.isValid,
63
+ data: { validationResult: result, config },
64
+ errors: result.errors,
65
+ warnings: result.warnings,
66
+ modified: false
67
+ }
68
+ } catch (error) {
69
+ return {
70
+ success: false,
71
+ errors: [`Ошибка при валидации: ${error}`],
72
+ warnings: [],
73
+ modified: false
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ /** Команда очистки конфигурации от неизвестных полей */
80
+ export class CleanConfigCommand implements MigrationCommand {
81
+ name = 'CleanConfig'
82
+ description = 'Очищает конфигурацию от неизвестных полей для указанной версии'
83
+
84
+ execute(config: any, options: { version: ConfigVersion; preserveUnknown?: boolean }): MigrationStepResult {
85
+ try {
86
+ if (options.preserveUnknown) {
87
+ return {
88
+ success: true,
89
+ data: config,
90
+ errors: [],
91
+ warnings: ['Очистка пропущена - preserveUnknown: true'],
92
+ modified: false
93
+ }
94
+ }
95
+
96
+ // Здесь можно реализовать логику очистки на основе схем
97
+ const cleanedConfig = this.cleanConfigForVersion(config, options.version)
98
+
99
+ return {
100
+ success: true,
101
+ data: cleanedConfig,
102
+ errors: [],
103
+ warnings: ['Конфигурация очищена от неизвестных полей'],
104
+ modified: true
105
+ }
106
+ } catch (error) {
107
+ return {
108
+ success: false,
109
+ errors: [`Ошибка при очистке конфигурации: ${error}`],
110
+ warnings: [],
111
+ modified: false
112
+ }
113
+ }
114
+ }
115
+
116
+ private cleanConfigForVersion(config: any, _version: ConfigVersion): any {
117
+ // Базовая реализация - возвращаем как есть
118
+ // В реальном проекте здесь была бы логика очистки на основе схем
119
+ return { ...config }
120
+ }
121
+ }
122
+
123
+ /** Команда создания резервной копии */
124
+ export class BackupConfigCommand implements MigrationCommand {
125
+ name = 'BackupConfig'
126
+ description = 'Создает резервную копию конфигурации'
127
+
128
+ execute(config: any, options?: { timestamp?: boolean }): MigrationStepResult {
129
+ try {
130
+ const timestamp = options?.timestamp ? Date.now() : undefined
131
+ const backup = {
132
+ original: JSON.parse(JSON.stringify(config)),
133
+ timestamp: timestamp || Date.now(),
134
+ version: new DefaultVersionDetector().detect(config)
135
+ }
136
+
137
+ return {
138
+ success: true,
139
+ data: { backup, config },
140
+ errors: [],
141
+ warnings: [],
142
+ modified: false
143
+ }
144
+ } catch (error) {
145
+ return {
146
+ success: false,
147
+ errors: [`Ошибка при создании резервной копии: ${error}`],
148
+ warnings: [],
149
+ modified: false
150
+ }
151
+ }
152
+ }
153
+ }
154
+
155
+ /** Дефолтный детектор версий */
156
+ export class DefaultVersionDetector implements VersionDetector {
157
+ detect(config: any): ConfigVersion | null {
158
+ try {
159
+ // Проверяем структуру для определения версии
160
+ if (!config || !config.settings || !config.sections) {
161
+ return null
162
+ }
163
+
164
+ // V2 признаки: наличие новых полей
165
+ const hasV2Features = [
166
+ config.settings.loader !== undefined,
167
+ config.settings.buttonStyle !== undefined,
168
+ config.settings.buttonType !== undefined,
169
+ config.sections.top.params?.chipStyle !== undefined,
170
+ config.sections.inside.messageUser?.bgType !== undefined,
171
+ config.sections.inside.aprooveButton !== undefined,
172
+ config.sections.bottom.inputSend?.borderStyle !== undefined,
173
+ config.sections.bottom.warningAlert !== undefined,
174
+ config.sections.bottom.disclaimer !== undefined
175
+ ]
176
+
177
+ // Если есть хотя бы 3 признака V2, считаем это V2
178
+ const v2FeaturesCount = hasV2Features.filter(Boolean).length
179
+ if (v2FeaturesCount >= 3) {
180
+ return '2.0'
181
+ }
182
+
183
+ // Базовая проверка на V1
184
+ const hasV1Structure = [
185
+ config.settings.widgetTitle !== undefined,
186
+ config.settings.bgChat !== undefined,
187
+ config.sections.top !== undefined,
188
+ config.sections.inside !== undefined,
189
+ config.sections.bottom !== undefined
190
+ ].every(Boolean)
191
+
192
+ if (hasV1Structure) {
193
+ return '1.0'
194
+ }
195
+
196
+ return null
197
+ } catch (error) {
198
+ console.error('Ошибка при детекции версии:', error)
199
+ return null
200
+ }
201
+ }
202
+ }
203
+
204
+ /** Дефолтный валидатор конфигураций */
205
+ export class DefaultConfigValidator implements ConfigValidator {
206
+ validate(config: any, version: ConfigVersion): { isValid: boolean; errors: string[]; warnings: string[] } {
207
+ const errors: string[] = []
208
+ const warnings: string[] = []
209
+
210
+ try {
211
+ if (!config) {
212
+ errors.push('Конфигурация не может быть пустой')
213
+ return { isValid: false, errors, warnings }
214
+ }
215
+
216
+ // Базовая валидация структуры
217
+ if (!config.settings) {
218
+ errors.push('Отсутствует секция settings')
219
+ }
220
+
221
+ if (!config.sections) {
222
+ errors.push('Отсутствует секция sections')
223
+ }
224
+
225
+ if (config.sections) {
226
+ if (!config.sections.top) errors.push('Отсутствует секция sections.top')
227
+ if (!config.sections.inside) errors.push('Отсутствует секция sections.inside')
228
+ if (!config.sections.bottom) errors.push('Отсутствует секция sections.bottom')
229
+ }
230
+
231
+ // Версионная валидация
232
+ switch (version) {
233
+ case '1.0':
234
+ this.validateV1(config, errors, warnings)
235
+ break
236
+ case '2.0':
237
+ this.validateV2(config, errors, warnings)
238
+ break
239
+ default:
240
+ warnings.push(`Валидация для версии ${version} не реализована`)
241
+ }
242
+
243
+ return {
244
+ isValid: errors.length === 0,
245
+ errors,
246
+ warnings
247
+ }
248
+ } catch (error) {
249
+ errors.push(`Ошибка при валидации: ${error}`)
250
+ return { isValid: false, errors, warnings }
251
+ }
252
+ }
253
+
254
+ private validateV1(config: any, errors: string[], _warnings: string[]): void {
255
+ // Проверяем обязательные поля V1
256
+ const requiredV1Fields = [
257
+ 'settings.widgetTitle',
258
+ 'settings.welcomeMessage',
259
+ 'settings.bgChat'
260
+ ]
261
+
262
+ for (const field of requiredV1Fields) {
263
+ if (!this.getNestedValue(config, field)) {
264
+ errors.push(`Отсутствует обязательное поле: ${field}`)
265
+ }
266
+ }
267
+ }
268
+
269
+ private validateV2(config: any, errors: string[], warnings: string[]): void {
270
+ // Сначала валидируем как V1
271
+ this.validateV1(config, errors, warnings)
272
+
273
+ // Дополнительные проверки для V2
274
+ const expectedV2Fields = [
275
+ 'settings.loader',
276
+ 'settings.buttonStyle',
277
+ 'sections.inside.aprooveButton',
278
+ 'sections.bottom.warningAlert'
279
+ ]
280
+
281
+ for (const field of expectedV2Fields) {
282
+ if (!this.getNestedValue(config, field)) {
283
+ warnings.push(`Рекомендуется добавить поле V2: ${field}`)
284
+ }
285
+ }
286
+ }
287
+
288
+ private getNestedValue(obj: any, path: string): any {
289
+ return path.split('.').reduce((current, key) => current?.[key], obj)
290
+ }
291
+ }
292
+
293
+ /** Фабрика команд */
294
+ export class CommandFactory {
295
+ private static commands = new Map<string, () => MigrationCommand>([
296
+ ['DetectVersion', () => new DetectVersionCommand()],
297
+ ['ValidateConfig', () => new ValidateConfigCommand()],
298
+ ['CleanConfig', () => new CleanConfigCommand()],
299
+ ['BackupConfig', () => new BackupConfigCommand()]
300
+ ])
301
+
302
+ static createCommand(name: string): MigrationCommand | null {
303
+ const factory = this.commands.get(name)
304
+ return factory ? factory() : null
305
+ }
306
+
307
+ static getAllCommands(): string[] {
308
+ return Array.from(this.commands.keys())
309
+ }
310
+
311
+ static registerCommand(name: string, factory: () => MigrationCommand): void {
312
+ this.commands.set(name, factory)
313
+ }
314
+ }