@green-api/greenapi-integration 0.7.0 → 0.7.2

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/README.md CHANGED
@@ -27,7 +27,6 @@ third-party services.
27
27
  - [Developer Guide](#developer-guide)
28
28
  - [Working Example](#working-example)
29
29
  - [Real-World Examples](#real-world-examples)
30
- - [Best Practices](#best-practices)
31
30
 
32
31
  ## Installation
33
32
 
@@ -43,16 +42,16 @@ The foundation of your integration. Handles message & instance management, and p
43
42
 
44
43
  ```typescript
45
44
  abstract class BaseAdapter<TPlatformWebhook, TPlatformMessage, TUser extends BaseUser = BaseUser, TInstance extends Instance = Instance> {
46
- private readonly gaLogger = GreenApiLogger.getInstance(this.constructor.name);
45
+ private readonly gaLogger = GreenApiLogger.getInstance(this.constructor.name);
47
46
 
48
- public constructor(
49
- transformer: MessageTransformer<TPlatformWebhook, TPlatformMessage>,
50
- storage: StorageProvider<TUser, TInstance>,
51
- );
47
+ public constructor(
48
+ transformer: MessageTransformer<TPlatformWebhook, TPlatformMessage>,
49
+ storage: StorageProvider<TUser, TInstance>,
50
+ );
52
51
 
53
- public abstract createPlatformClient(params: any): Promise<any>;
52
+ public abstract createPlatformClient(params: any): Promise<any>;
54
53
 
55
- public abstract sendToPlatform(message: TPlatformMessage, instance: TInstance): Promise<void>;
54
+ public abstract sendToPlatform(message: TPlatformMessage, instance: TInstance): Promise<void>;
56
55
  }
57
56
  ```
58
57
 
@@ -102,28 +101,28 @@ await adapter.updateUser(userEmail, updateData);
102
101
  ```typescript
103
102
  // Platform webhook endpoint
104
103
  app.post('/webhook/platform', async (req, res) => {
105
- try {
106
- await adapter.handlePlatformWebhook(req.body, instanceId);
107
- res.status(200).send();
108
- } catch (error) {
109
- console.error('Failed to handle platform webhook:', error);
110
- res.status(500).send();
111
- }
104
+ try {
105
+ await adapter.handlePlatformWebhook(req.body, instanceId);
106
+ res.status(200).send();
107
+ } catch (error) {
108
+ console.error('Failed to handle platform webhook:', error);
109
+ res.status(500).send();
110
+ }
112
111
  });
113
112
 
114
113
  // GREEN-API webhook endpoint
115
114
  app.post('/webhook/green-api', async (req, res) => {
116
- try {
117
- // Process specific webhook types
118
- await adapter.handleGreenApiWebhook(req.body, [
119
- 'incomingMessageReceived',
120
- 'outgoingMessageStatus'
121
- ]);
122
- res.status(200).send();
123
- } catch (error) {
124
- console.error('Failed to handle GREEN-API webhook:', error);
125
- res.status(500).send();
126
- }
115
+ try {
116
+ // Process specific webhook types
117
+ await adapter.handleGreenApiWebhook(req.body, [
118
+ 'incomingMessageReceived',
119
+ 'outgoingMessageStatus'
120
+ ]);
121
+ res.status(200).send();
122
+ } catch (error) {
123
+ console.error('Failed to handle GREEN-API webhook:', error);
124
+ res.status(500).send();
125
+ }
127
126
  });
128
127
  ```
129
128
 
@@ -133,9 +132,9 @@ Handles message format conversion between GREEN-API and your platform.
133
132
 
134
133
  ```typescript
135
134
  abstract class MessageTransformer<TPlatformWebhook, TPlatformMessage> {
136
- abstract toPlatformMessage(webhook: GreenApiWebhook): TPlatformMessage;
135
+ abstract toPlatformMessage(webhook: GreenApiWebhook): TPlatformMessage;
137
136
 
138
- abstract toGreenApiMessage(message: TPlatformWebhook): Message;
137
+ abstract toGreenApiMessage(message: TPlatformWebhook): Message;
139
138
  }
140
139
  ```
141
140
 
@@ -145,22 +144,22 @@ Interface for data persistence operations.
145
144
 
146
145
  ```typescript
147
146
  abstract class StorageProvider<
148
- TUser extends BaseUser = BaseUser,
149
- TInstance extends Instance = Instance,
150
- TUserCreate extends Record<string, any> = any,
151
- TUserUpdate extends Record<string, any> = any
147
+ TUser extends BaseUser = BaseUser,
148
+ TInstance extends Instance = Instance,
149
+ TUserCreate extends Record<string, any> = any,
150
+ TUserUpdate extends Record<string, any> = any
152
151
  > {
153
- abstract createInstance(instance: Instance): Promise<TInstance>;
152
+ abstract createInstance(instance: Instance): Promise<TInstance>;
154
153
 
155
- abstract getInstance(idInstance: number | bigint): Promise<TInstance | null>;
154
+ abstract getInstance(idInstance: number | bigint): Promise<TInstance | null>;
156
155
 
157
- abstract removeInstance(instanceId: number | bigint): Promise<TInstance>;
156
+ abstract removeInstance(instanceId: number | bigint): Promise<TInstance>;
158
157
 
159
- abstract createUser(data: TUserCreate): Promise<TUser>;
158
+ abstract createUser(data: TUserCreate): Promise<TUser>;
160
159
 
161
- abstract findUser(identifier: string): Promise<TUser | null>;
160
+ abstract findUser(identifier: string): Promise<TUser | null>;
162
161
 
163
- abstract updateUser(identifier: string, data: Partial<TUserUpdate>): Promise<TUser>;
162
+ abstract updateUser(identifier: string, data: Partial<TUserUpdate>): Promise<TUser>;
164
163
  }
165
164
  ```
166
165
 
@@ -170,12 +169,12 @@ Handles webhook authentication for incoming GREEN-API requests.
170
169
 
171
170
  ```typescript
172
171
  abstract class BaseGreenApiAuthGuard<T extends BaseRequest = BaseRequest> {
173
- private readonly gaLogger = GreenApiLogger.getInstance(this.constructor.name);
172
+ private readonly gaLogger = GreenApiLogger.getInstance(this.constructor.name);
174
173
 
175
- constructor(protected storage: StorageProvider);
174
+ constructor(protected storage: StorageProvider);
176
175
 
177
- // Validates incoming webhook requests
178
- async validateRequest(request: T): Promise<boolean>;
176
+ // Validates incoming webhook requests
177
+ async validateRequest(request: T): Promise<boolean>;
179
178
  }
180
179
  ```
181
180
 
@@ -183,24 +182,24 @@ Example implementation of `BaseGreenApiAuthGuard`:
183
182
 
184
183
  ```typescript
185
184
  class YourAuthGuard extends BaseGreenApiAuthGuard<YourRequest> {
186
- constructor(storage: StorageProvider) {
187
- super(storage);
188
- }
185
+ constructor(storage: StorageProvider) {
186
+ super(storage);
187
+ }
189
188
  }
190
189
 
191
190
  // Using with Express
192
191
  app.post('/webhook', async (req, res) => {
193
- const guard = new YourAuthGuard(storage);
194
- try {
195
- await guard.validateRequest(req);
196
- // Process webhook
197
- } catch (error) {
198
- if (error instanceof AuthenticationError) {
199
- res.status(401).json({error: error.message});
200
- return;
201
- }
202
- res.status(500).json({error: 'Internal server error'});
203
- }
192
+ const guard = new YourAuthGuard(storage);
193
+ try {
194
+ await guard.validateRequest(req);
195
+ // Process webhook
196
+ } catch (error) {
197
+ if (error instanceof AuthenticationError) {
198
+ res.status(401).json({error: error.message});
199
+ return;
200
+ }
201
+ res.status(500).json({error: 'Internal server error'});
202
+ }
204
203
  });
205
204
  ```
206
205
 
@@ -221,12 +220,12 @@ logger.fatal("Fatal error", {critical: true});
221
220
 
222
221
  // Error logging with full context
223
222
  try {
224
- await someOperation();
223
+ await someOperation();
225
224
  } catch (error) {
226
- logger.logErrorResponse(error, "Operation failed", {
227
- operationId: "123",
228
- additionalInfo: "some context"
229
- });
225
+ logger.logErrorResponse(error, "Operation failed", {
226
+ operationId: "123",
227
+ additionalInfo: "some context"
228
+ });
230
229
  }
231
230
  ```
232
231
 
@@ -252,20 +251,20 @@ try {
252
251
 
253
252
  ```json
254
253
  {
255
- "timestamp": "30/01/2025, 04:34:49",
256
- "level": "error",
257
- "context": "CoreService",
258
- "message": "Operation failed",
259
- "error": "Failed to process request",
260
- "stack": [
261
- "Error: Failed to process request",
262
- " at CoreService.process (/app/service.js:123:45)",
263
- " at async Router.handle (/app/router.js:67:89)"
264
- ],
265
- "additionalContext": {
266
- "requestId": "abc-123",
267
- "userId": "user_456"
268
- }
254
+ "timestamp": "30/01/2025, 04:34:49",
255
+ "level": "error",
256
+ "context": "CoreService",
257
+ "message": "Operation failed",
258
+ "error": "Failed to process request",
259
+ "stack": [
260
+ "Error: Failed to process request",
261
+ " at CoreService.process (/app/service.js:123:45)",
262
+ " at async Router.handle (/app/router.js:67:89)"
263
+ ],
264
+ "additionalContext": {
265
+ "requestId": "abc-123",
266
+ "userId": "user_456"
267
+ }
269
268
  }
270
269
  ```
271
270
 
@@ -274,12 +273,12 @@ try {
274
273
  ```typescript
275
274
  // Axios error handling
276
275
  try {
277
- await apiRequest();
276
+ await apiRequest();
278
277
  } catch (error) {
279
- logger.logErrorResponse(error, "API Request failed", {
280
- endpoint: "/users",
281
- method: "POST"
282
- });
278
+ logger.logErrorResponse(error, "API Request failed", {
279
+ endpoint: "/users",
280
+ method: "POST"
281
+ });
283
282
  }
284
283
  ```
285
284
 
@@ -307,13 +306,13 @@ The logger is framework-agnostic but can be easily integrated with any framework
307
306
  ```typescript
308
307
  // Express example
309
308
  app.use((err, req, res, next) => {
310
- const logger = GreenApiLogger.getInstance("Express");
311
- logger.error("Request failed", {
312
- path: req.path,
313
- method: req.method,
314
- error: err.message
315
- });
316
- next(err);
309
+ const logger = GreenApiLogger.getInstance("Express");
310
+ logger.error("Request failed", {
311
+ path: req.path,
312
+ method: req.method,
313
+ error: err.message
314
+ });
315
+ next(err);
317
316
  });
318
317
  ```
319
318
 
@@ -327,7 +326,7 @@ For example, when using NestJS, you can disable its built-in logger like this:
327
326
  ```typescript
328
327
  // main.ts
329
328
  const app = await NestFactory.create(AppModule, {
330
- logger: false // Disable NestJS logger
329
+ logger: false // Disable NestJS logger
331
330
  });
332
331
  ```
333
332
 
@@ -357,66 +356,14 @@ gaLogger = GreenApiLogger.getInstance(YourClass.name);
357
356
 
358
357
  - `getInstance(context: string = "Global"): GreenApiLogger`: Get or create logger instance for specified context
359
358
 
360
- #### Best Practices
361
-
362
- 1. **Use Consistent Context Names**
363
-
364
- ```typescript
365
- // In your component/service
366
- private readonly
367
- logger = GreenApiLogger.getInstance(YourService.name);
368
- ```
369
-
370
- 2. **Include Relevant Context**
371
-
372
- ```typescript
373
- logger.info("User action completed", {
374
- userId: user.id,
375
- action: "profile_update",
376
- duration: timeTaken
377
- });
378
- ```
379
-
380
- 3. **Proper Error Handling**
381
-
382
- ```typescript
383
- try {
384
- await complexOperation();
385
- } catch (error) {
386
- logger.logErrorResponse(error, "Complex operation failed", {
387
- operationId: id,
388
- parameters: params
389
- });
390
- }
391
- ```
392
-
393
- 4. **Use Appropriate Log Levels**
394
-
395
- ```typescript
396
- // Debug for detailed information
397
- logger.debug("Processing chunk", {chunkId: 123, size: 1024});
398
-
399
- // Info for general operation
400
- logger.info("User logged in", {userId: 456});
401
-
402
- // Warn for potential issues
403
- logger.warn("High memory usage", {memoryUsage: "85%"});
404
-
405
- // Error for actual problems
406
- logger.error("Database connection failed", {dbHost: "primary"});
407
-
408
- // Fatal for critical issues
409
- logger.fatal("System shutdown required", {reason: "data corruption"});
410
- ```
411
-
412
359
  ### 6. GreenApiClient
413
360
 
414
361
  Direct interface to GREEN-API methods.
415
362
 
416
363
  ```typescript
417
364
  const client = new GreenApiClient({
418
- idInstance: 'your_instance_id',
419
- apiTokenInstance: 'your_token'
365
+ idInstance: 'your_instance_id',
366
+ apiTokenInstance: 'your_token'
420
367
  });
421
368
 
422
369
  // Examples:
@@ -481,17 +428,17 @@ First, define the message types for your platform:
481
428
  ```typescript
482
429
  // types/types.ts
483
430
  export interface YourPlatformWebhook {
484
- id: string;
485
- from: string;
486
- message: string;
487
- timestamp: number;
488
- // Add other platform-specific fields
431
+ id: string;
432
+ from: string;
433
+ message: string;
434
+ timestamp: number;
435
+ // Add other platform-specific fields
489
436
  }
490
437
 
491
438
  export interface YourPlatformMessage {
492
- recipient: string;
493
- content: string;
494
- // Add other platform-specific fields
439
+ recipient: string;
440
+ content: string;
441
+ // Add other platform-specific fields
495
442
  }
496
443
  ```
497
444
 
@@ -505,22 +452,22 @@ import { MessageTransformer, Message, GreenApiWebhook } from '@green-api/greenap
505
452
  import { YourPlatformWebhook, YourPlatformMessage } from '../types/types';
506
453
 
507
454
  export class YourTransformer extends MessageTransformer<YourPlatformWebhook, YourPlatformMessage> {
508
- toPlatformMessage(webhook: GreenApiWebhook): YourPlatformMessage {
509
- // Transform GREEN-API webhook to your platform format
510
- return {
511
- recipient: webhook.senderData.sender,
512
- content: webhook.messageData.textMessageData?.textMessage || '',
513
- };
514
- }
515
-
516
- toGreenApiMessage(message: YourPlatformWebhook): Message {
517
- // Transform your platform webhook to GREEN-API format
518
- return {
519
- type: 'text',
520
- chatId: message.from,
521
- message: message.message,
522
- };
523
- }
455
+ toPlatformMessage(webhook: GreenApiWebhook): YourPlatformMessage {
456
+ // Transform GREEN-API webhook to your platform format
457
+ return {
458
+ recipient: webhook.senderData.sender,
459
+ content: webhook.messageData.textMessageData?.textMessage || '',
460
+ };
461
+ }
462
+
463
+ toGreenApiMessage(message: YourPlatformWebhook): Message {
464
+ // Transform your platform webhook to GREEN-API format
465
+ return {
466
+ type: 'text',
467
+ chatId: message.from,
468
+ message: message.message,
469
+ };
470
+ }
524
471
  }
525
472
  ```
526
473
 
@@ -534,28 +481,28 @@ import { StorageProvider, BaseUser, Instance, Settings } from '@green-api/greena
534
481
  import { PrismaClient } from '@prisma/client'; // Or your database client
535
482
 
536
483
  export class YourStorage extends StorageProvider {
537
- private db: PrismaClient;
538
-
539
- constructor() {
540
- this.db = new PrismaClient();
541
- }
542
-
543
- async findUserByEmail(email: string) {
544
- return this.db.user.findUnique({where: {email}});
545
- }
546
-
547
- async createInstance(instance: Instance) {
548
- return this.db.instance.create({
549
- data: {
550
- idInstance: instance.idInstance,
551
- apiTokenInstance: instance.apiTokenInstance,
552
- userId: instance.userId,
553
- settings: instance.settings || {},
554
- },
555
- });
556
- }
557
-
558
- // Implement other required methods
484
+ private db: PrismaClient;
485
+
486
+ constructor() {
487
+ this.db = new PrismaClient();
488
+ }
489
+
490
+ async findUserByEmail(email: string) {
491
+ return this.db.user.findUnique({where: {email}});
492
+ }
493
+
494
+ async createInstance(instance: Instance) {
495
+ return this.db.instance.create({
496
+ data: {
497
+ idInstance: instance.idInstance,
498
+ apiTokenInstance: instance.apiTokenInstance,
499
+ userId: instance.userId,
500
+ settings: instance.settings || {},
501
+ },
502
+ });
503
+ }
504
+
505
+ // Implement other required methods
559
506
  }
560
507
  ```
561
508
 
@@ -570,17 +517,17 @@ import { YourPlatformClient } from 'your-platform-sdk';
570
517
  import { YourPlatformWebhook, YourPlatformMessage } from '../types/types';
571
518
 
572
519
  export class YourAdapter extends BaseAdapter<YourPlatformWebhook, YourPlatformMessage> {
573
- async createPlatformClient(config: { apiKey: string, apiUrl: string }) {
574
- return new YourPlatformClient({
575
- baseUrl: config.apiUrl,
576
- apiKey: config.apiKey,
577
- });
578
- }
579
-
580
- async sendToPlatform(message: YourPlatformMessage, instance: Instance) {
581
- const client = await this.createPlatformClient(instance.config);
582
- await client.sendMessage(message);
583
- }
520
+ async createPlatformClient(config: { apiKey: string, apiUrl: string }) {
521
+ return new YourPlatformClient({
522
+ baseUrl: config.apiUrl,
523
+ apiKey: config.apiKey,
524
+ });
525
+ }
526
+
527
+ async sendToPlatform(message: YourPlatformMessage, instance: Instance) {
528
+ const client = await this.createPlatformClient(instance.config);
529
+ await client.sendMessage(message);
530
+ }
584
531
  }
585
532
  ```
586
533
 
@@ -601,74 +548,74 @@ const transformer = new YourTransformer();
601
548
  const adapter = new YourAdapter(transformer, storage);
602
549
 
603
550
  class WebhookGuard extends BaseGreenApiAuthGuard {
604
- constructor(storage: StorageProvider) {
605
- super(storage);
606
- }
551
+ constructor(storage: StorageProvider) {
552
+ super(storage);
553
+ }
607
554
  }
608
555
 
609
556
  const guard = new WebhookGuard(storage);
610
557
 
611
558
  // Webhook endpoints
612
559
  router.post('/green-api', async (req, res) => {
613
- try {
614
- // Validate webhook first
615
- await guard.validateRequest(req);
616
-
617
- // Process webhook if validation passed
618
- // As the second parameter, specfify the types of webhooks to be processed (otherwise skipped)
619
- await adapter.handleGreenApiWebhook(req.body, ['incomingMessageReceived']);
620
- res.status(200).json({status: 'ok'});
621
- } catch (error) {
622
- if (error instanceof AuthenticationError) {
623
- res.status(401).json({error: error.message});
624
- return;
625
- }
626
- console.error('Webhook error:', error);
627
- res.status(500).json({error: 'Internal server error'});
628
- }
560
+ try {
561
+ // Validate webhook first
562
+ await guard.validateRequest(req);
563
+
564
+ // Process webhook if validation passed
565
+ // As the second parameter, specfify the types of webhooks to be processed (otherwise skipped)
566
+ await adapter.handleGreenApiWebhook(req.body, ['incomingMessageReceived']);
567
+ res.status(200).json({status: 'ok'});
568
+ } catch (error) {
569
+ if (error instanceof AuthenticationError) {
570
+ res.status(401).json({error: error.message});
571
+ return;
572
+ }
573
+ console.error('Webhook error:', error);
574
+ res.status(500).json({error: 'Internal server error'});
575
+ }
629
576
  });
630
577
 
631
578
  router.post('/platform', async (req, res) => {
632
- try {
633
- const instanceId = req.query.instanceId;
634
- await adapter.handlePlatformWebhook(req.body, instanceId);
635
- res.status(200).json({status: 'ok'});
636
- } catch (error) {
637
- console.error('Platform webhook error:', error);
638
- res.status(500).json({error: 'Internal server error'});
639
- }
579
+ try {
580
+ const instanceId = req.query.instanceId;
581
+ await adapter.handlePlatformWebhook(req.body, instanceId);
582
+ res.status(200).json({status: 'ok'});
583
+ } catch (error) {
584
+ console.error('Platform webhook error:', error);
585
+ res.status(500).json({error: 'Internal server error'});
586
+ }
640
587
  });
641
588
 
642
589
  router.post('/instance', async (req, res) => {
643
- try {
644
- const {idInstance, apiTokenInstance, userEmail} = req.body;
645
-
646
- if (!idInstance || !apiTokenInstance || !userEmail) {
647
- throw new BadRequestError('Required fields missing');
648
- }
649
-
650
- const user = await storage.findUserByEmail(userEmail);
651
- const instance = await adapter.createInstance({
652
- idInstance: Number(idInstance),
653
- apiTokenInstance,
654
- settings: {
655
- webhookUrl: `${process.env.APP_URL}/webhook/green-api`,
656
- webhookUrlToken: `token_${Date.now()}`,
657
- incomingWebhook: 'yes'
658
- },
659
- userId: user.id
660
- });
661
-
662
- res.status(200).json({
663
- status: 'ok',
664
- data: instance,
665
- message: 'Instance created successfully. Please wait 2 minutes for settings to apply.'
666
- });
667
-
668
- } catch (error) {
669
- console.error('Instance creation error:', error);
670
- res.status(500).json({error: 'Failed to create instance'});
671
- }
590
+ try {
591
+ const {idInstance, apiTokenInstance, userEmail} = req.body;
592
+
593
+ if (!idInstance || !apiTokenInstance || !userEmail) {
594
+ throw new BadRequestError('Required fields missing');
595
+ }
596
+
597
+ const user = await storage.findUserByEmail(userEmail);
598
+ const instance = await adapter.createInstance({
599
+ idInstance: Number(idInstance),
600
+ apiTokenInstance,
601
+ settings: {
602
+ webhookUrl: `${process.env.APP_URL}/webhook/green-api`,
603
+ webhookUrlToken: `token_${Date.now()}`,
604
+ incomingWebhook: 'yes'
605
+ },
606
+ userId: user.id
607
+ });
608
+
609
+ res.status(200).json({
610
+ status: 'ok',
611
+ data: instance,
612
+ message: 'Instance created successfully. Please wait 2 minutes for settings to apply.'
613
+ });
614
+
615
+ } catch (error) {
616
+ console.error('Instance creation error:', error);
617
+ res.status(500).json({error: 'Failed to create instance'});
618
+ }
672
619
  });
673
620
 
674
621
  export default router;
@@ -692,25 +639,25 @@ import { YourStorage } from './core/storage';
692
639
  dotenv.config();
693
640
 
694
641
  async function bootstrap() {
695
- // Initialize components
696
- const storage = new YourStorage();
697
- const transformer = new YourTransformer();
698
- const adapter = new YourAdapter(transformer, storage);
642
+ // Initialize components
643
+ const storage = new YourStorage();
644
+ const transformer = new YourTransformer();
645
+ const adapter = new YourAdapter(transformer, storage);
699
646
 
700
- // Create Express application
701
- const app = express();
702
- app.use(bodyParser.json());
647
+ // Create Express application
648
+ const app = express();
649
+ app.use(bodyParser.json());
703
650
 
704
- // Set up webhook routes
705
- app.use('/webhook', webhookRouter);
651
+ // Set up webhook routes
652
+ app.use('/webhook', webhookRouter);
706
653
 
707
- // Start server
708
- const port = process.env.PORT || 3000;
709
- app.listen(port, () => {
710
- console.log(`Server running on port ${port}`);
711
- });
654
+ // Start server
655
+ const port = process.env.PORT || 3000;
656
+ app.listen(port, () => {
657
+ console.log(`Server running on port ${port}`);
658
+ });
712
659
 
713
- console.log('Integration platform ready!');
660
+ console.log('Integration platform ready!');
714
661
  }
715
662
 
716
663
  // Handle errors
@@ -723,19 +670,19 @@ bootstrap();
723
670
 
724
671
  ```json
725
672
  {
726
- "name": "greenapi-integration-yourplatform",
727
- "version": "1.0.0",
728
- "main": "dist/index.js",
729
- "types": "dist/index.d.ts",
730
- "scripts": {
731
- "build": "tsc",
732
- "prepublishOnly": "npm run build"
733
- },
734
- "dependencies": {
735
- "@green-api/greenapi-integration": "^0.4.0",
736
- "express": "^4.18.2"
737
- // other dependencies
738
- }
673
+ "name": "greenapi-integration-yourplatform",
674
+ "version": "1.0.0",
675
+ "main": "dist/index.js",
676
+ "types": "dist/index.d.ts",
677
+ "scripts": {
678
+ "build": "tsc",
679
+ "prepublishOnly": "npm run build"
680
+ },
681
+ "dependencies": {
682
+ "@green-api/greenapi-integration": "^0.4.0",
683
+ "express": "^4.18.2"
684
+ // other dependencies
685
+ }
739
686
  }
740
687
  ```
741
688
 
@@ -800,16 +747,16 @@ examples/
800
747
 
801
748
  ```typescript
802
749
  interface SimplePlatformWebhook {
803
- messageId: string;
804
- from: string;
805
- text: string;
806
- timestamp: number;
750
+ messageId: string;
751
+ from: string;
752
+ text: string;
753
+ timestamp: number;
807
754
  }
808
755
 
809
756
  interface SimplePlatformMessage {
810
- to: string;
811
- content: string;
812
- replyTo?: string;
757
+ to: string;
758
+ content: string;
759
+ replyTo?: string;
813
760
  }
814
761
  ```
815
762
 
@@ -817,36 +764,36 @@ interface SimplePlatformMessage {
817
764
 
818
765
  ```typescript
819
766
  import {
820
- MessageTransformer,
821
- Message,
822
- GreenApiWebhook,
823
- formatPhoneNumber,
824
- IntegrationError,
767
+ MessageTransformer,
768
+ Message,
769
+ GreenApiWebhook,
770
+ formatPhoneNumber,
771
+ IntegrationError,
825
772
  } from "@green-api/greenapi-integration";
826
773
  import { SimplePlatformMessage, SimplePlatformWebhook } from "./types";
827
774
 
828
775
  export class SimpleTransformer extends MessageTransformer<SimplePlatformWebhook, SimplePlatformMessage> {
829
- toPlatformMessage(webhook: GreenApiWebhook): SimplePlatformMessage {
830
- if (webhook.typeWebhook === "incomingMessageReceived") {
831
- if (webhook.messageData.typeMessage !== "extendedTextMessage") {
832
- throw new IntegrationError("Only text messages are supported", "BAD_REQUEST_ERROR", 400);
833
- }
834
-
835
- return {
836
- to: webhook.senderData.sender,
837
- content: webhook.messageData.extendedTextMessageData?.text || "",
838
- };
839
- }
840
- throw new IntegrationError("Only incomingMessageReceived type webhooks are supported", "INTEGRATION_ERROR", 500);
841
- }
842
-
843
- toGreenApiMessage(message: SimplePlatformWebhook): Message {
844
- return {
845
- type: "text",
846
- chatId: formatPhoneNumber(message.from),
847
- message: message.text,
848
- };
849
- }
776
+ toPlatformMessage(webhook: GreenApiWebhook): SimplePlatformMessage {
777
+ if (webhook.typeWebhook === "incomingMessageReceived") {
778
+ if (webhook.messageData.typeMessage !== "extendedTextMessage") {
779
+ throw new IntegrationError("Only text messages are supported", "BAD_REQUEST_ERROR", 400);
780
+ }
781
+
782
+ return {
783
+ to: webhook.senderData.sender,
784
+ content: webhook.messageData.extendedTextMessageData?.text || "",
785
+ };
786
+ }
787
+ throw new IntegrationError("Only incomingMessageReceived type webhooks are supported", "INTEGRATION_ERROR", 500);
788
+ }
789
+
790
+ toGreenApiMessage(message: SimplePlatformWebhook): Message {
791
+ return {
792
+ type: "text",
793
+ chatId: formatPhoneNumber(message.from),
794
+ message: message.text,
795
+ };
796
+ }
850
797
  }
851
798
  ```
852
799
 
@@ -856,44 +803,44 @@ export class SimpleTransformer extends MessageTransformer<SimplePlatformWebhook,
856
803
  import { StorageProvider, BaseUser, Instance } from '@green-api/greenapi-integration';
857
804
 
858
805
  export class SimpleStorage extends StorageProvider {
859
- private users: Map<string, BaseUser> = new Map();
860
- private instances: Map<number, Instance> = new Map();
861
-
862
- async createInstance(instance: Instance, userId: bigint): Promise<Instance> {
863
- this.instances.set(Number(instance.idInstance), {
864
- ...instance,
865
- });
866
- return instance;
867
- }
868
-
869
- async getInstance(idInstance: number): Promise<Instance | null> {
870
- return this.instances.get(idInstance) || null;
871
- }
872
-
873
- async removeInstance(instanceId: number): Promise<Instance> {
874
- const instance = this.instances.get(instanceId);
875
- if (!instance) throw new Error('Instance not found');
876
- this.instances.delete(instanceId);
877
- return instance;
878
- }
879
-
880
- async createUser(data: any): Promise<BaseUser> {
881
- const user = {id: Date.now(), ...data};
882
- this.users.set(data.email, user);
883
- return user;
884
- }
885
-
886
- async findUser(identifier: string): Promise<BaseUser | null> {
887
- return this.users.get(identifier) || null;
888
- }
889
-
890
- async updateUser(identifier: string, data: any): Promise<BaseUser> {
891
- const user = await this.findUser(identifier);
892
- if (!user) throw new Error('User not found');
893
- const updated = {...user, ...data};
894
- this.users.set(identifier, updated);
895
- return updated;
896
- }
806
+ private users: Map<string, BaseUser> = new Map();
807
+ private instances: Map<number, Instance> = new Map();
808
+
809
+ async createInstance(instance: Instance, userId: bigint): Promise<Instance> {
810
+ this.instances.set(Number(instance.idInstance), {
811
+ ...instance,
812
+ });
813
+ return instance;
814
+ }
815
+
816
+ async getInstance(idInstance: number): Promise<Instance | null> {
817
+ return this.instances.get(idInstance) || null;
818
+ }
819
+
820
+ async removeInstance(instanceId: number): Promise<Instance> {
821
+ const instance = this.instances.get(instanceId);
822
+ if (!instance) throw new Error('Instance not found');
823
+ this.instances.delete(instanceId);
824
+ return instance;
825
+ }
826
+
827
+ async createUser(data: any): Promise<BaseUser> {
828
+ const user = {id: Date.now(), ...data};
829
+ this.users.set(data.email, user);
830
+ return user;
831
+ }
832
+
833
+ async findUser(identifier: string): Promise<BaseUser | null> {
834
+ return this.users.get(identifier) || null;
835
+ }
836
+
837
+ async updateUser(identifier: string, data: any): Promise<BaseUser> {
838
+ const user = await this.findUser(identifier);
839
+ if (!user) throw new Error('User not found');
840
+ const updated = {...user, ...data};
841
+ this.users.set(identifier, updated);
842
+ return updated;
843
+ }
897
844
  }
898
845
  ```
899
846
 
@@ -905,38 +852,38 @@ import { SimplePlatformMessage, SimplePlatformWebhook } from "./types";
905
852
  import axios from 'axios';
906
853
 
907
854
  export class SimpleAdapter extends BaseAdapter<SimplePlatformWebhook, SimplePlatformMessage> {
908
- async createPlatformClient(config: { apiKey: string, apiUrl: string }) {
909
- return axios.create({
910
- baseURL: config.apiUrl,
911
- headers: {
912
- 'Authorization': `Bearer ${config.apiKey}`,
913
- 'Content-Type': 'application/json'
914
- }
915
- });
916
- }
917
-
918
- async sendToPlatform(message: SimplePlatformMessage, instance: Instance): Promise<void> {
919
- // In a real implementation, we would send to the platform
920
- // For demo, we'll just log and simulate a response
921
- console.log('Platform received message:', message);
922
-
923
- // Simulate platform processing and responding
924
- setTimeout(() => {
925
- console.log('Platform processing complete, sending response...');
926
- this.simulatePlatformResponse(message, instance.idInstance);
927
- }, 1000);
928
- }
929
-
930
- private async simulatePlatformResponse(originalMessage: SimplePlatformMessage, idInstance: number | bigint) {
931
- const platformWebhook: SimplePlatformWebhook = {
932
- messageId: `resp_${Date.now()}`,
933
- from: originalMessage.to.replace('@c.us', ''),
934
- text: `Thanks for your message: "${originalMessage.content}". This is an automated response.`,
935
- timestamp: Date.now()
936
- };
937
-
938
- await this.handlePlatformWebhook(platformWebhook, idInstance);
939
- }
855
+ async createPlatformClient(config: { apiKey: string, apiUrl: string }) {
856
+ return axios.create({
857
+ baseURL: config.apiUrl,
858
+ headers: {
859
+ 'Authorization': `Bearer ${config.apiKey}`,
860
+ 'Content-Type': 'application/json'
861
+ }
862
+ });
863
+ }
864
+
865
+ async sendToPlatform(message: SimplePlatformMessage, instance: Instance): Promise<void> {
866
+ // In a real implementation, we would send to the platform
867
+ // For demo, we'll just log and simulate a response
868
+ console.log('Platform received message:', message);
869
+
870
+ // Simulate platform processing and responding
871
+ setTimeout(() => {
872
+ console.log('Platform processing complete, sending response...');
873
+ this.simulatePlatformResponse(message, instance.idInstance);
874
+ }, 1000);
875
+ }
876
+
877
+ private async simulatePlatformResponse(originalMessage: SimplePlatformMessage, idInstance: number | bigint) {
878
+ const platformWebhook: SimplePlatformWebhook = {
879
+ messageId: `resp_${Date.now()}`,
880
+ from: originalMessage.to.replace('@c.us', ''),
881
+ text: `Thanks for your message: "${originalMessage.content}". This is an automated response.`,
882
+ timestamp: Date.now()
883
+ };
884
+
885
+ await this.handlePlatformWebhook(platformWebhook, idInstance);
886
+ }
940
887
  }
941
888
  ```
942
889
 
@@ -954,92 +901,80 @@ import * as dotenv from "dotenv";
954
901
  dotenv.config();
955
902
 
956
903
  async function main() {
957
- // Initialize components
958
- const transformer = new SimpleTransformer();
959
- const storage = new SimpleStorage();
960
- const adapter = new SimpleAdapter(transformer, storage);
961
-
962
- // Configuration for both instances
963
- const visitorInstance = {
964
- idInstance: Number(process.env.VISITOR_ID_INSTANCE),
965
- apiTokenInstance: process.env.VISITOR_API_TOKEN!,
966
- };
967
-
968
- const agentInstance = {
969
- idInstance: Number(process.env.AGENT_ID_INSTANCE),
970
- apiTokenInstance: process.env.AGENT_API_TOKEN!,
971
- };
972
- console.log(visitorInstance, agentInstance);
973
-
974
- // Create visitor's GREEN-API client (for sending initial message)
975
- const visitorClient = new GreenApiClient(visitorInstance);
976
-
977
- // Set up agent instance
978
- console.log("Setting up agent instance...");
979
- const user = await adapter.createUser("agent@example.com", {
980
- email: "agent@example.com",
981
- name: "Agent",
982
- });
983
-
984
- const instance = await adapter.createInstance({
985
- idInstance: agentInstance.idInstance, apiTokenInstance: agentInstance.apiTokenInstance, settings: {
986
- webhookUrl: process.env.WEBHOOK_URL + "/webhook/green-api",
987
- webhookUrlToken: "your-secure-token",
988
- incomingWebhook: "yes",
989
- },
990
- }, user.email);
991
-
992
- console.log("Waiting 2 minutes for settings to apply...");
993
- await new Promise(resolve => setTimeout(resolve, 120000));
994
- console.log("Instance ready!");
995
-
996
- // Set up webhook server
997
- const app = express();
998
- app.use(bodyParser.json());
999
-
1000
- // Handle GREEN-API webhooks
1001
- app.post("/webhook/green-api", async (req, res) => {
1002
- try {
1003
- console.log("Received webhook from GREEN-API:", req.body);
1004
- await adapter.handleGreenApiWebhook(req.body, ["incomingMessageReceived"]);
1005
- res.status(200).json({status: "ok"});
1006
- } catch (error) {
1007
- console.error("Error handling webhook:", error);
1008
- res.status(500).json({error: "Internal server error"});
1009
- }
1010
- });
1011
-
1012
- // Start the server
1013
- const port = Number(process.env.PORT) || 3000;
1014
- app.listen(port, () => {
1015
- console.log(`Webhook server listening on port ${port}`);
1016
- });
1017
-
1018
- // Send initial message from visitor
1019
- console.log("Sending initial message from visitor...");
1020
- await visitorClient.sendMessage({
1021
- chatId: formatPhoneNumber(process.env.AGENT_PHONE_NUMBER!),
1022
- message: "Hello! This is a test message from a visitor.",
1023
- });
1024
-
1025
- console.log("Initial message sent! Check the agent WhatsApp app to see the response.");
904
+ // Initialize components
905
+ const transformer = new SimpleTransformer();
906
+ const storage = new SimpleStorage();
907
+ const adapter = new SimpleAdapter(transformer, storage);
908
+
909
+ // Configuration for both instances
910
+ const visitorInstance = {
911
+ idInstance: Number(process.env.VISITOR_ID_INSTANCE),
912
+ apiTokenInstance: process.env.VISITOR_API_TOKEN!,
913
+ };
914
+
915
+ const agentInstance = {
916
+ idInstance: Number(process.env.AGENT_ID_INSTANCE),
917
+ apiTokenInstance: process.env.AGENT_API_TOKEN!,
918
+ };
919
+ console.log(visitorInstance, agentInstance);
920
+
921
+ // Create visitor's GREEN-API client (for sending initial message)
922
+ const visitorClient = new GreenApiClient(visitorInstance);
923
+
924
+ // Set up agent instance
925
+ console.log("Setting up agent instance...");
926
+ const user = await adapter.createUser("agent@example.com", {
927
+ email: "agent@example.com",
928
+ name: "Agent",
929
+ });
930
+
931
+ const instance = await adapter.createInstance({
932
+ idInstance: agentInstance.idInstance, apiTokenInstance: agentInstance.apiTokenInstance, settings: {
933
+ webhookUrl: process.env.WEBHOOK_URL + "/webhook/green-api",
934
+ webhookUrlToken: "your-secure-token",
935
+ incomingWebhook: "yes",
936
+ },
937
+ }, user.email);
938
+
939
+ console.log("Waiting 2 minutes for settings to apply...");
940
+ await new Promise(resolve => setTimeout(resolve, 120000));
941
+ console.log("Instance ready!");
942
+
943
+ // Set up webhook server
944
+ const app = express();
945
+ app.use(bodyParser.json());
946
+
947
+ // Handle GREEN-API webhooks
948
+ app.post("/webhook/green-api", async (req, res) => {
949
+ try {
950
+ console.log("Received webhook from GREEN-API:", req.body);
951
+ await adapter.handleGreenApiWebhook(req.body, ["incomingMessageReceived"]);
952
+ res.status(200).json({status: "ok"});
953
+ } catch (error) {
954
+ console.error("Error handling webhook:", error);
955
+ res.status(500).json({error: "Internal server error"});
956
+ }
957
+ });
958
+
959
+ // Start the server
960
+ const port = Number(process.env.PORT) || 3000;
961
+ app.listen(port, () => {
962
+ console.log(`Webhook server listening on port ${port}`);
963
+ });
964
+
965
+ // Send initial message from visitor
966
+ console.log("Sending initial message from visitor...");
967
+ await visitorClient.sendMessage({
968
+ chatId: formatPhoneNumber(process.env.AGENT_PHONE_NUMBER!),
969
+ message: "Hello! This is a test message from a visitor.",
970
+ });
971
+
972
+ console.log("Initial message sent! Check the agent WhatsApp app to see the response.");
1026
973
  }
1027
974
 
1028
975
  main().catch(console.error);
1029
976
  ```
1030
977
 
1031
- ### .env
1032
-
1033
- ```env
1034
- VISITOR_ID_INSTANCE=your_visitor_instance_id
1035
- VISITOR_API_TOKEN=your_visitor_instance_token
1036
- AGENT_ID_INSTANCE=your_agent_instance_id
1037
- AGENT_API_TOKEN=your_agent_instance_token
1038
- AGENT_PHONE_NUMBER=your_agent_phone_number
1039
- WEBHOOK_URL=your_webhook_url
1040
- PORT=3000
1041
- ```
1042
-
1043
978
  ## Real-World Examples
1044
979
 
1045
980
  For complete real-world integration examples, check out:
@@ -1066,10 +1001,10 @@ isValidSettingValue('webhookUrl', 'https://example.com') // Returns true
1066
1001
 
1067
1002
  // Clean settings
1068
1003
  const input = {
1069
- webhookUrl: 'https://example.com',
1070
- outgoingWebhook: 'yes',
1071
- invalidKey: 'value',
1072
- delaySendMessagesMilliseconds: 'invalid'
1004
+ webhookUrl: 'https://example.com',
1005
+ outgoingWebhook: 'yes',
1006
+ invalidKey: 'value',
1007
+ delaySendMessagesMilliseconds: 'invalid'
1073
1008
  }
1074
1009
  validateAndCleanSettings(input) // Returns { webhookUrl: 'https://example.com', outgoingWebhook: 'yes' }
1075
1010
  ```