@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.
Files changed (47) hide show
  1. package/README.md +214 -115
  2. package/dist/config.types.d.ts +111 -44
  3. package/dist/config.types.d.ts.map +1 -1
  4. package/dist/config.types.js +2 -67
  5. package/dist/config.types.js.map +1 -1
  6. package/dist/index.d.ts +6 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +5 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/migration/commands.d.ts +59 -0
  11. package/dist/migration/commands.d.ts.map +1 -0
  12. package/dist/migration/commands.js +286 -0
  13. package/dist/migration/commands.js.map +1 -0
  14. package/dist/migration/examples.d.ts +198 -0
  15. package/dist/migration/examples.d.ts.map +1 -0
  16. package/dist/migration/examples.js +439 -0
  17. package/dist/migration/examples.js.map +1 -0
  18. package/dist/migration/facade.d.ts +85 -0
  19. package/dist/migration/facade.d.ts.map +1 -0
  20. package/dist/migration/facade.js +168 -0
  21. package/dist/migration/facade.js.map +1 -0
  22. package/dist/migration/migrator.d.ts +49 -0
  23. package/dist/migration/migrator.d.ts.map +1 -0
  24. package/dist/migration/migrator.js +245 -0
  25. package/dist/migration/migrator.js.map +1 -0
  26. package/dist/migration/strategies.d.ts +85 -0
  27. package/dist/migration/strategies.d.ts.map +1 -0
  28. package/dist/migration/strategies.js +217 -0
  29. package/dist/migration/strategies.js.map +1 -0
  30. package/dist/migration/types.d.ts +196 -0
  31. package/dist/migration/types.d.ts.map +1 -0
  32. package/dist/migration/types.js +5 -0
  33. package/dist/migration/types.js.map +1 -0
  34. package/dist/utils.d.ts +1 -11
  35. package/dist/utils.d.ts.map +1 -1
  36. package/dist/utils.js +3 -127
  37. package/dist/utils.js.map +1 -1
  38. package/package.json +13 -4
  39. package/src/config.types.ts +132 -118
  40. package/src/index.ts +26 -0
  41. package/src/migration/commands.ts +314 -0
  42. package/src/migration/examples.ts +471 -0
  43. package/src/migration/facade.ts +196 -0
  44. package/src/migration/migrator.ts +361 -0
  45. package/src/migration/strategies.ts +249 -0
  46. package/src/migration/types.ts +182 -0
  47. package/src/utils.ts +3 -143
@@ -1,63 +1,165 @@
1
+ import config from '../examples/configV2.json'
1
2
  /**
2
- * Типы для конфигурации виджета чата
3
+ * Типы для конфигурации виджета чата (V2)
3
4
  */
4
5
 
5
6
  // Базовые типы
6
7
  export type Size = 'sm' | 'md' | 'lg'
7
8
  export type BorderRadius = '0' | 'sm' | 'md' | 'lg'
8
9
  export type BtnType = 'icon' | 'text' | 'both'
9
- export type LaunchView = 'closed' | 'compact' | 'open'
10
+ export type LaunchView = 'closed' | 'compact'
11
+ export type ChipStyle = 'filled' | 'outlined' | 'invisible'
12
+ export type Loader = 'dots' | 'dots-pulse' | 'circle-pulse' | 'circle-pulse-1'
13
+ export type BgType = 'plain' | 'bubble'
14
+ export type InputStyle = 'inside' | 'stacked'
15
+ export type ButtonStyle = 'filled' | 'outlined' | 'invisible'
16
+ export type WarningStyle = 'gradient' | 'filled' | 'faded'
17
+
18
+ // Схема конфигурации
19
+ export interface ConfigSchema {
20
+ version: string
21
+ required: string[]
22
+ }
23
+
24
+ // Настройки виджета
25
+ export interface WidgetSettings {
26
+ bgChat: string
27
+ gapMessageLine: number
28
+ fontFamily: string
29
+ borderRadius: BorderRadius
30
+ launchView: LaunchView
31
+ letterSpacing: number
32
+ logo: string
33
+ fontWeight: number
34
+ loader: Loader
35
+ }
36
+
37
+ // Тексты виджета
38
+ export interface WidgetTexts {
39
+ welcomeMessage: string
40
+ widgetTitle: string
41
+ launchIssueTitle: string
42
+ launchIssueText: string
43
+ issueText: string
44
+ reconnectText: string
45
+ inputPlaceholder: string
46
+ disableInputText: string
47
+ disclaimer: string
48
+ }
49
+
50
+ // Базовые типы для элементов
51
+ export interface BorderStyle {
52
+ borderColor: string
53
+ borderWidth?: number
54
+ }
55
+
10
56
  export interface ColorItems {
11
57
  color?: string
12
58
  bgColor?: string
13
59
  }
