chatly-sdk 0.0.5 → 0.0.7

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 (56) hide show
  1. package/CONTRIBUTING.md +658 -0
  2. package/IMPROVEMENTS.md +402 -0
  3. package/README.md +1538 -164
  4. package/dist/index.d.ts +430 -9
  5. package/dist/index.js +1420 -63
  6. package/examples/01-basic-chat/README.md +61 -0
  7. package/examples/01-basic-chat/index.js +58 -0
  8. package/examples/01-basic-chat/package.json +13 -0
  9. package/examples/02-group-chat/README.md +78 -0
  10. package/examples/02-group-chat/index.js +76 -0
  11. package/examples/02-group-chat/package.json +13 -0
  12. package/examples/03-offline-messaging/README.md +73 -0
  13. package/examples/03-offline-messaging/index.js +80 -0
  14. package/examples/03-offline-messaging/package.json +13 -0
  15. package/examples/04-live-chat/README.md +80 -0
  16. package/examples/04-live-chat/index.js +114 -0
  17. package/examples/04-live-chat/package.json +13 -0
  18. package/examples/05-hybrid-messaging/README.md +71 -0
  19. package/examples/05-hybrid-messaging/index.js +106 -0
  20. package/examples/05-hybrid-messaging/package.json +13 -0
  21. package/examples/06-postgresql-integration/README.md +101 -0
  22. package/examples/06-postgresql-integration/adapters/groupStore.js +73 -0
  23. package/examples/06-postgresql-integration/adapters/messageStore.js +47 -0
  24. package/examples/06-postgresql-integration/adapters/userStore.js +40 -0
  25. package/examples/06-postgresql-integration/index.js +92 -0
  26. package/examples/06-postgresql-integration/package.json +14 -0
  27. package/examples/06-postgresql-integration/schema.sql +58 -0
  28. package/examples/08-customer-support/README.md +70 -0
  29. package/examples/08-customer-support/index.js +104 -0
  30. package/examples/08-customer-support/package.json +13 -0
  31. package/examples/README.md +105 -0
  32. package/jest.config.cjs +28 -0
  33. package/package.json +12 -8
  34. package/src/chat/ChatSession.ts +81 -0
  35. package/src/chat/GroupSession.ts +79 -0
  36. package/src/constants.ts +61 -0
  37. package/src/crypto/e2e.ts +0 -20
  38. package/src/index.ts +525 -63
  39. package/src/models/mediaTypes.ts +58 -0
  40. package/src/models/message.ts +4 -1
  41. package/src/transport/adapters.ts +51 -1
  42. package/src/transport/memoryTransport.ts +75 -13
  43. package/src/transport/websocketClient.ts +269 -21
  44. package/src/transport/websocketServer.ts +26 -26
  45. package/src/utils/errors.ts +97 -0
  46. package/src/utils/logger.ts +96 -0
  47. package/src/utils/mediaUtils.ts +235 -0
  48. package/src/utils/messageQueue.ts +162 -0
  49. package/src/utils/validation.ts +99 -0
  50. package/test/crypto.test.ts +122 -35
  51. package/test/sdk.test.ts +276 -0
  52. package/test/validation.test.ts +64 -0
  53. package/tsconfig.json +11 -10
  54. package/tsconfig.test.json +11 -0
  55. package/src/ChatManager.ts +0 -103
  56. package/src/crypto/keyManager.ts +0 -28
