@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,171 @@
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 {
10
+ Provider,
11
+ ProviderMessage,
12
+ ProviderMessageResult,
13
+ ProviderHealth
14
+ } from '../types';
15
+
16
+ /**
17
+ * Base class for external providers (Slack, Discord, Teams)
18
+ * These are optional peer dependencies and will be implemented when those packages are available
19
+ */
20
+ abstract class ExternalProvider implements Provider {
21
+ public abstract readonly type: 'slack' | 'discord' | 'teams';
22
+ public abstract readonly name: string;
23
+
24
+ protected initialized = false;
25
+
26
+ public async initialize(): Promise<void> {
27
+ throw new Error(
28
+ `${this.name} provider is not implemented yet. ` +
29
+ `Install ${this.name} package to enable this provider.`
30
+ );
31
+ }
32
+
33
+ public isInitialized(): boolean {
34
+ return this.initialized;
35
+ }
36
+
37
+ public async sendMessage(_message: ProviderMessage): Promise<ProviderMessageResult> {
38
+ throw new Error(
39
+ `${this.name} provider is not available. ` +
40
+ `Install ${this.name} package to send messages.`
41
+ );
42
+ }
43
+
44
+ public async getHealth(): Promise<ProviderHealth> {
45
+ return {
46
+ status: 'unknown',
47
+ lastCheck: new Date(),
48
+ errorCount: 0,
49
+ details: {
50
+ error: `${this.name} provider not installed`
51
+ }
52
+ };
53
+ }
54
+
55
+ public async shutdown(): Promise<void> {
56
+ this.initialized = false;
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Slack provider placeholder
62
+ *
63
+ * To enable Slack integration:
64
+ * 1. Install @bernierllc/chat-integration-slack
65
+ * 2. Import SlackProvider from that package
66
+ * 3. Register with the chat suite
67
+ *
68
+ * Example:
69
+ * ```typescript
70
+ * import { SlackProvider } from '@bernierllc/chat-integration-slack';
71
+ *
72
+ * const slackProvider = new SlackProvider({
73
+ * token: process.env.SLACK_BOT_TOKEN,
74
+ * channels: ['#general', '#dev']
75
+ * });
76
+ *
77
+ * await chatSuite.registerProvider(slackProvider);
78
+ * ```
79
+ */
80
+ export class SlackProvider extends ExternalProvider {
81
+ public readonly type = 'slack' as const;
82
+ public readonly name = '@bernierllc/chat-integration-slack';
83
+
84
+ constructor(_config?: Record<string, unknown>) {
85
+ super();
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Discord provider placeholder
91
+ *
92
+ * To enable Discord integration:
93
+ * 1. Install @bernierllc/chat-integration-discord
94
+ * 2. Import DiscordProvider from that package
95
+ * 3. Register with the chat suite
96
+ *
97
+ * Example:
98
+ * ```typescript
99
+ * import { DiscordProvider } from '@bernierllc/chat-integration-discord';
100
+ *
101
+ * const discordProvider = new DiscordProvider({
102
+ * token: process.env.DISCORD_BOT_TOKEN,
103
+ * guilds: ['123456789012345678']
104
+ * });
105
+ *
106
+ * await chatSuite.registerProvider(discordProvider);
107
+ * ```
108
+ */
109
+ export class DiscordProvider extends ExternalProvider {
110
+ public readonly type = 'discord' as const;
111
+ public readonly name = '@bernierllc/chat-integration-discord';
112
+
113
+ constructor(_config?: Record<string, unknown>) {
114
+ super();
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Microsoft Teams provider placeholder
120
+ *
121
+ * To enable Teams integration:
122
+ * 1. Install @bernierllc/chat-integration-teams
123
+ * 2. Import TeamsProvider from that package
124
+ * 3. Register with the chat suite
125
+ *
126
+ * Example:
127
+ * ```typescript
128
+ * import { TeamsProvider } from '@bernierllc/chat-integration-teams';
129
+ *
130
+ * const teamsProvider = new TeamsProvider({
131
+ * tenantId: process.env.TEAMS_TENANT_ID,
132
+ * clientId: process.env.TEAMS_CLIENT_ID,
133
+ * clientSecret: process.env.TEAMS_CLIENT_SECRET
134
+ * });
135
+ *
136
+ * await chatSuite.registerProvider(teamsProvider);
137
+ * ```
138
+ */
139
+ export class TeamsProvider extends ExternalProvider {
140
+ public readonly type = 'teams' as const;
141
+ public readonly name = '@bernierllc/chat-integration-teams';
142
+
143
+ constructor(_config?: Record<string, unknown>) {
144
+ super();
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Check if an external provider package is available
150
+ */
151
+ export function isProviderAvailable(providerName: string): boolean {
152
+ try {
153
+ require.resolve(providerName);
154
+ return true;
155
+ } catch {
156
+ return false;
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Get list of available external providers
162
+ */
163
+ export function getAvailableProviders(): string[] {
164
+ const providers = [
165
+ '@bernierllc/chat-integration-slack',
166
+ '@bernierllc/chat-integration-discord',
167
+ '@bernierllc/chat-integration-teams'
168
+ ];
169
+
170
+ return providers.filter(isProviderAvailable);
171
+ }
@@ -0,0 +1,10 @@
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 './ChatKitProvider';
10
+ export * from './ExternalProviders';
@@ -0,0 +1,112 @@
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 } from '../types';
10
+ import { DEFAULT_SUITE_CONFIG, mergeConfigs, validateConfig } from '../utils/config-inheritance';
11
+ import { ChatSuiteError, ChatSuiteErrorType } from '../utils/error-handling';
12
+
13
+ /**
14
+ * Manages chat suite configuration with validation and inheritance
15
+ */
16
+ export class ConfigManager {
17
+ private config: ChatSuiteConfig;
18
+ private configOverrides: Map<string, unknown> = new Map();
19
+
20
+ constructor(initialConfig?: Partial<ChatSuiteConfig>) {
21
+ this.config = mergeConfigs(DEFAULT_SUITE_CONFIG, initialConfig || {});
22
+ this.validateConfiguration();
23
+ }
24
+
25
+ /**
26
+ * Get the current configuration
27
+ */
28
+ public getConfig(): Readonly<ChatSuiteConfig> {
29
+ return this.config;
30
+ }
31
+
32
+ /**
33
+ * Update configuration
34
+ */
35
+ public updateConfig(updates: Partial<ChatSuiteConfig>): void {
36
+ const newConfig = mergeConfigs(this.config, updates);
37
+ this.validateConfiguration(newConfig);
38
+ this.config = newConfig;
39
+ }
40
+
41
+ /**
42
+ * Get a specific configuration value
43
+ */
44
+ public get<K extends keyof ChatSuiteConfig>(key: K): ChatSuiteConfig[K] {
45
+ return this.config[key];
46
+ }
47
+
48
+ /**
49
+ * Set a configuration override
50
+ */
51
+ public setOverride(key: string, value: unknown): void {
52
+ this.configOverrides.set(key, value);
53
+ }
54
+
55
+ /**
56
+ * Get a configuration override
57
+ */
58
+ public getOverride(key: string): unknown {
59
+ return this.configOverrides.get(key);
60
+ }
61
+
62
+ /**
63
+ * Clear all overrides
64
+ */
65
+ public clearOverrides(): void {
66
+ this.configOverrides.clear();
67
+ }
68
+
69
+ /**
70
+ * Reset to default configuration
71
+ */
72
+ public reset(): void {
73
+ this.config = { ...DEFAULT_SUITE_CONFIG };
74
+ this.configOverrides.clear();
75
+ }
76
+
77
+ /**
78
+ * Validate the current configuration
79
+ */
80
+ private validateConfiguration(config: ChatSuiteConfig = this.config): void {
81
+ const validation = validateConfig(config);
82
+ if (!validation.valid) {
83
+ throw new ChatSuiteError(
84
+ ChatSuiteErrorType.CONFIGURATION_ERROR,
85
+ `Configuration validation failed: ${validation.errors.join(', ')}`
86
+ );
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Export configuration as JSON
92
+ */
93
+ public toJSON(): string {
94
+ return JSON.stringify(this.config, null, 2);
95
+ }
96
+
97
+ /**
98
+ * Load configuration from JSON
99
+ */
100
+ public fromJSON(json: string): void {
101
+ try {
102
+ const parsed = JSON.parse(json) as Partial<ChatSuiteConfig>;
103
+ this.updateConfig(parsed);
104
+ } catch (error) {
105
+ throw new ChatSuiteError(
106
+ ChatSuiteErrorType.CONFIGURATION_ERROR,
107
+ 'Failed to parse configuration JSON',
108
+ error instanceof Error ? error : undefined
109
+ );
110
+ }
111
+ }
112
+ }
@@ -0,0 +1,169 @@
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 { Provider, ProviderType, ChatSuiteHealth } from '../types';
10
+
11
+ /**
12
+ * Health check result
13
+ */
14
+ export interface HealthCheckResult {
15
+ healthy: boolean;
16
+ timestamp: Date;
17
+ details?: Record<string, unknown>;
18
+ }
19
+
20
+ /**
21
+ * Monitors health of all chat suite components
22
+ */
23
+ export class HealthMonitor {
24
+ private providers: Map<ProviderType, Provider> = new Map();
25
+ private lastHealthCheck?: Date;
26
+ private healthCheckInterval?: NodeJS.Timeout;
27
+
28
+ /**
29
+ * Register a provider for health monitoring
30
+ */
31
+ public registerProvider(provider: Provider): void {
32
+ this.providers.set(provider.type, provider);
33
+ }
34
+
35
+ /**
36
+ * Unregister a provider
37
+ */
38
+ public unregisterProvider(providerType: ProviderType): void {
39
+ this.providers.delete(providerType);
40
+ }
41
+
42
+ /**
43
+ * Start periodic health checks
44
+ */
45
+ public startMonitoring(intervalMs: number = 60000): void {
46
+ this.stopMonitoring();
47
+ this.healthCheckInterval = setInterval(() => {
48
+ void this.checkHealth();
49
+ }, intervalMs);
50
+ }
51
+
52
+ /**
53
+ * Stop periodic health checks
54
+ */
55
+ public stopMonitoring(): void {
56
+ if (this.healthCheckInterval) {
57
+ clearInterval(this.healthCheckInterval);
58
+ this.healthCheckInterval = undefined;
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Perform health check on all components
64
+ */
65
+ public async checkHealth(): Promise<ChatSuiteHealth> {
66
+ const timestamp = new Date();
67
+ this.lastHealthCheck = timestamp;
68
+
69
+ const providerStatuses: ChatSuiteHealth['providers'] = {} as ChatSuiteHealth['providers'];
70
+
71
+ // Check each provider
72
+ for (const [type, provider] of this.providers) {
73
+ try {
74
+ const health = await provider.getHealth();
75
+ providerStatuses[type] = {
76
+ status: health.status,
77
+ latency: health.latency,
78
+ errorCount: health.errorCount
79
+ };
80
+ } catch (error) {
81
+ providerStatuses[type] = {
82
+ status: 'unhealthy',
83
+ errorCount: 1
84
+ };
85
+ }
86
+ }
87
+
88
+ // Determine overall status
89
+ const statuses = Object.values(providerStatuses).map(p => p.status);
90
+ let overallStatus: ChatSuiteHealth['status'] = 'healthy';
91
+
92
+ if (statuses.some(s => s === 'unhealthy')) {
93
+ overallStatus = 'unhealthy';
94
+ } else if (statuses.some(s => s === 'degraded')) {
95
+ overallStatus = 'degraded';
96
+ }
97
+
98
+ return {
99
+ status: overallStatus,
100
+ providers: providerStatuses,
101
+ timestamp
102
+ };
103
+ }
104
+
105
+ /**
106
+ * Get health status for a specific provider
107
+ */
108
+ public async checkProviderHealth(providerType: ProviderType): Promise<HealthCheckResult> {
109
+ const provider = this.providers.get(providerType);
110
+ if (!provider) {
111
+ return {
112
+ healthy: false,
113
+ timestamp: new Date(),
114
+ details: { error: 'Provider not registered' }
115
+ };
116
+ }
117
+
118
+ try {
119
+ const health = await provider.getHealth();
120
+ return {
121
+ healthy: health.status === 'healthy',
122
+ timestamp: new Date(),
123
+ details: {
124
+ status: health.status,
125
+ latency: health.latency,
126
+ errorCount: health.errorCount,
127
+ uptime: health.uptime
128
+ }
129
+ };
130
+ } catch (error) {
131
+ return {
132
+ healthy: false,
133
+ timestamp: new Date(),
134
+ details: {
135
+ error: error instanceof Error ? error.message : 'Health check failed'
136
+ }
137
+ };
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Get the last health check timestamp
143
+ */
144
+ public getLastCheckTime(): Date | undefined {
145
+ return this.lastHealthCheck;
146
+ }
147
+
148
+ /**
149
+ * Get all registered providers
150
+ */
151
+ public getRegisteredProviders(): ProviderType[] {
152
+ return Array.from(this.providers.keys());
153
+ }
154
+
155
+ /**
156
+ * Check if monitoring is active
157
+ */
158
+ public isMonitoring(): boolean {
159
+ return this.healthCheckInterval !== undefined;
160
+ }
161
+
162
+ /**
163
+ * Clean up resources
164
+ */
165
+ public shutdown(): void {
166
+ this.stopMonitoring();
167
+ this.providers.clear();
168
+ }
169
+ }