@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,164 @@
|
|
|
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, ProviderMessage, MessageBridgeConfig } from '../types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Bridged message information
|
|
13
|
+
*/
|
|
14
|
+
export interface BridgedMessage {
|
|
15
|
+
originalMessageId: string;
|
|
16
|
+
sourceProvider: ProviderType;
|
|
17
|
+
targetProvider: ProviderType;
|
|
18
|
+
targetMessageId?: string;
|
|
19
|
+
timestamp: Date;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Message bridge for cross-platform synchronization
|
|
24
|
+
*/
|
|
25
|
+
export class MessageBridge {
|
|
26
|
+
private bridgedMessages: Map<string, BridgedMessage[]> = new Map();
|
|
27
|
+
private channelMappings: Map<string, string> = new Map();
|
|
28
|
+
|
|
29
|
+
constructor(private config: MessageBridgeConfig) {
|
|
30
|
+
if (config.channelMappings) {
|
|
31
|
+
this.channelMappings = config.channelMappings;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Check if message should be bridged
|
|
37
|
+
*/
|
|
38
|
+
public shouldBridge(sourceProvider: ProviderType, targetProvider: ProviderType): boolean {
|
|
39
|
+
if (!this.config.enabled) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return this.config.sourceProviders.includes(sourceProvider) &&
|
|
44
|
+
this.config.targetProviders.includes(targetProvider);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Transform message for target provider
|
|
49
|
+
*/
|
|
50
|
+
public transformMessage(
|
|
51
|
+
message: ProviderMessage,
|
|
52
|
+
sourceProvider: ProviderType,
|
|
53
|
+
targetProvider: ProviderType
|
|
54
|
+
): ProviderMessage {
|
|
55
|
+
const transformed: ProviderMessage = {
|
|
56
|
+
...message,
|
|
57
|
+
metadata: {
|
|
58
|
+
...message.metadata,
|
|
59
|
+
bridged: true,
|
|
60
|
+
sourceProvider,
|
|
61
|
+
originalContent: message.content
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Map channel if mapping exists
|
|
66
|
+
if (message.channelId) {
|
|
67
|
+
const mappedChannel = this.getMappedChannel(message.channelId, sourceProvider, targetProvider);
|
|
68
|
+
if (mappedChannel) {
|
|
69
|
+
transformed.channelId = mappedChannel;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Add source provider prefix to content
|
|
74
|
+
transformed.content = `[From ${sourceProvider}] ${message.content}`;
|
|
75
|
+
|
|
76
|
+
return transformed;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Record a bridged message
|
|
81
|
+
*/
|
|
82
|
+
public recordBridgedMessage(bridgedMessage: BridgedMessage): void {
|
|
83
|
+
const existing = this.bridgedMessages.get(bridgedMessage.originalMessageId) || [];
|
|
84
|
+
existing.push(bridgedMessage);
|
|
85
|
+
this.bridgedMessages.set(bridgedMessage.originalMessageId, existing);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Get all bridges for a message
|
|
90
|
+
*/
|
|
91
|
+
public getBridges(originalMessageId: string): BridgedMessage[] {
|
|
92
|
+
return this.bridgedMessages.get(originalMessageId) || [];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Add channel mapping
|
|
97
|
+
*/
|
|
98
|
+
public addChannelMapping(sourceChannel: string, targetChannel: string): void {
|
|
99
|
+
this.channelMappings.set(sourceChannel, targetChannel);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get mapped channel
|
|
104
|
+
*/
|
|
105
|
+
public getMappedChannel(
|
|
106
|
+
sourceChannel: string,
|
|
107
|
+
_sourceProvider: ProviderType,
|
|
108
|
+
_targetProvider: ProviderType
|
|
109
|
+
): string | undefined {
|
|
110
|
+
return this.channelMappings.get(sourceChannel);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Check if reactions should be synced
|
|
115
|
+
*/
|
|
116
|
+
public shouldSyncReactions(): boolean {
|
|
117
|
+
return this.config.syncReactions ?? false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Check if edits should be synced
|
|
122
|
+
*/
|
|
123
|
+
public shouldSyncEdits(): boolean {
|
|
124
|
+
return this.config.syncEdits ?? false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Check if deletions should be synced
|
|
129
|
+
*/
|
|
130
|
+
public shouldSyncDeletions(): boolean {
|
|
131
|
+
return this.config.syncDeletions ?? false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Clear all bridged message records
|
|
136
|
+
*/
|
|
137
|
+
public clear(): void {
|
|
138
|
+
this.bridgedMessages.clear();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Get statistics
|
|
143
|
+
*/
|
|
144
|
+
public getStats(): {
|
|
145
|
+
totalBridged: number;
|
|
146
|
+
bridgesByProvider: Map<ProviderType, number>;
|
|
147
|
+
} {
|
|
148
|
+
const bridgesByProvider = new Map<ProviderType, number>();
|
|
149
|
+
let total = 0;
|
|
150
|
+
|
|
151
|
+
this.bridgedMessages.forEach(bridges => {
|
|
152
|
+
bridges.forEach(bridge => {
|
|
153
|
+
const count = bridgesByProvider.get(bridge.targetProvider) || 0;
|
|
154
|
+
bridgesByProvider.set(bridge.targetProvider, count + 1);
|
|
155
|
+
total++;
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
totalBridged: total,
|
|
161
|
+
bridgesByProvider
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
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 } from '../types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* User identity across platforms
|
|
13
|
+
*/
|
|
14
|
+
export interface UserIdentity {
|
|
15
|
+
unifiedId: string;
|
|
16
|
+
platformIds: Map<ProviderType, string>;
|
|
17
|
+
displayName?: string;
|
|
18
|
+
email?: string;
|
|
19
|
+
metadata?: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* User mapping storage
|
|
24
|
+
*/
|
|
25
|
+
export class UserMapper {
|
|
26
|
+
private identities: Map<string, UserIdentity> = new Map();
|
|
27
|
+
private providerIndex: Map<string, string> = new Map(); // provider:userId -> unifiedId
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Create or update a user identity
|
|
31
|
+
*/
|
|
32
|
+
public mapUser(identity: UserIdentity): void {
|
|
33
|
+
this.identities.set(identity.unifiedId, identity);
|
|
34
|
+
|
|
35
|
+
// Update provider index
|
|
36
|
+
identity.platformIds.forEach((platformUserId, provider) => {
|
|
37
|
+
const key = this.getProviderKey(provider, platformUserId);
|
|
38
|
+
this.providerIndex.set(key, identity.unifiedId);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get unified user ID from platform-specific ID
|
|
44
|
+
*/
|
|
45
|
+
public getUnifiedId(provider: ProviderType, platformUserId: string): string | undefined {
|
|
46
|
+
const key = this.getProviderKey(provider, platformUserId);
|
|
47
|
+
return this.providerIndex.get(key);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get platform-specific user ID from unified ID
|
|
52
|
+
*/
|
|
53
|
+
public getPlatformId(unifiedId: string, provider: ProviderType): string | undefined {
|
|
54
|
+
const identity = this.identities.get(unifiedId);
|
|
55
|
+
return identity?.platformIds.get(provider);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get full user identity
|
|
60
|
+
*/
|
|
61
|
+
public getIdentity(unifiedId: string): UserIdentity | undefined {
|
|
62
|
+
return this.identities.get(unifiedId);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Add platform ID to existing user
|
|
67
|
+
*/
|
|
68
|
+
public addPlatformId(unifiedId: string, provider: ProviderType, platformUserId: string): boolean {
|
|
69
|
+
const identity = this.identities.get(unifiedId);
|
|
70
|
+
if (!identity) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
identity.platformIds.set(provider, platformUserId);
|
|
75
|
+
this.mapUser(identity);
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Remove user identity
|
|
81
|
+
*/
|
|
82
|
+
public removeUser(unifiedId: string): boolean {
|
|
83
|
+
const identity = this.identities.get(unifiedId);
|
|
84
|
+
if (!identity) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Remove from provider index
|
|
89
|
+
identity.platformIds.forEach((platformUserId, provider) => {
|
|
90
|
+
const key = this.getProviderKey(provider, platformUserId);
|
|
91
|
+
this.providerIndex.delete(key);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return this.identities.delete(unifiedId);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get all users
|
|
99
|
+
*/
|
|
100
|
+
public getAllUsers(): UserIdentity[] {
|
|
101
|
+
return Array.from(this.identities.values());
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Clear all mappings
|
|
106
|
+
*/
|
|
107
|
+
public clear(): void {
|
|
108
|
+
this.identities.clear();
|
|
109
|
+
this.providerIndex.clear();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get number of mapped users
|
|
114
|
+
*/
|
|
115
|
+
public size(): number {
|
|
116
|
+
return this.identities.size;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Create provider key for indexing
|
|
121
|
+
*/
|
|
122
|
+
private getProviderKey(provider: ProviderType, platformUserId: string): string {
|
|
123
|
+
return `${provider}:${platformUserId}`;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Create a new unified user ID
|
|
129
|
+
*/
|
|
130
|
+
export function createUnifiedId(): string {
|
|
131
|
+
return `user_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
132
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"types": ["node"],
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"declarationMap": true,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"rootDir": "./src",
|
|
11
|
+
"strict": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"moduleResolution": "node",
|
|
17
|
+
"noImplicitAny": true,
|
|
18
|
+
"strictNullChecks": true,
|
|
19
|
+
"strictFunctionTypes": true,
|
|
20
|
+
"strictBindCallApply": true,
|
|
21
|
+
"strictPropertyInitialization": true,
|
|
22
|
+
"noImplicitThis": true,
|
|
23
|
+
"alwaysStrict": true,
|
|
24
|
+
"noUnusedLocals": true,
|
|
25
|
+
"noUnusedParameters": true,
|
|
26
|
+
"noImplicitReturns": true,
|
|
27
|
+
"noFallthroughCasesInSwitch": true
|
|
28
|
+
},
|
|
29
|
+
"include": ["src/**/*"],
|
|
30
|
+
"exclude": ["node_modules", "dist", "__tests__"]
|
|
31
|
+
}
|