chatly-sdk 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/dist/index.js ADDED
@@ -0,0 +1,443 @@
1
+ // src/crypto/e2e.ts
2
+ import { createECDH as createECDH2, createCipheriv, createDecipheriv, randomBytes as randomBytes2, pbkdf2Sync } from "crypto";
3
+
4
+ // src/crypto/utils.ts
5
+ function bufferToBase64(buffer) {
6
+ return buffer.toString("base64");
7
+ }
8
+ function base64ToBuffer(data) {
9
+ return Buffer.from(data, "base64");
10
+ }
11
+
12
+ // src/crypto/keys.ts
13
+ import { createECDH } from "crypto";
14
+ var SUPPORTED_CURVE = "prime256v1";
15
+ function generateIdentityKeyPair() {
16
+ const ecdh = createECDH(SUPPORTED_CURVE);
17
+ ecdh.generateKeys();
18
+ return {
19
+ publicKey: bufferToBase64(ecdh.getPublicKey()),
20
+ privateKey: bufferToBase64(ecdh.getPrivateKey())
21
+ };
22
+ }
23
+
24
+ // src/crypto/e2e.ts
25
+ import { createHash } from "crypto";
26
+ var ALGORITHM = "aes-256-gcm";
27
+ var IV_LENGTH = 12;
28
+ var SALT_LENGTH = 16;
29
+ var KEY_LENGTH = 32;
30
+ var TAG_LENGTH = 16;
31
+ var PBKDF2_ITERATIONS = 1e5;
32
+ function deriveSharedSecret(local, remotePublicKey) {
33
+ const ecdh = createECDH2(SUPPORTED_CURVE);
34
+ ecdh.setPrivateKey(base64ToBuffer(local.privateKey));
35
+ const remotePublicKeyBuffer = base64ToBuffer(remotePublicKey);
36
+ const sharedSecret = ecdh.computeSecret(remotePublicKeyBuffer);
37
+ const a = base64ToBuffer(local.publicKey);
38
+ const b = base64ToBuffer(remotePublicKey);
39
+ const [first, second] = Buffer.compare(a, b) <= 0 ? [a, b] : [b, a];
40
+ const hash = createHash("sha256").update(first).update(second).digest();
41
+ const salt = hash.slice(0, SALT_LENGTH);
42
+ const derivedKey = pbkdf2Sync(sharedSecret, salt, PBKDF2_ITERATIONS, KEY_LENGTH, "sha256");
43
+ return derivedKey;
44
+ }
45
+ function encryptMessage(plaintext, secret) {
46
+ const iv = randomBytes2(IV_LENGTH);
47
+ const cipher = createCipheriv(ALGORITHM, secret, iv);
48
+ let ciphertext = cipher.update(plaintext, "utf8");
49
+ ciphertext = Buffer.concat([ciphertext, cipher.final()]);
50
+ const tag = cipher.getAuthTag();
51
+ const encrypted = Buffer.concat([ciphertext, tag]);
52
+ return {
53
+ ciphertext: bufferToBase64(encrypted),
54
+ iv: bufferToBase64(iv)
55
+ };
56
+ }
57
+ function decryptMessage(ciphertext, iv, secret) {
58
+ const encryptedBuffer = base64ToBuffer(ciphertext);
59
+ const ivBuffer = base64ToBuffer(iv);
60
+ const tag = encryptedBuffer.slice(-TAG_LENGTH);
61
+ const actualCiphertext = encryptedBuffer.slice(0, -TAG_LENGTH);
62
+ const decipher = createDecipheriv(ALGORITHM, secret, ivBuffer);
63
+ decipher.setAuthTag(tag);
64
+ let decrypted = decipher.update(actualCiphertext);
65
+ decrypted = Buffer.concat([decrypted, decipher.final()]);
66
+ return decrypted.toString("utf8");
67
+ }
68
+
69
+ // src/crypto/uuid.ts
70
+ function generateUUID() {
71
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
72
+ return crypto.randomUUID();
73
+ }
74
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
75
+ const bytes = new Uint8Array(16);
76
+ crypto.getRandomValues(bytes);
77
+ bytes[6] = bytes[6] & 15 | 64;
78
+ bytes[8] = bytes[8] & 63 | 128;
79
+ const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
80
+ return [
81
+ hex.slice(0, 8),
82
+ hex.slice(8, 12),
83
+ hex.slice(12, 16),
84
+ hex.slice(16, 20),
85
+ hex.slice(20, 32)
86
+ ].join("-");
87
+ }
88
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
89
+ const r = Math.random() * 16 | 0;
90
+ const v = c === "x" ? r : r & 3 | 8;
91
+ return v.toString(16);
92
+ });
93
+ }
94
+
95
+ // src/chat/ChatSession.ts
96
+ var ChatSession = class {
97
+ constructor(id, userA, userB) {
98
+ this.id = id;
99
+ this.userA = userA;
100
+ this.userB = userB;
101
+ }
102
+ sharedSecret = null;
103
+ ephemeralKeyPair = null;
104
+ /**
105
+ * Initialize the session by deriving the shared secret
106
+ * ECDH is commutative, so we can use either user's keys
107
+ */
108
+ async initialize() {
109
+ const localKeyPair = {
110
+ publicKey: this.userA.publicKey,
111
+ privateKey: this.userA.privateKey
112
+ };
113
+ this.sharedSecret = deriveSharedSecret(localKeyPair, this.userB.publicKey);
114
+ }
115
+ /**
116
+ * Initialize from a specific user's perspective (useful when decrypting)
117
+ */
118
+ async initializeForUser(user) {
119
+ const otherUser = user.id === this.userA.id ? this.userB : this.userA;
120
+ const localKeyPair = {
121
+ publicKey: user.publicKey,
122
+ privateKey: user.privateKey
123
+ };
124
+ this.sharedSecret = deriveSharedSecret(localKeyPair, otherUser.publicKey);
125
+ }
126
+ /**
127
+ * Encrypt a message for this session
128
+ */
129
+ async encrypt(plaintext, senderId) {
130
+ if (!this.sharedSecret) {
131
+ await this.initialize();
132
+ }
133
+ if (!this.sharedSecret) {
134
+ throw new Error("Failed to initialize session");
135
+ }
136
+ const { ciphertext, iv } = encryptMessage(plaintext, this.sharedSecret);
137
+ return {
138
+ id: generateUUID(),
139
+ senderId,
140
+ receiverId: senderId === this.userA.id ? this.userB.id : this.userA.id,
141
+ ciphertext,
142
+ iv,
143
+ timestamp: Date.now(),
144
+ type: "text"
145
+ };
146
+ }
147
+ /**
148
+ * Decrypt a message in this session
149
+ */
150
+ async decrypt(message, user) {
151
+ if (!this.sharedSecret || user.id !== this.userA.id && user.id !== this.userB.id) {
152
+ await this.initializeForUser(user);
153
+ }
154
+ if (!this.sharedSecret) {
155
+ throw new Error("Failed to initialize session");
156
+ }
157
+ return decryptMessage(message.ciphertext, message.iv, this.sharedSecret);
158
+ }
159
+ };
160
+
161
+ // src/crypto/group.ts
162
+ import { pbkdf2Sync as pbkdf2Sync2 } from "crypto";
163
+ var KEY_LENGTH2 = 32;
164
+ var PBKDF2_ITERATIONS2 = 1e5;
165
+ function deriveGroupKey(groupId) {
166
+ const salt = Buffer.from(groupId, "utf8");
167
+ const key = pbkdf2Sync2(groupId, salt, PBKDF2_ITERATIONS2, KEY_LENGTH2, "sha256");
168
+ return {
169
+ groupId,
170
+ key: bufferToBase64(key)
171
+ };
172
+ }
173
+
174
+ // src/chat/GroupSession.ts
175
+ var GroupSession = class {
176
+ constructor(group) {
177
+ this.group = group;
178
+ }
179
+ groupKey = null;
180
+ /**
181
+ * Initialize the session by deriving the group key
182
+ */
183
+ async initialize() {
184
+ const groupKeyData = deriveGroupKey(this.group.id);
185
+ this.groupKey = base64ToBuffer(groupKeyData.key);
186
+ }
187
+ /**
188
+ * Encrypt a message for this group
189
+ */
190
+ async encrypt(plaintext, senderId) {
191
+ if (!this.groupKey) {
192
+ await this.initialize();
193
+ }
194
+ if (!this.groupKey) {
195
+ throw new Error("Failed to initialize group session");
196
+ }
197
+ const { ciphertext, iv } = encryptMessage(plaintext, this.groupKey);
198
+ return {
199
+ id: generateUUID(),
200
+ senderId,
201
+ groupId: this.group.id,
202
+ ciphertext,
203
+ iv,
204
+ timestamp: Date.now(),
205
+ type: "text"
206
+ };
207
+ }
208
+ /**
209
+ * Decrypt a message in this group
210
+ */
211
+ async decrypt(message) {
212
+ if (!this.groupKey) {
213
+ await this.initialize();
214
+ }
215
+ if (!this.groupKey) {
216
+ throw new Error("Failed to initialize group session");
217
+ }
218
+ return decryptMessage(message.ciphertext, message.iv, this.groupKey);
219
+ }
220
+ };
221
+
222
+ // src/stores/memory/userStore.ts
223
+ var InMemoryUserStore = class {
224
+ users = /* @__PURE__ */ new Map();
225
+ async create(user) {
226
+ const stored = { ...user, createdAt: Date.now() };
227
+ this.users.set(stored.id, stored);
228
+ return stored;
229
+ }
230
+ async findById(id) {
231
+ return this.users.get(id);
232
+ }
233
+ async save(user) {
234
+ this.users.set(user.id, user);
235
+ }
236
+ async list() {
237
+ return Array.from(this.users.values());
238
+ }
239
+ };
240
+
241
+ // src/stores/memory/messageStore.ts
242
+ var InMemoryMessageStore = class {
243
+ messages = [];
244
+ async create(message) {
245
+ this.messages.push(message);
246
+ return message;
247
+ }
248
+ async listByUser(userId) {
249
+ return this.messages.filter(
250
+ (msg) => msg.senderId === userId || msg.receiverId === userId
251
+ );
252
+ }
253
+ async listByGroup(groupId) {
254
+ return this.messages.filter((msg) => msg.groupId === groupId);
255
+ }
256
+ };
257
+
258
+ // src/stores/memory/groupStore.ts
259
+ var InMemoryGroupStore = class {
260
+ groups = /* @__PURE__ */ new Map();
261
+ async create(group) {
262
+ this.groups.set(group.id, group);
263
+ return group;
264
+ }
265
+ async findById(id) {
266
+ return this.groups.get(id);
267
+ }
268
+ async list() {
269
+ return Array.from(this.groups.values());
270
+ }
271
+ };
272
+
273
+ // src/transport/memoryTransport.ts
274
+ var InMemoryTransport = class {
275
+ handler;
276
+ connected = false;
277
+ async connect(_userId) {
278
+ this.connected = true;
279
+ }
280
+ async send(message) {
281
+ if (!this.connected) {
282
+ throw new Error("Transport not connected");
283
+ }
284
+ this.handler?.(message);
285
+ }
286
+ onMessage(handler) {
287
+ this.handler = handler;
288
+ }
289
+ };
290
+
291
+ // src/index.ts
292
+ var ChatSDK = class {
293
+ config;
294
+ currentUser = null;
295
+ constructor(config) {
296
+ this.config = config;
297
+ }
298
+ /**
299
+ * Create a new user with generated identity keys
300
+ */
301
+ async createUser(username) {
302
+ const keyPair = generateIdentityKeyPair();
303
+ const user = {
304
+ id: generateUUID(),
305
+ username,
306
+ identityKey: keyPair.publicKey,
307
+ publicKey: keyPair.publicKey,
308
+ privateKey: keyPair.privateKey
309
+ };
310
+ await this.config.userStore.create(user);
311
+ return user;
312
+ }
313
+ /**
314
+ * Import an existing user from stored data
315
+ */
316
+ async importUser(userData) {
317
+ await this.config.userStore.save(userData);
318
+ return userData;
319
+ }
320
+ /**
321
+ * Set the current active user
322
+ */
323
+ setCurrentUser(user) {
324
+ this.currentUser = user;
325
+ if (this.config.transport) {
326
+ this.config.transport.connect(user.id);
327
+ }
328
+ }
329
+ /**
330
+ * Get the current active user
331
+ */
332
+ getCurrentUser() {
333
+ return this.currentUser;
334
+ }
335
+ /**
336
+ * Start a 1:1 chat session between two users
337
+ */
338
+ async startSession(userA, userB) {
339
+ const ids = [userA.id, userB.id].sort();
340
+ const sessionId = `${ids[0]}-${ids[1]}`;
341
+ const session = new ChatSession(sessionId, userA, userB);
342
+ await session.initialize();
343
+ return session;
344
+ }
345
+ /**
346
+ * Create a new group with members
347
+ */
348
+ async createGroup(name, members) {
349
+ if (members.length < 2) {
350
+ throw new Error("Group must have at least 2 members");
351
+ }
352
+ const group = {
353
+ id: generateUUID(),
354
+ name,
355
+ members,
356
+ createdAt: Date.now()
357
+ };
358
+ await this.config.groupStore.create(group);
359
+ const session = new GroupSession(group);
360
+ await session.initialize();
361
+ return session;
362
+ }
363
+ /**
364
+ * Load an existing group by ID
365
+ */
366
+ async loadGroup(id) {
367
+ const group = await this.config.groupStore.findById(id);
368
+ if (!group) {
369
+ throw new Error(`Group not found: ${id}`);
370
+ }
371
+ const session = new GroupSession(group);
372
+ await session.initialize();
373
+ return session;
374
+ }
375
+ /**
376
+ * Send a message in a chat session (1:1 or group)
377
+ */
378
+ async sendMessage(session, plaintext) {
379
+ if (!this.currentUser) {
380
+ throw new Error("No current user set. Call setCurrentUser() first.");
381
+ }
382
+ let message;
383
+ if (session instanceof ChatSession) {
384
+ message = await session.encrypt(plaintext, this.currentUser.id);
385
+ } else {
386
+ message = await session.encrypt(plaintext, this.currentUser.id);
387
+ }
388
+ await this.config.messageStore.create(message);
389
+ if (this.config.transport) {
390
+ await this.config.transport.send(message);
391
+ }
392
+ return message;
393
+ }
394
+ /**
395
+ * Decrypt a message
396
+ */
397
+ async decryptMessage(message, user) {
398
+ if (message.groupId) {
399
+ const group = await this.config.groupStore.findById(message.groupId);
400
+ if (!group) {
401
+ throw new Error(`Group not found: ${message.groupId}`);
402
+ }
403
+ const session = new GroupSession(group);
404
+ await session.initialize();
405
+ return await session.decrypt(message);
406
+ } else {
407
+ const otherUserId = message.senderId === user.id ? message.receiverId : message.senderId;
408
+ if (!otherUserId) {
409
+ throw new Error("Invalid message: missing receiver/sender");
410
+ }
411
+ const otherUser = await this.config.userStore.findById(otherUserId);
412
+ if (!otherUser) {
413
+ throw new Error(`User not found: ${otherUserId}`);
414
+ }
415
+ const ids = [user.id, otherUser.id].sort();
416
+ const sessionId = `${ids[0]}-${ids[1]}`;
417
+ const session = new ChatSession(sessionId, user, otherUser);
418
+ await session.initializeForUser(user);
419
+ return await session.decrypt(message, user);
420
+ }
421
+ }
422
+ /**
423
+ * Get messages for a user
424
+ */
425
+ async getMessagesForUser(userId) {
426
+ return await this.config.messageStore.listByUser(userId);
427
+ }
428
+ /**
429
+ * Get messages for a group
430
+ */
431
+ async getMessagesForGroup(groupId) {
432
+ return await this.config.messageStore.listByGroup(groupId);
433
+ }
434
+ };
435
+ export {
436
+ ChatSDK,
437
+ ChatSession,
438
+ GroupSession,
439
+ InMemoryGroupStore,
440
+ InMemoryMessageStore,
441
+ InMemoryTransport,
442
+ InMemoryUserStore
443
+ };
@@ -0,0 +1,71 @@
1
+ import { ChatSDK } from "../src/index.js";
2
+ import {
3
+ InMemoryUserStore,
4
+ InMemoryMessageStore,
5
+ InMemoryGroupStore,
6
+ } from "../src/index.js";
7
+ import { InMemoryTransport } from "../src/index.js";
8
+
9
+ /**
10
+ * Example: Group Chat with multiple members
11
+ */
12
+ async function main() {
13
+ // Initialize SDK
14
+ const sdk = new ChatSDK({
15
+ userStore: new InMemoryUserStore(),
16
+ messageStore: new InMemoryMessageStore(),
17
+ groupStore: new InMemoryGroupStore(),
18
+ transport: new InMemoryTransport(),
19
+ });
20
+
21
+ // Create users
22
+ console.log("Creating users...");
23
+ const alice = await sdk.createUser("alice");
24
+ const bob = await sdk.createUser("bob");
25
+ const charlie = await sdk.createUser("charlie");
26
+
27
+ console.log(`Alice: ${alice.id}`);
28
+ console.log(`Bob: ${bob.id}`);
29
+ console.log(`Charlie: ${charlie.id}`);
30
+
31
+ // Create a group
32
+ console.log("\nCreating group...");
33
+ const group = await sdk.createGroup("Project Team", [alice, bob, charlie]);
34
+ console.log(`Group created: ${group.group.id} - ${group.group.name}`);
35
+ console.log(`Members: ${group.group.members.map((m) => m.username).join(", ")}`);
36
+
37
+ // Alice sends a message to the group
38
+ console.log("\nAlice sending group message...");
39
+ sdk.setCurrentUser(alice);
40
+ const message1 = await sdk.sendMessage(group, "Hello team! Let's start the project.");
41
+ console.log(`Message sent: ${message1.id}`);
42
+
43
+ // Bob reads the group message
44
+ console.log("\nBob reading group messages...");
45
+ sdk.setCurrentUser(bob);
46
+ const bobMessages = await sdk.getMessagesForGroup(group.group.id);
47
+ for (const msg of bobMessages) {
48
+ const decrypted = await sdk.decryptMessage(msg, bob);
49
+ console.log(`Bob sees: "${decrypted}" from ${msg.senderId}`);
50
+ }
51
+
52
+ // Charlie replies
53
+ console.log("\nCharlie replying...");
54
+ sdk.setCurrentUser(charlie);
55
+ const message2 = await sdk.sendMessage(group, "Sounds good! I'm ready.");
56
+ console.log(`Message sent: ${message2.id}`);
57
+
58
+ // Alice reads all messages
59
+ console.log("\nAlice reading all group messages...");
60
+ sdk.setCurrentUser(alice);
61
+ const allMessages = await sdk.getMessagesForGroup(group.group.id);
62
+ console.log(`Total messages: ${allMessages.length}`);
63
+ for (const msg of allMessages) {
64
+ const decrypted = await sdk.decryptMessage(msg, alice);
65
+ const sender = group.group.members.find((m) => m.id === msg.senderId);
66
+ console.log(`${sender?.username || "Unknown"}: "${decrypted}"`);
67
+ }
68
+ }
69
+
70
+ main().catch(console.error);
71
+
@@ -0,0 +1,72 @@
1
+ import { ChatSDK } from "../src/index.js";
2
+ import {
3
+ InMemoryUserStore,
4
+ InMemoryMessageStore,
5
+ InMemoryGroupStore,
6
+ } from "../src/index.js";
7
+ import { InMemoryTransport } from "../src/index.js";
8
+
9
+ /**
10
+ * Example: 1:1 Chat between two users
11
+ */
12
+ async function main() {
13
+ // Initialize SDK with in-memory stores
14
+ const sdk = new ChatSDK({
15
+ userStore: new InMemoryUserStore(),
16
+ messageStore: new InMemoryMessageStore(),
17
+ groupStore: new InMemoryGroupStore(),
18
+ transport: new InMemoryTransport(),
19
+ });
20
+
21
+ // Create two users
22
+ console.log("Creating users...");
23
+ const alice = await sdk.createUser("alice");
24
+ const bob = await sdk.createUser("bob");
25
+
26
+ console.log(`Alice ID: ${alice.id}`);
27
+ console.log(`Bob ID: ${bob.id}`);
28
+
29
+ // Set Alice as current user
30
+ sdk.setCurrentUser(alice);
31
+
32
+ // Start a chat session between Alice and Bob
33
+ console.log("\nStarting chat session...");
34
+ const session = await sdk.startSession(alice, bob);
35
+
36
+ // Alice sends a message to Bob
37
+ console.log("\nAlice sending message...");
38
+ const message1 = await sdk.sendMessage(session, "Hello Bob! This is encrypted.");
39
+ console.log(`Message sent: ${message1.id}`);
40
+
41
+ // Switch to Bob's perspective
42
+ sdk.setCurrentUser(bob);
43
+
44
+ // Bob receives and decrypts the message
45
+ console.log("\nBob receiving messages...");
46
+ const messages = await sdk.getMessagesForUser(bob.id);
47
+ console.log(`Bob has ${messages.length} message(s)`);
48
+
49
+ for (const msg of messages) {
50
+ const decrypted = await sdk.decryptMessage(msg, bob);
51
+ console.log(`Decrypted: "${decrypted}"`);
52
+ }
53
+
54
+ // Bob replies
55
+ console.log("\nBob replying...");
56
+ const replySession = await sdk.startSession(bob, alice);
57
+ const message2 = await sdk.sendMessage(replySession, "Hi Alice! Got your message.");
58
+ console.log(`Reply sent: ${message2.id}`);
59
+
60
+ // Switch back to Alice
61
+ sdk.setCurrentUser(alice);
62
+ const aliceMessages = await sdk.getMessagesForUser(alice.id);
63
+ console.log(`\nAlice has ${aliceMessages.length} message(s)`);
64
+
65
+ for (const msg of aliceMessages) {
66
+ const decrypted = await sdk.decryptMessage(msg, alice);
67
+ console.log(`Decrypted: "${decrypted}"`);
68
+ }
69
+ }
70
+
71
+ main().catch(console.error);
72
+
@@ -0,0 +1,61 @@
1
+ import { ChatSDK } from "../src/index.js";
2
+ import {
3
+ InMemoryUserStore,
4
+ InMemoryMessageStore,
5
+ InMemoryGroupStore,
6
+ } from "../src/index.js";
7
+ import type { StoredUser } from "../src/index.js";
8
+
9
+ /**
10
+ * Example: Save and load user data
11
+ */
12
+ async function main() {
13
+ // Initialize SDK
14
+ const sdk = new ChatSDK({
15
+ userStore: new InMemoryUserStore(),
16
+ messageStore: new InMemoryMessageStore(),
17
+ groupStore: new InMemoryGroupStore(),
18
+ });
19
+
20
+ // Create a user
21
+ console.log("Creating user...");
22
+ const user = await sdk.createUser("john_doe");
23
+ console.log(`User created: ${user.username} (${user.id})`);
24
+ console.log(`Public key: ${user.publicKey.substring(0, 20)}...`);
25
+
26
+ // Simulate saving user data (in real app, this would be to a database)
27
+ const userStore = new InMemoryUserStore();
28
+ const storedUser: StoredUser = {
29
+ ...user,
30
+ createdAt: Date.now(),
31
+ };
32
+
33
+ // Save user
34
+ await userStore.save(storedUser);
35
+ console.log("\nUser saved to store");
36
+
37
+ // Simulate loading user from storage
38
+ console.log("\nLoading user from store...");
39
+ const loadedUser = await userStore.findById(user.id);
40
+ if (loadedUser) {
41
+ console.log(`User loaded: ${loadedUser.username} (${loadedUser.id})`);
42
+ console.log(`Keys match: ${loadedUser.publicKey === user.publicKey}`);
43
+
44
+ // Import the user into a new SDK instance
45
+ const sdk2 = new ChatSDK({
46
+ userStore: new InMemoryUserStore(),
47
+ messageStore: new InMemoryMessageStore(),
48
+ groupStore: new InMemoryGroupStore(),
49
+ });
50
+
51
+ const importedUser = await sdk2.importUser(loadedUser as StoredUser);
52
+ console.log(`\nUser imported into new SDK instance: ${importedUser.username}`);
53
+ sdk2.setCurrentUser(importedUser);
54
+ console.log("User is now active in SDK2");
55
+ } else {
56
+ console.error("Failed to load user");
57
+ }
58
+ }
59
+
60
+ main().catch(console.error);
61
+
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "chatly-sdk",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsup src/index.ts --dts --format esm",
9
+ "start": "ts-node src/index.ts",
10
+ "test": "ts-node test/crypto.test.ts"
11
+ },
12
+
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+
17
+ "keywords": [
18
+ "chat",
19
+ "sdk",
20
+ "e2e",
21
+ "encryption",
22
+ "messaging",
23
+ "whatsapp"
24
+ ],
25
+ "author": "",
26
+ "license": "ISC",
27
+ "description": "Production-ready end-to-end encrypted chat SDK with WhatsApp-style features",
28
+ "dependencies": {
29
+ "buffer": "^6.0.3"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^24.10.1",
33
+ "ts-node": "^10.9.2",
34
+ "tsup": "^8.0.0",
35
+ "typescript": "^5.9.3"
36
+ }
37
+ }