@@ -0,0 +1,71 @@
1
+ # Hybrid Messaging Example
2
+
3
+ Combines real-time and offline messaging (Slack/Instagram-style).
4
+
5
+ ## What You'll Learn
6
+
7
+ - Hybrid online/offline messaging
8
+ - Message queue with automatic retry
9
+ - Graceful degradation
10
+ - Best of both worlds
11
+
12
+ ## Running the Example
13
+
14
+ ```bash
15
+ npm install
16
+ npm start
17
+ ```
18
+
19
+ ## How It Works
20
+
21
+ This example demonstrates **hybrid messaging**:
22
+ - Real-time delivery when online
23
+ - Automatic queueing when offline
24
+ - Messages sent when reconnected
25
+ - Seamless user experience
26
+
27
+ ## Output
28
+
29
+ ```
30
+ šŸ”„ Chatly SDK - Hybrid Messaging Example
31
+ ========================================
32
+
33
+ Initializing hybrid SDK...
34
+ āœ… SDK ready (online + offline support)
35
+
36
+ Creating users...
37
+ āœ… Alice and Bob created
38
+
39
+ Scenario 1: Online messaging (real-time)
40
+ 🟢 Connected
41
+ šŸ“¤ Alice: Hey! (delivered instantly)
42
+ šŸ“Ø Bob received: Hey!
43
+
44
+ Scenario 2: Offline messaging (queued)
45
+ šŸ”“ Simulating disconnect...
46
+ šŸ“¤ Alice: Are you there? (queued)
47
+ šŸ“¤ Alice: I'll wait for you (queued)
48
+ ā³ 2 messages in queue
49
+
50
+ Scenario 3: Reconnection (auto-send)
51
+ 🟢 Reconnected!
52
+ āœ… Sending queued messages...
53
+ šŸ“Ø Bob received: Are you there?
54
+ šŸ“Ø Bob received: I'll wait for you
55
+
56
+ āœ… Hybrid messaging works perfectly!
57
+ ```
58
+
59
+ ## Key Features
60
+
61
+ - **Smart Delivery**: Real-time when online, queued when offline
62
+ - **Automatic Queue**: Messages queued during disconnection
63
+ - **Auto-Retry**: Failed messages retry automatically
64
+ - **Seamless UX**: Users don't need to worry about connection state
65
+
66
+ ## Use Cases
67
+
68
+ - **Social Media DMs** (Instagram, Twitter)
69
+ - **Team Chat** (Slack, Microsoft Teams)
70
+ - **Mobile Apps** (intermittent connectivity)
71
+ - **Progressive Web Apps**
@@ -0,0 +1,106 @@
1
+ import {
2
+ ChatSDK,
3
+ InMemoryUserStore,
4
+ InMemoryMessageStore,
5
+ InMemoryGroupStore,
6
+ MemoryTransport,
7
+ EVENTS,
8
+ ConnectionState,
9
+ LogLevel
10
+ } from 'chatly-sdk';
11
+
12
+ async function main() {
13
+ console.log('šŸ”„ Chatly SDK - Hybrid Messaging Example');
14
+ console.log('========================================\n');
15
+
16
+ // Use MemoryTransport for demo (simulates WebSocket)
17
+ const transport = new MemoryTransport();
18
+
19
+ console.log('Initializing hybrid SDK...');
20
+ const sdk = new ChatSDK({
21
+ userStore: new InMemoryUserStore(),
22
+ messageStore: new InMemoryMessageStore(),
23
+ groupStore: new InMemoryGroupStore(),
24
+ transport, // Hybrid: works online AND offline
25
+ logLevel: LogLevel.NONE,
26
+ });
27
+
28
+ // Track connection state
29
+ let connectionState = ConnectionState.DISCONNECTED;
30
+ sdk.on(EVENTS.CONNECTION_STATE_CHANGED, (state) => {
31
+ connectionState = state;
32
+ const emoji = state === ConnectionState.CONNECTED ? '🟢' : 'šŸ”“';
33
+ console.log(`${emoji} Connection: ${state}`);
34
+ });
35
+
36
+ console.log('āœ… SDK ready (online + offline support)\n');
37
+
38
+ // Create users
39
+ console.log('Creating users...');
40
+ const alice = await sdk.createUser('alice');
41
+ const bob = await sdk.createUser('bob');
42
+ console.log('āœ… Alice and Bob created\n');
43
+
44
+ const session = await sdk.startSession(alice, bob);
45
+
46
+ // Scenario 1: Online messaging (real-time)
47
+ console.log('Scenario 1: Online messaging (real-time)');
48
+ sdk.setCurrentUser(alice);
49
+ await sdk.setCurrentUser(alice); // This connects the transport
50
+
51
+ await new Promise(resolve => setTimeout(resolve, 500));
52
+
53
+ await sdk.sendMessage(session, 'Hey!');
54
+ console.log('šŸ“¤ Alice: Hey! (delivered instantly)');
55
+
56
+ sdk.setCurrentUser(bob);
57
+ const messages1 = await sdk.getMessagesForUser(bob.id);
58
+ const text1 = await sdk.decryptMessage(messages1[0], bob);
59
+ console.log(`šŸ“Ø Bob received: ${text1}\n`);
60
+
61
+ // Scenario 2: Offline messaging (queued)
62
+ console.log('Scenario 2: Offline messaging (queued)');
63
+ console.log('šŸ”“ Simulating disconnect...');
64
+ await sdk.disconnect();
65
+
66
+ sdk.setCurrentUser(alice);
67
+ await sdk.sendMessage(session, 'Are you there?');
68
+ console.log('šŸ“¤ Alice: Are you there? (queued)');
69
+
70
+ await sdk.sendMessage(session, 'I\'ll wait for you');
71
+ console.log('šŸ“¤ Alice: I\'ll wait for you (queued)');
72
+
73
+ const queueStatus = sdk.getQueueStatus();
74
+ console.log(`ā³ ${queueStatus.pending} messages in queue\n`);
75
+
76
+ // Scenario 3: Reconnection (auto-send queued messages)
77
+ console.log('Scenario 3: Reconnection (auto-send)');
78
+ console.log('🟢 Reconnecting...');
79
+
80
+ await sdk.reconnect();
81
+ await new Promise(resolve => setTimeout(resolve, 500));
82
+
83
+ console.log('āœ… Sending queued messages...');
84
+
85
+ sdk.setCurrentUser(bob);
86
+ const messages2 = await sdk.getMessagesForUser(bob.id);
87
+
88
+ // Get the last 2 messages
89
+ const recentMessages = messages2.slice(-2);
90
+ for (const msg of recentMessages) {
91
+ const text = await sdk.decryptMessage(msg, bob);
92
+ console.log(`šŸ“Ø Bob received: ${text}`);
93
+ }
94
+
95
+ console.log();
96
+ console.log('āœ… Hybrid messaging works perfectly!');
97
+ console.log('\nšŸ’” Key Features:');
98
+ console.log(' - Real-time when online');
99
+ console.log(' - Queued when offline');
100
+ console.log(' - Auto-send on reconnect');
101
+ console.log(' - Seamless user experience');
102
+
103
+ await sdk.disconnect();
104
+ }
105
+
106
+ main().catch(console.error);
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "chatly-sdk-hybrid-messaging-example",
3
+ "version": "1.0.0",
4
+ "description": "Hybrid online/offline messaging example using Chatly SDK",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "scripts": {
8
+ "start": "node index.js"
9
+ },
10
+ "dependencies": {
11
+ "chatly-sdk": "^0.0.5"
12
+ }
13
+ }
@@ -0,0 +1,101 @@
1
+ # PostgreSQL Integration Example
2
+
3
+ Complete example of using Chatly SDK with PostgreSQL database.
4
+
5
+ ## What You'll Learn
6
+
7
+ - Implementing custom storage adapters
8
+ - PostgreSQL schema design
9
+ - Database transactions
10
+ - Connection pooling
11
+ - Production-ready setup
12
+
13
+ ## Prerequisites
14
+
15
+ - PostgreSQL installed and running
16
+ - Database created: `chatly`
17
+
18
+ ## Setup
19
+
20
+ ```bash
21
+ # Install dependencies
22
+ npm install
23
+
24
+ # Create database
25
+ createdb chatly
26
+
27
+ # Run schema migration
28
+ psql chatly < schema.sql
29
+
30
+ # Update database credentials in index.js
31
+ # Then run
32
+ npm start
33
+ ```
34
+
35
+ ## Database Schema
36
+
37
+ See [`schema.sql`](./schema.sql) for the complete schema:
38
+ - `users` table
39
+ - `messages` table
40
+ - `groups` table
41
+ - `group_members` table
42
+ - Indexes for performance
43
+
44
+ ## Code Structure
45
+
46
+ ```
47
+ 06-postgresql-integration/
48
+ ā”œā”€ā”€ README.md
49
+ ā”œā”€ā”€ package.json
50
+ ā”œā”€ā”€ schema.sql # Database schema
51
+ ā”œā”€ā”€ adapters/
52
+ │ ā”œā”€ā”€ userStore.js # User storage adapter
53
+ │ ā”œā”€ā”€ messageStore.js # Message storage adapter
54
+ │ └── groupStore.js # Group storage adapter
55
+ └── index.js # Main example
56
+ ```
57
+
58
+ ## Output
59
+
60
+ ```
61
+ šŸ—„ļø Chatly SDK - PostgreSQL Integration
62
+ ======================================
63
+
64
+ Connecting to PostgreSQL...
65
+ āœ… Connected to database: chatly
66
+
67
+ Creating users in database...
68
+ āœ… Alice saved to PostgreSQL
69
+ āœ… Bob saved to PostgreSQL
70
+
71
+ Sending encrypted messages...
72
+ šŸ“¤ Message 1 saved to database
73
+ šŸ“¤ Message 2 saved to database
74
+ šŸ“¤ Message 3 saved to database
75
+
76
+ Retrieving messages from database...
77
+ šŸ“Ø Retrieved 3 messages from PostgreSQL
78
+ šŸ“Ø Decrypted: Hello from PostgreSQL!
79
+ šŸ“Ø Decrypted: Messages are persisted
80
+ šŸ“Ø Decrypted: Even after restart!
81
+
82
+ āœ… PostgreSQL integration works!
83
+ ```
84
+
85
+ ## Production Features
86
+
87
+ - āœ… Connection pooling
88
+ - āœ… Prepared statements (SQL injection protection)
89
+ - āœ… Transactions for data integrity
90
+ - āœ… Indexes for performance
91
+ - āœ… Error handling
92
+ - āœ… Graceful shutdown
93
+
94
+ ## Adapting for Other Databases
95
+
96
+ This pattern works for any SQL database:
97
+ - **MySQL**: Change `pg` to `mysql2`
98
+ - **SQLite**: Use `better-sqlite3`
99
+ - **SQL Server**: Use `mssql`
100
+
101
+ Just implement the same adapter interfaces!
@@ -0,0 +1,73 @@
1
+ export class PostgreSQLGroupStore {
2
+ constructor(pool) {
3
+ this.pool = pool;
4
+ }
5
+
6
+ async create(group) {
7
+ const client = await this.pool.connect();
8
+ try {
9
+ await client.query('BEGIN');
10
+
11
+ // Insert group
12
+ await client.query(
13
+ 'INSERT INTO groups (id, name, shared_secret) VALUES ($1, $2, $3)',
14
+ [group.id, group.name, group.sharedSecret]
15
+ );
16
+
17
+ // Insert members
18
+ for (const userId of group.members) {
19
+ await client.query(
20
+ 'INSERT INTO group_members (group_id, user_id) VALUES ($1, $2)',
21
+ [group.id, userId]
22
+ );
23
+ }
24
+
25
+ await client.query('COMMIT');
26
+ return group;
27
+ } catch (error) {
28
+ await client.query('ROLLBACK');
29
+ throw error;
30
+ } finally {
31
+ client.release();
32
+ }
33
+ }
34
+
35
+ async findById(id) {
36
+ const groupResult = await this.pool.query(
37
+ 'SELECT id, name, shared_secret as "sharedSecret" FROM groups WHERE id = $1',
38
+ [id]
39
+ );
40
+
41
+ if (groupResult.rows.length === 0) return undefined;
42
+
43
+ const membersResult = await this.pool.query(
44
+ 'SELECT user_id FROM group_members WHERE group_id = $1',
45
+ [id]
46
+ );
47
+
48
+ return {
49
+ ...groupResult.rows[0],
50
+ members: membersResult.rows.map(row => row.user_id)
51
+ };
52
+ }
53
+
54
+ async list() {
55
+ const groupsResult = await this.pool.query(
56
+ 'SELECT id, name, shared_secret as "sharedSecret" FROM groups'
57
+ );
58
+
59
+ const groups = [];
60
+ for (const group of groupsResult.rows) {
61
+ const membersResult = await this.pool.query(
62
+ 'SELECT user_id FROM group_members WHERE group_id = $1',
63
+ [group.id]
64
+ );
65
+ groups.push({
66
+ ...group,
67
+ members: membersResult.rows.map(row => row.user_id)
68
+ });
69
+ }
70
+
71
+ return groups;
72
+ }
73
+ }
@@ -0,0 +1,47 @@
1
+ export class PostgreSQLMessageStore {
2
+ constructor(pool) {
3
+ this.pool = pool;
4
+ }
5
+
6
+ async create(message) {
7
+ await this.pool.query(
8
+ `INSERT INTO messages (id, sender_id, receiver_id, group_id, ciphertext, iv, timestamp, status)
9
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
10
+ [
11
+ message.id,
12
+ message.senderId,
13
+ message.receiverId || null,
14
+ message.groupId || null,
15
+ message.ciphertext,
16
+ message.iv,
17
+ message.timestamp,
18
+ message.status || 'pending'
19
+ ]
20
+ );
21
+ return message;
22
+ }
23
+
24
+ async listByUser(userId) {
25
+ const result = await this.pool.query(
26
+ `SELECT id, sender_id as "senderId", receiver_id as "receiverId",
27
+ group_id as "groupId", ciphertext, iv, timestamp, status
28
+ FROM messages
29
+ WHERE receiver_id = $1 OR sender_id = $1
30
+ ORDER BY timestamp ASC`,
31
+ [userId]
32
+ );
33
+ return result.rows;
34
+ }
35
+
36
+ async listByGroup(groupId) {
37
+ const result = await this.pool.query(
38
+ `SELECT id, sender_id as "senderId", receiver_id as "receiverId",
39
+ group_id as "groupId", ciphertext, iv, timestamp, status
40
+ FROM messages
41
+ WHERE group_id = $1
42
+ ORDER BY timestamp ASC`,
43
+ [groupId]
44
+ );
45
+ return result.rows;
46
+ }
47
+ }
@@ -0,0 +1,40 @@
1
+ export class PostgreSQLUserStore {
2
+ constructor(pool) {
3
+ this.pool = pool;
4
+ }
5
+
6
+ async create(user) {
7
+ await this.pool.query(
8
+ `INSERT INTO users (id, username, public_key, private_key)
9
+ VALUES ($1, $2, $3, $4)`,
10
+ [user.id, user.username, user.publicKey, user.privateKey]
11
+ );
12
+ return user;
13
+ }
14
+
15
+ async findById(id) {
16
+ const result = await this.pool.query(
17
+ `SELECT id, username, public_key as "publicKey", private_key as "privateKey"
18
+ FROM users WHERE id = $1`,
19
+ [id]
20
+ );
21
+ return result.rows[0];
22
+ }
23
+
24
+ async save(user) {
25
+ await this.pool.query(
26
+ `UPDATE users
27
+ SET username = $1, public_key = $2
28
+ WHERE id = $3`,
29
+ [user.username, user.publicKey, user.id]
30
+ );
31
+ }
32
+
33
+ async list() {
34
+ const result = await this.pool.query(
35
+ `SELECT id, username, public_key as "publicKey", private_key as "privateKey"
36
+ FROM users`
37
+ );
38
+ return result.rows;
39
+ }
40
+ }
@@ -0,0 +1,92 @@
1
+ import pkg from 'pg';
2
+ const { Pool } = pkg;
3
+ import { ChatSDK, LogLevel } from 'chatly-sdk';
4
+ import { PostgreSQLUserStore } from './adapters/userStore.js';
5
+ import { PostgreSQLMessageStore } from './adapters/messageStore.js';
6
+ import { PostgreSQLGroupStore } from './adapters/groupStore.js';
7
+
8
+ async function main() {
9
+ console.log('šŸ—„ļø Chatly SDK - PostgreSQL Integration');
10
+ console.log('======================================\n');
11
+
12
+ // Create PostgreSQL connection pool
13
+ console.log('Connecting to PostgreSQL...');
14
+ const pool = new Pool({
15
+ host: 'localhost',
16
+ port: 5432,
17
+ database: 'chatly',
18
+ user: 'postgres', // Update with your credentials
19
+ password: 'password', // Update with your credentials
20
+ max: 20,
21
+ min: 5,
22
+ });
23
+
24
+ // Test connection
25
+ try {
26
+ await pool.query('SELECT NOW()');
27
+ console.log('āœ… Connected to database: chatly\n');
28
+ } catch (error) {
29
+ console.error('āŒ Database connection failed:', error.message);
30
+ console.log('\nšŸ’” Make sure PostgreSQL is running and database exists:');
31
+ console.log(' createdb chatly');
32
+ console.log(' psql chatly < schema.sql');
33
+ process.exit(1);
34
+ }
35
+
36
+ // Initialize SDK with PostgreSQL adapters
37
+ const sdk = new ChatSDK({
38
+ userStore: new PostgreSQLUserStore(pool),
39
+ messageStore: new PostgreSQLMessageStore(pool),
40
+ groupStore: new PostgreSQLGroupStore(pool),
41
+ logLevel: LogLevel.NONE,
42
+ });
43
+
44
+ // Create users
45
+ console.log('Creating users in database...');
46
+ const alice = await sdk.createUser('alice-pg');
47
+ const bob = await sdk.createUser('bob-pg');
48
+ console.log('āœ… Alice saved to PostgreSQL');
49
+ console.log('āœ… Bob saved to PostgreSQL\n');
50
+
51
+ // Start session
52
+ const session = await sdk.startSession(alice, bob);
53
+
54
+ // Send messages
55
+ console.log('Sending encrypted messages...');
56
+ sdk.setCurrentUser(alice);
57
+
58
+ await sdk.sendMessage(session, 'Hello from PostgreSQL!');
59
+ console.log('šŸ“¤ Message 1 saved to database');
60
+
61
+ await sdk.sendMessage(session, 'Messages are persisted');
62
+ console.log('šŸ“¤ Message 2 saved to database');
63
+
64
+ await sdk.sendMessage(session, 'Even after restart!');
65
+ console.log('šŸ“¤ Message 3 saved to database\n');
66
+
67
+ // Retrieve messages
68
+ console.log('Retrieving messages from database...');
69
+ sdk.setCurrentUser(bob);
70
+
71
+ const messages = await sdk.getMessagesForUser(bob.id);
72
+ console.log(`šŸ“Ø Retrieved ${messages.length} messages from PostgreSQL`);
73
+
74
+ for (const msg of messages) {
75
+ const plaintext = await sdk.decryptMessage(msg, bob);
76
+ console.log(`šŸ“Ø Decrypted: ${plaintext}`);
77
+ }
78
+ console.log();
79
+
80
+ console.log('āœ… PostgreSQL integration works!');
81
+ console.log('\nšŸ’” Key Features:');
82
+ console.log(' - Messages persisted in PostgreSQL');
83
+ console.log(' - Connection pooling for performance');
84
+ console.log(' - Transactions for data integrity');
85
+ console.log(' - Indexes for fast queries');
86
+
87
+ // Cleanup
88
+ await pool.end();
89
+ console.log('\nšŸ”Œ Database connection closed');
90
+ }
91
+
92
+ main().catch(console.error);
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "chatly-sdk-postgresql-integration",
3
+ "version": "1.0.0",
4
+ "description": "PostgreSQL database integration example for Chatly SDK",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "scripts": {
8
+ "start": "node index.js"
9
+ },
10
+ "dependencies": {
11
+ "chatly-sdk": "^0.0.5",
12
+ "pg": "^8.11.3"
13
+ }
14
+ }
@@ -0,0 +1,58 @@
1
+ -- Chatly SDK PostgreSQL Schema
2
+
3
+ -- Users table
4
+ CREATE TABLE IF NOT EXISTS users (
5
+ id VARCHAR(255) PRIMARY KEY,
6
+ username VARCHAR(50) NOT NULL UNIQUE,
7
+ public_key TEXT NOT NULL,
8
+ private_key TEXT NOT NULL,
9
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
10
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
11
+ );
12
+
13
+ -- Messages table
14
+ CREATE TABLE IF NOT EXISTS messages (
15
+ id VARCHAR(255) PRIMARY KEY,
16
+ sender_id VARCHAR(255) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
17
+ receiver_id VARCHAR(255) REFERENCES users(id) ON DELETE CASCADE,
18
+ group_id VARCHAR(255),
19
+ ciphertext TEXT NOT NULL,
20
+ iv VARCHAR(255) NOT NULL,
21
+ timestamp BIGINT NOT NULL,
22
+ status VARCHAR(20) DEFAULT 'pending',
23
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
24
+ );
25
+
26
+ -- Groups table
27
+ CREATE TABLE IF NOT EXISTS groups (
28
+ id VARCHAR(255) PRIMARY KEY,
29
+ name VARCHAR(100) NOT NULL,
30
+ shared_secret TEXT NOT NULL,
31
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
32
+ );
33
+
34
+ -- Group members table
35
+ CREATE TABLE IF NOT EXISTS group_members (
36
+ group_id VARCHAR(255) NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
37
+ user_id VARCHAR(255) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
38
+ joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
39
+ PRIMARY KEY (group_id, user_id)
40
+ );
41
+
42
+ -- Indexes for performance
43
+ CREATE INDEX IF NOT EXISTS idx_messages_receiver ON messages(receiver_id, timestamp);
44
+ CREATE INDEX IF NOT EXISTS idx_messages_group ON messages(group_id, timestamp);
45
+ CREATE INDEX IF NOT EXISTS idx_messages_sender ON messages(sender_id);
46
+ CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
47
+
48
+ -- Update timestamp trigger
49
+ CREATE OR REPLACE FUNCTION update_updated_at_column()
50
+ RETURNS TRIGGER AS $$
51
+ BEGIN
52
+ NEW.updated_at = CURRENT_TIMESTAMP;
53
+ RETURN NEW;
54
+ END;
55
+ $$ language 'plpgsql';
56
+
57
+ CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users
58
+ FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
@@ -0,0 +1,70 @@
1
+ # Customer Support Chat Example
2
+
3
+ Real-world customer support system with live chat and offline fallback.
4
+
5
+ ## What You'll Learn
6
+
7
+ - Building a customer support chat system
8
+ - Agent availability management
9
+ - Offline message handling
10
+ - Queue management for support tickets
11
+
12
+ ## Running the Example
13
+
14
+ ```bash
15
+ npm install
16
+ npm start
17
+ ```
18
+
19
+ ## How It Works
20
+
21
+ This example simulates a **customer support system**:
22
+ - Customers can send messages anytime
23
+ - Messages queued if no agents online
24
+ - Agents see messages when they come online
25
+ - Real-time chat when both are online
26
+
27
+ ## Output
28
+
29
+ ```
30
+ šŸŽ§ Chatly SDK - Customer Support Example
31
+ ========================================
32
+
33
+ Setting up support system...
34
+ āœ… Support agent created
35
+ āœ… Customer created
36
+
37
+ Scenario 1: Customer sends message (agent offline)
38
+ šŸ“ Customer: I need help with my order
39
+ ā³ Message queued (no agents available)
40
+
41
+ Scenario 2: Agent comes online
42
+ 🟢 Agent online
43
+ šŸ“¬ Agent has 1 pending message
44
+ šŸ“Ø Agent sees: I need help with my order
45
+
46
+ Scenario 3: Live chat (both online)
47
+ šŸ’¬ Real-time conversation started
48
+ šŸ“¤ Agent: Hi! How can I help?
49
+ šŸ“Ø Customer received: Hi! How can I help?
50
+ šŸ“¤ Customer: My order #12345 is delayed
51
+ šŸ“Ø Agent received: My order #12345 is delayed
52
+ šŸ“¤ Agent: Let me check that for you
53
+ šŸ“Ø Customer received: Let me check that for you
54
+
55
+ āœ… Support system works perfectly!
56
+ ```
57
+
58
+ ## Features
59
+
60
+ - **24/7 Availability**: Customers can message anytime
61
+ - **Offline Queue**: Messages queued when agents offline
62
+ - **Real-time**: Live chat when agents available
63
+ - **Message History**: Full conversation history
64
+
65
+ ## Use Cases
66
+
67
+ - **Customer Support** (Zendesk, Intercom-style)
68
+ - **Help Desk Systems**
69
+ - **Live Chat Widgets**
70
+ - **Support Ticketing**