14
- // Типы для элементов интерфейса
60
+
15
61
  export interface UIElement {
16
62
  color: string
17
63
  bgColor?: string
18
64
  type?: BtnType
65
+ bgType?: BgType
19
66
  }
20
67
 
21
- export interface SectionParams {
22
- size: Size
68
+ export interface InputSendElement extends UIElement {
69
+ inputStyle: InputStyle
70
+ borderStyle: BorderStyle
23
71
  }
24
72
 
25
- // Типы для настроек
26
- export interface WidgetSettings {
27
- widgetTitle: string
28
- welcomeMessage: string
29
- bgChat: string
30
- gapMessageLine: number
31
- paddingChat: number
32
- fontFamily: string
33
- borderRadius: BorderRadius
34
- launchView: LaunchView
35
- letterSpacing: number
36
- logo: string
73
+ // Типы для Active Snippet
74
+ export interface ActiveSnippetParams {
75
+ buttonType: BtnType
76
+ buttonStyle: ButtonStyle
77
+ }
78
+
79
+ export interface ActiveSnippetElement {
80
+ params: ActiveSnippetParams
81
+ color: string
82
+ bgColor: string
83
+ headerChip: ColorItems
84
+ propertyColor: string
85
+ valueColor: string
86
+ yesButton: ColorItems
87
+ noButton: ColorItems
88
+ }
89
+
90
+ // Типы для предупреждений
91
+ export interface WarningParams {
92
+ warningStyle: WarningStyle
93
+ showIcon: boolean
94
+ icon: string
95
+ }
96
+
97
+ export interface WarningElement {
98
+ params: WarningParams
99
+ iconColor: string
100
+ bgColor: string
101
+ headlineColor?: string
102
+ color: string
103
+ resetButton?: {
104
+ color: string
105
+ bgColor: string
106
+ }
107
+ }
108
+
109
+ export interface WarningsSection {
110
+ launchIssue: WarningElement
111
+ connectionIssue: WarningElement
112
+ reconnectIssue: WarningElement
113
+ disableInputIssue: {
114
+ iconColor: string
115
+ bgColor: string
116
+ color: string
117
+ }
118
+ }
119
+
120
+ // Типы для лоадера
121
+ export interface LoaderSection {
122
+ completeStep: string
123
+ activeStep: string
37
124
  }
38
125
 
39
126
  // Типы для секций
40
127
  export interface TopSection {
41
- params: SectionParams
42
- chipWidgetTitle: UIElement
43
- btnClose: UIElement
128
+ params: {
129
+ size: Size
130
+ chipStyle: ChipStyle
131
+ chipType: BtnType
132
+ buttonStyle: ButtonStyle
133
+ buttonType: BtnType
134
+ }
135
+ chipWidgetTitle: ColorItems
136
+ buttons: ColorItems
44
137
  }
45
138
 
46
139
  export interface InsideSection {
47
- params: SectionParams
140
+ params: {
141
+ size: Size
142
+ }
48
143
  messageUser: UIElement
49
144
  messageBot: UIElement
145
+ activeSnippet: ActiveSnippetElement
50
146
  welcomeMessage: UIElement
51
147
  }
52
148
 
53
149
  export interface BottomSection {
54
- params: SectionParams
55
- inputSend: UIElement
150
+ params: {
151
+ size: Size
152
+ disclaimerShow: boolean
153
+ }
154
+ inputSend: InputSendElement
155
+ warningAlert: UIElement
56
156
  btnSend: UIElement
57
157
  activeBtn: UIElement
58
158
  }
59
159
 
60
160
  export interface WidgetSections {
161
+ warnings: WarningsSection
162
+ loader: LoaderSection
61
163
  top: TopSection
62
164
  inside: InsideSection
63
165
  bottom: BottomSection
@@ -65,18 +167,22 @@ export interface WidgetSections {
65
167
 
66
168
  // Основной тип конфигурации
67
169
  export interface WidgetConfig {
170
+ schema: ConfigSchema
68
171
  settings: WidgetSettings
172
+ texts: WidgetTexts
69
173
  sections: WidgetSections
70
174
  }
71
175
 
72
176
  // Типы для частичного обновления конфигурации
73
177
  export type PartialWidgetConfig = Partial<WidgetConfig>
74
178
  export type PartialWidgetSettings = Partial<WidgetSettings>
179
+ export type PartialWidgetTexts = Partial<WidgetTexts>
75
180
  export type PartialWidgetSections = Partial<WidgetSections>
76
181
 
77
182
  // Утилитарные типы
78
183
  export type ConfigKey = keyof WidgetConfig
79
184
  export type SettingsKey = keyof WidgetSettings
185
+ export type TextsKey = keyof WidgetTexts
80
186
  export type SectionsKey = keyof WidgetSections
81
187
 
82
188
  // Типы для валидации
@@ -85,101 +191,9 @@ export interface ConfigValidationResult {
85
191
  errors: string[]
86
192
  }
87
193
 
88
-
89
- export type GeneralSettings = Pick<WidgetSettings, 'widgetTitle' | 'welcomeMessage' | 'launchView' | 'logo'>
90
-
91
- export type ShapesSettings = Pick<
92
- WidgetSettings,
93
- 'gapMessageLine' | 'paddingChat' | 'fontFamily' | 'borderRadius'
94
- > & {
95
- bottomSize: WidgetConfig['sections']['bottom']['params']['size']
96
- sendButtonType: BtnType
97
- headerSize: WidgetConfig['sections']['top']['params']['size']
98
- messageSize: WidgetConfig['sections']['inside']['params']['size']
99
- }
100
- export type EmittedColorElement = {
101
- bgChat: ColorItems
102
- chipWidgetTitle: ColorItems
103
- btnClose: ColorItems
104
- messageUser: ColorItems
105
- messageBot: ColorItems
106
- inputSend: ColorItems
107
- btnSend: ColorItems
108
- activeBtn: ColorItems
109
- welcomeMessage: ColorItems
110
- }
111
- export interface FontSettings {
112
- fontFamily: string
113
- letterSpacing: number
114
- }
115
-
116
- // Экспорт дефолтной конфигурации (для типизации)
117
- export const DEFAULT_CONFIG: WidgetConfig = {
118
- settings: {
119
- widgetTitle: 'HyperShadow',
120
- welcomeMessage:
121
- '🖖 Hi there — I’m your assistant for finding documents, tracking access, and making sense of your files. \n\nHow can I help?',
122
- bgChat: 'rgba(47, 47, 49, 0.90)',
123
- gapMessageLine: 12,
124
- paddingChat: 8,
125
- fontFamily: 'MacPaw Fixel',
126
- borderRadius: 'lg',
127
- launchView: 'closed',
128
- letterSpacing: 0,
129
- logo: '',
130
- },
131
- sections: {
132
- top: {
133
- params: {
134
- size: 'md',
135
- },
136
- chipWidgetTitle: {
137
- color: '#BEB6E9',
138
- bgColor: '#5E4AC6',
139
- },
140
- btnClose: {
141
- color: '#BBBBBD',
142
- bgColor: '#2F2F31',
143
- },
144
- },
145
- inside: {
146
- params: {
147
- size: 'md',
148
- },
149
- messageUser: {
150
- color: '#F9F8F8',
151
- bgColor: '#F8F8F933',
152
- },
153
- messageBot: {
154
- color: '#fff',
155
- bgColor: '#5E4AC6',
156
- },
157
- welcomeMessage: {
158
- color: '#fff',
159
- },
160
- },
161
- bottom: {
162
- params: {
163
- size: 'sm',
164
- },
165
- inputSend: {
166
- color: '#EEECEC',
167
- bgColor: '#1E1E1E',
168
- },
169
- btnSend: {
170
- color: '#1E1E1E',
171
- bgColor: 'rgba(255, 255, 255, 0.50)',
172
- type: 'both',
173
- },
174
- activeBtn: {
175
- color: '#fff',
176
- bgColor: '#F8F8F933',
177
- },
178
- },
179
- },
180
- }
181
-
182
194
  // Утилитарный тип для глубоких частичных объектов
183
195
  export type DeepPartial<T> = {
184
196
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]
185
- }
197
+ }
198
+
199
+ export const DEFAULT_CONFIG: WidgetConfig = config as WidgetConfig
package/src/index.ts CHANGED
@@ -1,2 +1,28 @@
1
1
  export * from './config.types'
2
2
  export * from './utils'
3
+
4
+ // Система миграции конфигураций
5
+ // Явный реэкспорт с алиасом для конфликтующего имени ConfigSchema
6
+ export {
7
+ ConfigVersion,
8
+ MigrationResult,
9
+ MigrationContext,
10
+ MigrationOptions,
11
+ MigrationStrategy,
12
+ MigrationStepResult,
13
+ MigrationCommand,
14
+ VersionDetector,
15
+ ConfigValidator,
16
+ ConfigSchema as MigrationConfigSchema,
17
+ MigrationReport,
18
+ MigrationLogger,
19
+ ConfigV1,
20
+ ConfigV2,
21
+ ConfigByVersion,
22
+ ConfigFactory,
23
+ } from './migration/types'
24
+ export * from './migration/strategies'
25
+ export * from './migration/commands'
26
+ export * from './migration/migrator'
27
+ export * from './migration/facade'
28
+ export * from './migration/examples'
@@ -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
+ }