@bernierllc/chat-suite 1.0.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.
- package/.eslintrc.js +26 -0
- package/README.md +542 -0
- package/__tests__/integration/ChatSuite.test.ts +235 -0
- package/__tests__/unit/ConfigManager.test.ts +122 -0
- package/__tests__/unit/MessageOrchestrator.test.ts +223 -0
- package/__tests__/unit/UserManager.test.ts +208 -0
- package/dist/ChatSuite.d.ts +76 -0
- package/dist/ChatSuite.d.ts.map +1 -0
- package/dist/ChatSuite.js +273 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/neverhub/discovery.d.ts +40 -0
- package/dist/neverhub/discovery.d.ts.map +1 -0
- package/dist/neverhub/discovery.js +106 -0
- package/dist/neverhub/event-handlers.d.ts +38 -0
- package/dist/neverhub/event-handlers.d.ts.map +1 -0
- package/dist/neverhub/event-handlers.js +125 -0
- package/dist/neverhub/index.d.ts +4 -0
- package/dist/neverhub/index.d.ts.map +1 -0
- package/dist/neverhub/index.js +26 -0
- package/dist/neverhub/service-registration.d.ts +29 -0
- package/dist/neverhub/service-registration.d.ts.map +1 -0
- package/dist/neverhub/service-registration.js +66 -0
- package/dist/providers/ChatKitProvider.d.ts +53 -0
- package/dist/providers/ChatKitProvider.d.ts.map +1 -0
- package/dist/providers/ChatKitProvider.js +167 -0
- package/dist/providers/ExternalProviders.d.ts +101 -0
- package/dist/providers/ExternalProviders.d.ts.map +1 -0
- package/dist/providers/ExternalProviders.js +153 -0
- package/dist/providers/index.d.ts +3 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +25 -0
- package/dist/services/ConfigManager.d.ts +50 -0
- package/dist/services/ConfigManager.d.ts.map +1 -0
- package/dist/services/ConfigManager.js +95 -0
- package/dist/services/HealthMonitor.d.ts +58 -0
- package/dist/services/HealthMonitor.d.ts.map +1 -0
- package/dist/services/HealthMonitor.js +148 -0
- package/dist/services/MessageOrchestrator.d.ts +63 -0
- package/dist/services/MessageOrchestrator.d.ts.map +1 -0
- package/dist/services/MessageOrchestrator.js +212 -0
- package/dist/services/ProviderManager.d.ts +83 -0
- package/dist/services/ProviderManager.d.ts.map +1 -0
- package/dist/services/ProviderManager.js +204 -0
- package/dist/services/UserManager.d.ts +61 -0
- package/dist/services/UserManager.d.ts.map +1 -0
- package/dist/services/UserManager.js +141 -0
- package/dist/services/index.d.ts +6 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +28 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +26 -0
- package/dist/types/message-types.d.ts +80 -0
- package/dist/types/message-types.d.ts.map +1 -0
- package/dist/types/message-types.js +32 -0
- package/dist/types/provider-types.d.ts +96 -0
- package/dist/types/provider-types.d.ts.map +1 -0
- package/dist/types/provider-types.js +9 -0
- package/dist/types/suite-types.d.ts +101 -0
- package/dist/types/suite-types.d.ts.map +1 -0
- package/dist/types/suite-types.js +9 -0
- package/dist/utils/config-inheritance.d.ts +24 -0
- package/dist/utils/config-inheritance.d.ts.map +1 -0
- package/dist/utils/config-inheritance.js +167 -0
- package/dist/utils/error-handling.d.ts +37 -0
- package/dist/utils/error-handling.d.ts.map +1 -0
- package/dist/utils/error-handling.js +102 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +27 -0
- package/dist/utils/message-bridge.d.ts +68 -0
- package/dist/utils/message-bridge.d.ts.map +1 -0
- package/dist/utils/message-bridge.js +126 -0
- package/dist/utils/user-mapping.d.ts +63 -0
- package/dist/utils/user-mapping.d.ts.map +1 -0
- package/dist/utils/user-mapping.js +110 -0
- package/jest.config.cjs +30 -0
- package/package.json +67 -0
- package/src/ChatSuite.ts +347 -0
- package/src/index.ts +25 -0
- package/src/neverhub/discovery.ts +137 -0
- package/src/neverhub/event-handlers.ts +141 -0
- package/src/neverhub/index.ts +11 -0
- package/src/neverhub/service-registration.ts +89 -0
- package/src/providers/ChatKitProvider.ts +193 -0
- package/src/providers/ExternalProviders.ts +171 -0
- package/src/providers/index.ts +10 -0
- package/src/services/ConfigManager.ts +112 -0
- package/src/services/HealthMonitor.ts +169 -0
- package/src/services/MessageOrchestrator.ts +271 -0
- package/src/services/ProviderManager.ts +247 -0
- package/src/services/UserManager.ts +176 -0
- package/src/services/index.ts +13 -0
- package/src/types/index.ts +11 -0
- package/src/types/message-types.ts +94 -0
- package/src/types/provider-types.ts +116 -0
- package/src/types/suite-types.ts +117 -0
- package/src/utils/config-inheritance.ts +189 -0
- package/src/utils/error-handling.ts +114 -0
- package/src/utils/index.ts +12 -0
- package/src/utils/message-bridge.ts +164 -0
- package/src/utils/user-mapping.ts +132 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ProviderType, ProviderAttachment } from './provider-types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Message priority levels
|
|
13
|
+
*/
|
|
14
|
+
export enum MessagePriority {
|
|
15
|
+
LOW = 'low',
|
|
16
|
+
NORMAL = 'normal',
|
|
17
|
+
HIGH = 'high',
|
|
18
|
+
URGENT = 'urgent'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Message status
|
|
23
|
+
*/
|
|
24
|
+
export enum MessageStatus {
|
|
25
|
+
PENDING = 'pending',
|
|
26
|
+
ROUTING = 'routing',
|
|
27
|
+
SENDING = 'sending',
|
|
28
|
+
SENT = 'sent',
|
|
29
|
+
FAILED = 'failed',
|
|
30
|
+
RETRYING = 'retrying'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Orchestrated message that will be routed through the suite
|
|
35
|
+
*/
|
|
36
|
+
export interface OrchestratedMessage {
|
|
37
|
+
id: string;
|
|
38
|
+
content: string;
|
|
39
|
+
userId?: string;
|
|
40
|
+
channelId?: string;
|
|
41
|
+
threadId?: string;
|
|
42
|
+
attachments?: ProviderAttachment[];
|
|
43
|
+
priority: MessagePriority;
|
|
44
|
+
status: MessageStatus;
|
|
45
|
+
targetProviders?: ProviderType[];
|
|
46
|
+
metadata?: Record<string, unknown>;
|
|
47
|
+
createdAt: Date;
|
|
48
|
+
updatedAt: Date;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Message routing decision
|
|
53
|
+
*/
|
|
54
|
+
export interface RoutingDecision {
|
|
55
|
+
provider: ProviderType;
|
|
56
|
+
confidence: number;
|
|
57
|
+
reasoning?: string;
|
|
58
|
+
fallbackProviders?: ProviderType[];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Message broadcast configuration
|
|
63
|
+
*/
|
|
64
|
+
export interface BroadcastConfig {
|
|
65
|
+
content: string;
|
|
66
|
+
platforms: ProviderType[];
|
|
67
|
+
channels?: string[];
|
|
68
|
+
priority?: MessagePriority;
|
|
69
|
+
metadata?: Record<string, unknown>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Message bridge configuration for cross-platform sync
|
|
74
|
+
*/
|
|
75
|
+
export interface MessageBridgeConfig {
|
|
76
|
+
enabled: boolean;
|
|
77
|
+
sourceProviders: ProviderType[];
|
|
78
|
+
targetProviders: ProviderType[];
|
|
79
|
+
channelMappings?: Map<string, string>;
|
|
80
|
+
syncReactions?: boolean;
|
|
81
|
+
syncEdits?: boolean;
|
|
82
|
+
syncDeletions?: boolean;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Message event data
|
|
87
|
+
*/
|
|
88
|
+
export interface MessageEvent {
|
|
89
|
+
type: 'message.sent' | 'message.received' | 'message.failed' | 'message.bridged';
|
|
90
|
+
messageId: string;
|
|
91
|
+
provider: ProviderType;
|
|
92
|
+
timestamp: Date;
|
|
93
|
+
data: Record<string, unknown>;
|
|
94
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Provider type identifiers
|
|
11
|
+
*/
|
|
12
|
+
export type ProviderType = 'chatkit' | 'slack' | 'discord' | 'teams';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Provider health status
|
|
16
|
+
*/
|
|
17
|
+
export type ProviderHealthStatus = 'healthy' | 'degraded' | 'unhealthy' | 'unknown';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Provider configuration
|
|
21
|
+
*/
|
|
22
|
+
export interface ProviderConfig {
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
priority: number;
|
|
25
|
+
config: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Provider health information
|
|
30
|
+
*/
|
|
31
|
+
export interface ProviderHealth {
|
|
32
|
+
status: ProviderHealthStatus;
|
|
33
|
+
lastCheck: Date;
|
|
34
|
+
latency?: number;
|
|
35
|
+
errorCount: number;
|
|
36
|
+
uptime?: number;
|
|
37
|
+
details?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Provider interface that all providers must implement
|
|
42
|
+
*/
|
|
43
|
+
export interface Provider {
|
|
44
|
+
readonly type: ProviderType;
|
|
45
|
+
readonly name: string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Initialize the provider
|
|
49
|
+
*/
|
|
50
|
+
initialize(): Promise<void>;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Check if the provider is initialized
|
|
54
|
+
*/
|
|
55
|
+
isInitialized(): boolean;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Send a message through this provider
|
|
59
|
+
*/
|
|
60
|
+
sendMessage(message: ProviderMessage): Promise<ProviderMessageResult>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get health status of this provider
|
|
64
|
+
*/
|
|
65
|
+
getHealth(): Promise<ProviderHealth>;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Shutdown the provider
|
|
69
|
+
*/
|
|
70
|
+
shutdown(): Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Message to be sent through a provider
|
|
75
|
+
*/
|
|
76
|
+
export interface ProviderMessage {
|
|
77
|
+
content: string;
|
|
78
|
+
userId?: string;
|
|
79
|
+
channelId?: string;
|
|
80
|
+
threadId?: string;
|
|
81
|
+
attachments?: ProviderAttachment[];
|
|
82
|
+
metadata?: Record<string, unknown>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* File attachment
|
|
87
|
+
*/
|
|
88
|
+
export interface ProviderAttachment {
|
|
89
|
+
filename: string;
|
|
90
|
+
contentType: string;
|
|
91
|
+
data: Buffer | string;
|
|
92
|
+
size: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Result from sending a message
|
|
97
|
+
*/
|
|
98
|
+
export interface ProviderMessageResult {
|
|
99
|
+
success: boolean;
|
|
100
|
+
messageId?: string;
|
|
101
|
+
timestamp?: Date;
|
|
102
|
+
error?: string;
|
|
103
|
+
provider: ProviderType;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Provider capabilities
|
|
108
|
+
*/
|
|
109
|
+
export interface ProviderCapabilities {
|
|
110
|
+
streaming: boolean;
|
|
111
|
+
attachments: boolean;
|
|
112
|
+
threads: boolean;
|
|
113
|
+
reactions: boolean;
|
|
114
|
+
editing: boolean;
|
|
115
|
+
deletion: boolean;
|
|
116
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ProviderType, ProviderConfig } from './provider-types';
|
|
10
|
+
import type { MessageBridgeConfig } from './message-types';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* AI routing configuration
|
|
14
|
+
*/
|
|
15
|
+
export interface AIRoutingConfig {
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
serviceName?: string;
|
|
18
|
+
fallbackToHuman?: boolean;
|
|
19
|
+
intentThreshold?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Analytics configuration
|
|
24
|
+
*/
|
|
25
|
+
export interface AnalyticsConfig {
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
serviceName?: string;
|
|
28
|
+
metricsInterval?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* NeverHub capability definition
|
|
33
|
+
*/
|
|
34
|
+
export interface NeverHubCapability {
|
|
35
|
+
type: string;
|
|
36
|
+
name: string;
|
|
37
|
+
version: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* NeverHub configuration
|
|
42
|
+
*/
|
|
43
|
+
export interface NeverHubConfig {
|
|
44
|
+
enabled: boolean;
|
|
45
|
+
serviceName: string;
|
|
46
|
+
capabilities: NeverHubCapability[];
|
|
47
|
+
dependencies: string[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Provider configurations map
|
|
52
|
+
*/
|
|
53
|
+
export interface ProviderConfigs {
|
|
54
|
+
chatkit?: ProviderConfig;
|
|
55
|
+
slack?: ProviderConfig;
|
|
56
|
+
discord?: ProviderConfig;
|
|
57
|
+
teams?: ProviderConfig;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Complete chat suite configuration
|
|
62
|
+
*/
|
|
63
|
+
export interface ChatSuiteConfig {
|
|
64
|
+
enabled: boolean;
|
|
65
|
+
providers: ProviderConfigs;
|
|
66
|
+
aiRouting?: AIRoutingConfig;
|
|
67
|
+
analytics?: AnalyticsConfig;
|
|
68
|
+
neverhub?: NeverHubConfig;
|
|
69
|
+
messageBridge?: MessageBridgeConfig;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Chat suite health status
|
|
74
|
+
*/
|
|
75
|
+
export interface ChatSuiteHealth {
|
|
76
|
+
status: 'healthy' | 'degraded' | 'unhealthy';
|
|
77
|
+
providers: Record<ProviderType, {
|
|
78
|
+
status: string;
|
|
79
|
+
latency?: number;
|
|
80
|
+
errorCount: number;
|
|
81
|
+
}>;
|
|
82
|
+
aiRouting?: {
|
|
83
|
+
enabled: boolean;
|
|
84
|
+
status: string;
|
|
85
|
+
};
|
|
86
|
+
analytics?: {
|
|
87
|
+
enabled: boolean;
|
|
88
|
+
status: string;
|
|
89
|
+
};
|
|
90
|
+
neverhub?: {
|
|
91
|
+
enabled: boolean;
|
|
92
|
+
connected: boolean;
|
|
93
|
+
};
|
|
94
|
+
timestamp: Date;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Suite initialization result
|
|
99
|
+
*/
|
|
100
|
+
export interface SuiteInitResult {
|
|
101
|
+
success: boolean;
|
|
102
|
+
providersInitialized: ProviderType[];
|
|
103
|
+
providersFailed: ProviderType[];
|
|
104
|
+
aiRoutingEnabled: boolean;
|
|
105
|
+
analyticsEnabled: boolean;
|
|
106
|
+
neverhubConnected: boolean;
|
|
107
|
+
error?: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Suite operation result
|
|
112
|
+
*/
|
|
113
|
+
export interface SuiteResult<T = unknown> {
|
|
114
|
+
success: boolean;
|
|
115
|
+
data?: T;
|
|
116
|
+
error?: string;
|
|
117
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ChatSuiteConfig, ProviderConfigs, ProviderConfig } from '../types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Default provider configuration
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_PROVIDER_CONFIG: ProviderConfig = {
|
|
15
|
+
enabled: false,
|
|
16
|
+
priority: 999,
|
|
17
|
+
config: {}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Default chat suite configuration
|
|
22
|
+
*/
|
|
23
|
+
export const DEFAULT_SUITE_CONFIG: ChatSuiteConfig = {
|
|
24
|
+
enabled: true,
|
|
25
|
+
providers: {
|
|
26
|
+
chatkit: {
|
|
27
|
+
enabled: true,
|
|
28
|
+
priority: 1,
|
|
29
|
+
config: {
|
|
30
|
+
serviceName: 'chatkit-adapter',
|
|
31
|
+
features: ['streaming', 'attachments', 'threads']
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
aiRouting: {
|
|
36
|
+
enabled: true,
|
|
37
|
+
serviceName: 'chat-ai-router',
|
|
38
|
+
fallbackToHuman: true,
|
|
39
|
+
intentThreshold: 0.8
|
|
40
|
+
},
|
|
41
|
+
analytics: {
|
|
42
|
+
enabled: true,
|
|
43
|
+
serviceName: 'chat-analytics',
|
|
44
|
+
metricsInterval: 60000
|
|
45
|
+
},
|
|
46
|
+
neverhub: {
|
|
47
|
+
enabled: true,
|
|
48
|
+
serviceName: 'chat-suite',
|
|
49
|
+
capabilities: [
|
|
50
|
+
{ type: 'chat', name: 'multi-provider-chat', version: '1.0.0' },
|
|
51
|
+
{ type: 'orchestration', name: 'chat-orchestration', version: '1.0.0' },
|
|
52
|
+
{ type: 'ai', name: 'intelligent-routing', version: '1.0.0' }
|
|
53
|
+
],
|
|
54
|
+
dependencies: ['chat-provider-*', 'chat-ai-router', 'chat-analytics']
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Merge configurations with inheritance
|
|
60
|
+
*/
|
|
61
|
+
export function mergeConfigs(
|
|
62
|
+
baseConfig: ChatSuiteConfig,
|
|
63
|
+
overrideConfig: Partial<ChatSuiteConfig>
|
|
64
|
+
): ChatSuiteConfig {
|
|
65
|
+
return {
|
|
66
|
+
enabled: overrideConfig.enabled ?? baseConfig.enabled,
|
|
67
|
+
providers: mergeProviderConfigs(baseConfig.providers, overrideConfig.providers),
|
|
68
|
+
aiRouting: overrideConfig.aiRouting ? {
|
|
69
|
+
...baseConfig.aiRouting,
|
|
70
|
+
...overrideConfig.aiRouting
|
|
71
|
+
} : baseConfig.aiRouting,
|
|
72
|
+
analytics: overrideConfig.analytics ? {
|
|
73
|
+
...baseConfig.analytics,
|
|
74
|
+
...overrideConfig.analytics
|
|
75
|
+
} : baseConfig.analytics,
|
|
76
|
+
neverhub: overrideConfig.neverhub ? {
|
|
77
|
+
...baseConfig.neverhub,
|
|
78
|
+
...overrideConfig.neverhub
|
|
79
|
+
} : baseConfig.neverhub,
|
|
80
|
+
messageBridge: overrideConfig.messageBridge ?? baseConfig.messageBridge
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Merge provider configurations
|
|
86
|
+
*/
|
|
87
|
+
function mergeProviderConfigs(
|
|
88
|
+
baseProviders: ProviderConfigs,
|
|
89
|
+
overrideProviders?: Partial<ProviderConfigs>
|
|
90
|
+
): ProviderConfigs {
|
|
91
|
+
if (!overrideProviders) {
|
|
92
|
+
return baseProviders;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
chatkit: mergeProviderConfig(baseProviders.chatkit, overrideProviders.chatkit),
|
|
97
|
+
slack: mergeProviderConfig(baseProviders.slack, overrideProviders.slack),
|
|
98
|
+
discord: mergeProviderConfig(baseProviders.discord, overrideProviders.discord),
|
|
99
|
+
teams: mergeProviderConfig(baseProviders.teams, overrideProviders.teams)
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Merge individual provider configuration
|
|
105
|
+
*/
|
|
106
|
+
function mergeProviderConfig(
|
|
107
|
+
base?: ProviderConfig,
|
|
108
|
+
override?: ProviderConfig
|
|
109
|
+
): ProviderConfig | undefined {
|
|
110
|
+
if (!override && !base) {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const baseConfig = base || DEFAULT_PROVIDER_CONFIG;
|
|
115
|
+
if (!override) {
|
|
116
|
+
return baseConfig;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
enabled: override.enabled ?? baseConfig.enabled,
|
|
121
|
+
priority: override.priority ?? baseConfig.priority,
|
|
122
|
+
config: {
|
|
123
|
+
...baseConfig.config,
|
|
124
|
+
...override.config
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Validate configuration
|
|
131
|
+
*/
|
|
132
|
+
export function validateConfig(config: ChatSuiteConfig): { valid: boolean; errors: string[] } {
|
|
133
|
+
const errors: string[] = [];
|
|
134
|
+
|
|
135
|
+
// Check that at least one provider is enabled
|
|
136
|
+
const enabledProviders = Object.values(config.providers).filter(p => p?.enabled);
|
|
137
|
+
if (enabledProviders.length === 0) {
|
|
138
|
+
errors.push('At least one provider must be enabled');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Validate AI routing config
|
|
142
|
+
if (config.aiRouting?.enabled) {
|
|
143
|
+
if (!config.aiRouting.serviceName) {
|
|
144
|
+
errors.push('AI routing service name is required when AI routing is enabled');
|
|
145
|
+
}
|
|
146
|
+
if (config.aiRouting.intentThreshold !== undefined &&
|
|
147
|
+
(config.aiRouting.intentThreshold < 0 || config.aiRouting.intentThreshold > 1)) {
|
|
148
|
+
errors.push('AI routing intent threshold must be between 0 and 1');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Validate analytics config
|
|
153
|
+
if (config.analytics?.enabled && !config.analytics.serviceName) {
|
|
154
|
+
errors.push('Analytics service name is required when analytics is enabled');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Validate NeverHub config
|
|
158
|
+
if (config.neverhub?.enabled) {
|
|
159
|
+
if (!config.neverhub.serviceName) {
|
|
160
|
+
errors.push('NeverHub service name is required when NeverHub is enabled');
|
|
161
|
+
}
|
|
162
|
+
if (!config.neverhub.capabilities || config.neverhub.capabilities.length === 0) {
|
|
163
|
+
errors.push('NeverHub capabilities are required when NeverHub is enabled');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
valid: errors.length === 0,
|
|
169
|
+
errors
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get active providers from configuration
|
|
175
|
+
*/
|
|
176
|
+
export function getActiveProviders(config: ChatSuiteConfig): Array<{ name: string; priority: number }> {
|
|
177
|
+
const providers: Array<{ name: string; priority: number }> = [];
|
|
178
|
+
|
|
179
|
+
Object.entries(config.providers).forEach(([name, providerConfig]) => {
|
|
180
|
+
if (providerConfig?.enabled) {
|
|
181
|
+
providers.push({
|
|
182
|
+
name,
|
|
183
|
+
priority: providerConfig.priority
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
return providers.sort((a, b) => a.priority - b.priority);
|
|
189
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { SuiteResult } from '../types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Chat suite error types
|
|
13
|
+
*/
|
|
14
|
+
export enum ChatSuiteErrorType {
|
|
15
|
+
PROVIDER_ERROR = 'PROVIDER_ERROR',
|
|
16
|
+
ROUTING_ERROR = 'ROUTING_ERROR',
|
|
17
|
+
CONFIGURATION_ERROR = 'CONFIGURATION_ERROR',
|
|
18
|
+
INITIALIZATION_ERROR = 'INITIALIZATION_ERROR',
|
|
19
|
+
MESSAGE_ERROR = 'MESSAGE_ERROR',
|
|
20
|
+
NEVERHUB_ERROR = 'NEVERHUB_ERROR'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Custom error class for chat suite errors
|
|
25
|
+
*/
|
|
26
|
+
export class ChatSuiteError extends Error {
|
|
27
|
+
constructor(
|
|
28
|
+
public type: ChatSuiteErrorType,
|
|
29
|
+
message: string,
|
|
30
|
+
public originalError?: Error
|
|
31
|
+
) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = 'ChatSuiteError';
|
|
34
|
+
Object.setPrototypeOf(this, ChatSuiteError.prototype);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Safely execute an async operation and return a SuiteResult
|
|
40
|
+
*/
|
|
41
|
+
export async function safeExecute<T>(
|
|
42
|
+
operation: () => Promise<T>,
|
|
43
|
+
errorType: ChatSuiteErrorType = ChatSuiteErrorType.MESSAGE_ERROR
|
|
44
|
+
): Promise<SuiteResult<T>> {
|
|
45
|
+
try {
|
|
46
|
+
const data = await operation();
|
|
47
|
+
return { success: true, data };
|
|
48
|
+
} catch (error) {
|
|
49
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
error: `${errorType}: ${errorMessage}`
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Retry an operation with exponential backoff
|
|
59
|
+
*/
|
|
60
|
+
export async function retryOperation<T>(
|
|
61
|
+
operation: () => Promise<T>,
|
|
62
|
+
maxRetries: number = 3,
|
|
63
|
+
baseDelay: number = 1000
|
|
64
|
+
): Promise<T> {
|
|
65
|
+
let lastError: Error | undefined;
|
|
66
|
+
|
|
67
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
68
|
+
try {
|
|
69
|
+
return await operation();
|
|
70
|
+
} catch (error) {
|
|
71
|
+
lastError = error instanceof Error ? error : new Error('Unknown error');
|
|
72
|
+
|
|
73
|
+
if (attempt < maxRetries) {
|
|
74
|
+
const delay = baseDelay * Math.pow(2, attempt);
|
|
75
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
throw lastError || new Error('Operation failed after retries');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Create a standardized error message
|
|
85
|
+
*/
|
|
86
|
+
export function formatError(
|
|
87
|
+
context: string,
|
|
88
|
+
error: unknown
|
|
89
|
+
): string {
|
|
90
|
+
if (error instanceof ChatSuiteError) {
|
|
91
|
+
return `[${context}] ${error.type}: ${error.message}`;
|
|
92
|
+
}
|
|
93
|
+
if (error instanceof Error) {
|
|
94
|
+
return `[${context}] ${error.message}`;
|
|
95
|
+
}
|
|
96
|
+
return `[${context}] Unknown error: ${String(error)}`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Check if an error is retryable
|
|
101
|
+
*/
|
|
102
|
+
export function isRetryableError(error: unknown): boolean {
|
|
103
|
+
if (error instanceof ChatSuiteError) {
|
|
104
|
+
return error.type === ChatSuiteErrorType.PROVIDER_ERROR ||
|
|
105
|
+
error.type === ChatSuiteErrorType.MESSAGE_ERROR;
|
|
106
|
+
}
|
|
107
|
+
if (error instanceof Error) {
|
|
108
|
+
const message = error.message.toLowerCase();
|
|
109
|
+
return message.includes('timeout') ||
|
|
110
|
+
message.includes('network') ||
|
|
111
|
+
message.includes('unavailable');
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Bernier LLC
|
|
3
|
+
|
|
4
|
+
This file is licensed to the client under a limited-use license.
|
|
5
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export * from './error-handling';
|
|
10
|
+
export * from './config-inheritance';
|
|
11
|
+
export * from './user-mapping';
|
|
12
|
+
export * from './message-bridge';
|