@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.
Files changed (105) hide show
  1. package/.eslintrc.js +26 -0
  2. package/README.md +542 -0
  3. package/__tests__/integration/ChatSuite.test.ts +235 -0
  4. package/__tests__/unit/ConfigManager.test.ts +122 -0
  5. package/__tests__/unit/MessageOrchestrator.test.ts +223 -0
  6. package/__tests__/unit/UserManager.test.ts +208 -0
  7. package/dist/ChatSuite.d.ts +76 -0
  8. package/dist/ChatSuite.d.ts.map +1 -0
  9. package/dist/ChatSuite.js +273 -0
  10. package/dist/index.d.ts +7 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +37 -0
  13. package/dist/neverhub/discovery.d.ts +40 -0
  14. package/dist/neverhub/discovery.d.ts.map +1 -0
  15. package/dist/neverhub/discovery.js +106 -0
  16. package/dist/neverhub/event-handlers.d.ts +38 -0
  17. package/dist/neverhub/event-handlers.d.ts.map +1 -0
  18. package/dist/neverhub/event-handlers.js +125 -0
  19. package/dist/neverhub/index.d.ts +4 -0
  20. package/dist/neverhub/index.d.ts.map +1 -0
  21. package/dist/neverhub/index.js +26 -0
  22. package/dist/neverhub/service-registration.d.ts +29 -0
  23. package/dist/neverhub/service-registration.d.ts.map +1 -0
  24. package/dist/neverhub/service-registration.js +66 -0
  25. package/dist/providers/ChatKitProvider.d.ts +53 -0
  26. package/dist/providers/ChatKitProvider.d.ts.map +1 -0
  27. package/dist/providers/ChatKitProvider.js +167 -0
  28. package/dist/providers/ExternalProviders.d.ts +101 -0
  29. package/dist/providers/ExternalProviders.d.ts.map +1 -0
  30. package/dist/providers/ExternalProviders.js +153 -0
  31. package/dist/providers/index.d.ts +3 -0
  32. package/dist/providers/index.d.ts.map +1 -0
  33. package/dist/providers/index.js +25 -0
  34. package/dist/services/ConfigManager.d.ts +50 -0
  35. package/dist/services/ConfigManager.d.ts.map +1 -0
  36. package/dist/services/ConfigManager.js +95 -0
  37. package/dist/services/HealthMonitor.d.ts +58 -0
  38. package/dist/services/HealthMonitor.d.ts.map +1 -0
  39. package/dist/services/HealthMonitor.js +148 -0
  40. package/dist/services/MessageOrchestrator.d.ts +63 -0
  41. package/dist/services/MessageOrchestrator.d.ts.map +1 -0
  42. package/dist/services/MessageOrchestrator.js +212 -0
  43. package/dist/services/ProviderManager.d.ts +83 -0
  44. package/dist/services/ProviderManager.d.ts.map +1 -0
  45. package/dist/services/ProviderManager.js +204 -0
  46. package/dist/services/UserManager.d.ts +61 -0
  47. package/dist/services/UserManager.d.ts.map +1 -0
  48. package/dist/services/UserManager.js +141 -0
  49. package/dist/services/index.d.ts +6 -0
  50. package/dist/services/index.d.ts.map +1 -0
  51. package/dist/services/index.js +28 -0
  52. package/dist/types/index.d.ts +4 -0
  53. package/dist/types/index.d.ts.map +1 -0
  54. package/dist/types/index.js +26 -0
  55. package/dist/types/message-types.d.ts +80 -0
  56. package/dist/types/message-types.d.ts.map +1 -0
  57. package/dist/types/message-types.js +32 -0
  58. package/dist/types/provider-types.d.ts +96 -0
  59. package/dist/types/provider-types.d.ts.map +1 -0
  60. package/dist/types/provider-types.js +9 -0
  61. package/dist/types/suite-types.d.ts +101 -0
  62. package/dist/types/suite-types.d.ts.map +1 -0
  63. package/dist/types/suite-types.js +9 -0
  64. package/dist/utils/config-inheritance.d.ts +24 -0
  65. package/dist/utils/config-inheritance.d.ts.map +1 -0
  66. package/dist/utils/config-inheritance.js +167 -0
  67. package/dist/utils/error-handling.d.ts +37 -0
  68. package/dist/utils/error-handling.d.ts.map +1 -0
  69. package/dist/utils/error-handling.js +102 -0
  70. package/dist/utils/index.d.ts +5 -0
  71. package/dist/utils/index.d.ts.map +1 -0
  72. package/dist/utils/index.js +27 -0
  73. package/dist/utils/message-bridge.d.ts +68 -0
  74. package/dist/utils/message-bridge.d.ts.map +1 -0
  75. package/dist/utils/message-bridge.js +126 -0
  76. package/dist/utils/user-mapping.d.ts +63 -0
  77. package/dist/utils/user-mapping.d.ts.map +1 -0
  78. package/dist/utils/user-mapping.js +110 -0
  79. package/jest.config.cjs +30 -0
  80. package/package.json +67 -0
  81. package/src/ChatSuite.ts +347 -0
  82. package/src/index.ts +25 -0
  83. package/src/neverhub/discovery.ts +137 -0
  84. package/src/neverhub/event-handlers.ts +141 -0
  85. package/src/neverhub/index.ts +11 -0
  86. package/src/neverhub/service-registration.ts +89 -0
  87. package/src/providers/ChatKitProvider.ts +193 -0
  88. package/src/providers/ExternalProviders.ts +171 -0
  89. package/src/providers/index.ts +10 -0
  90. package/src/services/ConfigManager.ts +112 -0
  91. package/src/services/HealthMonitor.ts +169 -0
  92. package/src/services/MessageOrchestrator.ts +271 -0
  93. package/src/services/ProviderManager.ts +247 -0
  94. package/src/services/UserManager.ts +176 -0
  95. package/src/services/index.ts +13 -0
  96. package/src/types/index.ts +11 -0
  97. package/src/types/message-types.ts +94 -0
  98. package/src/types/provider-types.ts +116 -0
  99. package/src/types/suite-types.ts +117 -0
  100. package/src/utils/config-inheritance.ts +189 -0
  101. package/src/utils/error-handling.ts +114 -0
  102. package/src/utils/index.ts +12 -0
  103. package/src/utils/message-bridge.ts +164 -0
  104. package/src/utils/user-mapping.ts +132 -0
  105. 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';