@app-connect/core 1.7.1 → 1.7.4
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 +1 -1
- package/connector/proxy/engine.js +163 -0
- package/connector/proxy/index.js +492 -0
- package/connector/registry.js +11 -8
- package/handlers/admin.js +12 -3
- package/handlers/auth.js +20 -10
- package/handlers/contact.js +26 -9
- package/handlers/disposition.js +19 -6
- package/handlers/log.js +62 -18
- package/index.js +48 -2
- package/lib/callLogComposer.js +198 -12
- package/lib/oauth.js +0 -1
- package/models/dynamo/connectorSchema.js +146 -0
- package/package.json +67 -67
- package/releaseNotes.json +72 -0
- package/test/connector/proxy/engine.test.js +93 -0
- package/test/connector/proxy/index.test.js +279 -0
- package/test/connector/proxy/sample.json +161 -0
- package/test/{adapter → connector}/registry.test.js +4 -4
- package/test/handlers/auth.test.js +3 -1
package/lib/callLogComposer.js
CHANGED
|
@@ -41,6 +41,11 @@ async function composeCallLog(params) {
|
|
|
41
41
|
startTime,
|
|
42
42
|
duration,
|
|
43
43
|
result,
|
|
44
|
+
ringSenseTranscript,
|
|
45
|
+
ringSenseSummary,
|
|
46
|
+
ringSenseAIScore,
|
|
47
|
+
ringSenseBulletedSummary,
|
|
48
|
+
ringSenseLink,
|
|
44
49
|
platform
|
|
45
50
|
} = params;
|
|
46
51
|
|
|
@@ -62,14 +67,18 @@ async function composeCallLog(params) {
|
|
|
62
67
|
}
|
|
63
68
|
|
|
64
69
|
if (userSettings?.addRingCentralUserName?.value) {
|
|
65
|
-
const ringcentralUsername = (callLog.direction === 'Inbound' ? callLog?.to?.name : callLog?.from?.name) ??
|
|
66
|
-
|
|
70
|
+
const ringcentralUsername = (callLog.direction === 'Inbound' ? callLog?.to?.name : callLog?.from?.name) ?? null;
|
|
71
|
+
if (ringcentralUsername) {
|
|
72
|
+
body = upsertRingCentralUserName({ body, userName: ringcentralUsername, logFormat });
|
|
73
|
+
}
|
|
67
74
|
}
|
|
68
75
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
if (userSettings?.addRingCentralNumber?.value ?? false) {
|
|
77
|
+
const ringcentralNumber = callLog.direction === 'Inbound' ? callLog?.to?.phoneNumber : callLog?.from?.phoneNumber;
|
|
78
|
+
if (ringcentralNumber) {
|
|
79
|
+
const ringcentralExtensionNumber = callLog.direction === 'Inbound' ? callLog?.from?.extensionNumber : callLog?.to?.extensionNumber;
|
|
80
|
+
body = upsertRingCentralNumberAndExtension({ body, number: ringcentralNumber, extension: ringcentralExtensionNumber ?? '', logFormat });
|
|
81
|
+
}
|
|
73
82
|
}
|
|
74
83
|
|
|
75
84
|
if (subject && (userSettings?.addCallLogSubject?.value ?? true)) {
|
|
@@ -115,6 +124,26 @@ async function composeCallLog(params) {
|
|
|
115
124
|
body = upsertTranscript({ body, transcript, logFormat });
|
|
116
125
|
}
|
|
117
126
|
|
|
127
|
+
if (ringSenseTranscript && (userSettings?.addCallLogRingSenseRecordingTranscript?.value ?? true)) {
|
|
128
|
+
body = upsertRingSenseTranscript({ body, transcript: ringSenseTranscript, logFormat });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (ringSenseSummary && (userSettings?.addCallLogRingSenseRecordingSummary?.value ?? true)) {
|
|
132
|
+
body = upsertRingSenseSummary({ body, summary: ringSenseSummary, logFormat });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (ringSenseAIScore && (userSettings?.addCallLogRingSenseRecordingAIScore?.value ?? true)) {
|
|
136
|
+
body = upsertRingSenseAIScore({ body, score: ringSenseAIScore, logFormat });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (ringSenseBulletedSummary && (userSettings?.addCallLogRingSenseRecordingBulletedSummary?.value ?? true)) {
|
|
140
|
+
body = upsertRingSenseBulletedSummary({ body, summary: ringSenseBulletedSummary, logFormat });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (ringSenseLink && (userSettings?.addCallLogRingSenseRecordingLink?.value ?? true)) {
|
|
144
|
+
body = upsertRingSenseLink({ body, link: ringSenseLink, logFormat });
|
|
145
|
+
}
|
|
146
|
+
|
|
118
147
|
if (callLog?.legs && (userSettings?.addCallLogLegs?.value ?? true)) {
|
|
119
148
|
body = upsertLegs({ body, legs: callLog.legs, logFormat });
|
|
120
149
|
}
|
|
@@ -382,7 +411,7 @@ function upsertCallDuration({ body, duration, logFormat }) {
|
|
|
382
411
|
// More flexible regex that handles both with and without newlines
|
|
383
412
|
const durationRegex = /- Duration: ([^\n-]+)(?=\n-|\n|$)/;
|
|
384
413
|
if (durationRegex.test(result)) {
|
|
385
|
-
result = result.replace(durationRegex, `- Duration: ${formattedDuration}
|
|
414
|
+
result = result.replace(durationRegex, `- Duration: ${formattedDuration}`);
|
|
386
415
|
} else {
|
|
387
416
|
result += `- Duration: ${formattedDuration}\n`;
|
|
388
417
|
}
|
|
@@ -415,7 +444,7 @@ function upsertCallResult({ body, result, logFormat }) {
|
|
|
415
444
|
// More flexible regex that handles both with and without newlines
|
|
416
445
|
const resultRegex = /- Result: ([^\n-]+)(?=\n-|\n|$)/;
|
|
417
446
|
if (resultRegex.test(bodyResult)) {
|
|
418
|
-
bodyResult = bodyResult.replace(resultRegex, `- Result: ${result}
|
|
447
|
+
bodyResult = bodyResult.replace(resultRegex, `- Result: ${result}`);
|
|
419
448
|
} else {
|
|
420
449
|
bodyResult += `- Result: ${result}\n`;
|
|
421
450
|
}
|
|
@@ -429,8 +458,8 @@ function upsertCallRecording({ body, recordingLink, logFormat }) {
|
|
|
429
458
|
let result = body;
|
|
430
459
|
|
|
431
460
|
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
432
|
-
|
|
433
|
-
|
|
461
|
+
// More flexible regex that handles both <li> wrapped and unwrapped content, and existing <a> anchors
|
|
462
|
+
const recordingLinkRegex = /(?:<li>)?<b>Call recording link<\/b>:\s*(?:<a[^>]*>[^<]*<\/a>|[^<]+)(?:<\/li>|(?=<|$))/i;
|
|
434
463
|
if (recordingLink) {
|
|
435
464
|
if (recordingLinkRegex.test(result)) {
|
|
436
465
|
if (recordingLink.startsWith('http')) {
|
|
@@ -502,7 +531,7 @@ function upsertAiNote({ body, aiNote, logFormat }) {
|
|
|
502
531
|
if (aiNoteRegex.test(result)) {
|
|
503
532
|
result = result.replace(aiNoteRegex, `- AI Note:\n${clearedAiNote}\n--- END`);
|
|
504
533
|
} else {
|
|
505
|
-
result +=
|
|
534
|
+
result += `\n- AI Note:\n${clearedAiNote}\n--- END\n`;
|
|
506
535
|
}
|
|
507
536
|
}
|
|
508
537
|
return result;
|
|
@@ -534,7 +563,7 @@ function upsertTranscript({ body, transcript, logFormat }) {
|
|
|
534
563
|
if (transcriptRegex.test(result)) {
|
|
535
564
|
result = result.replace(transcriptRegex, `- Transcript:\n${transcript}\n--- END`);
|
|
536
565
|
} else {
|
|
537
|
-
result +=
|
|
566
|
+
result += `\n- Transcript:\n${transcript}\n--- END\n`;
|
|
538
567
|
}
|
|
539
568
|
}
|
|
540
569
|
return result;
|
|
@@ -615,6 +644,158 @@ function upsertLegs({ body, legs, logFormat }) {
|
|
|
615
644
|
return result;
|
|
616
645
|
}
|
|
617
646
|
|
|
647
|
+
function upsertRingSenseTranscript({ body, transcript, logFormat }) {
|
|
648
|
+
if (!transcript) return body;
|
|
649
|
+
|
|
650
|
+
let result = body;
|
|
651
|
+
const clearedTranscript = transcript.replace(/\n+$/, '');
|
|
652
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
653
|
+
const formattedTranscript = clearedTranscript.replace(/(?:\r\n|\r|\n)/g, '<br>');
|
|
654
|
+
const transcriptRegex = /<div><b>RingSense transcript<\/b><br>(.+?)<\/div>/;
|
|
655
|
+
if (transcriptRegex.test(result)) {
|
|
656
|
+
result = result.replace(transcriptRegex, `<div><b>RingSense transcript</b><br>${formattedTranscript}</div>`);
|
|
657
|
+
} else {
|
|
658
|
+
result += `<div><b>RingSense transcript</b><br>${formattedTranscript}</div>`;
|
|
659
|
+
}
|
|
660
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
661
|
+
const transcriptRegex = /### RingSense transcript\n([\s\S]*?)(?=\n### |\n$|$)/;
|
|
662
|
+
if (transcriptRegex.test(result)) {
|
|
663
|
+
result = result.replace(transcriptRegex, `### RingSense transcript\n${clearedTranscript}\n`);
|
|
664
|
+
} else {
|
|
665
|
+
result += `### RingSense transcript\n${clearedTranscript}\n`;
|
|
666
|
+
}
|
|
667
|
+
} else {
|
|
668
|
+
const transcriptRegex = /- RingSense transcript:([\s\S]*?)--- END/;
|
|
669
|
+
if (transcriptRegex.test(result)) {
|
|
670
|
+
result = result.replace(transcriptRegex, `- RingSense transcript:\n${clearedTranscript}\n--- END`);
|
|
671
|
+
} else {
|
|
672
|
+
result += `\n- RingSense transcript:\n${clearedTranscript}\n--- END\n`;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return result;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
function upsertRingSenseSummary({ body, summary, logFormat }) {
|
|
679
|
+
if (!summary) return body;
|
|
680
|
+
|
|
681
|
+
let result = body;
|
|
682
|
+
// remove new line in last line of summary
|
|
683
|
+
const clearedSummary = summary.replace(/\n+$/, '');
|
|
684
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
685
|
+
const summaryRegex = /<div><b>RingSense summary<\/b><br>(.+?)<\/div>/;
|
|
686
|
+
const formattedSummary = clearedSummary.replace(/(?:\r\n|\r|\n)/g, '<br>');
|
|
687
|
+
if (summaryRegex.test(result)) {
|
|
688
|
+
result = result.replace(summaryRegex, `<div><b>RingSense summary</b><br>${formattedSummary}</div>`);
|
|
689
|
+
} else {
|
|
690
|
+
result += `<div><b>RingSense summary</b><br>${formattedSummary}</div>`;
|
|
691
|
+
}
|
|
692
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
693
|
+
const summaryRegex = /### RingSense summary\n([\s\S]*?)(?=\n### |\n$|$)/;
|
|
694
|
+
if (summaryRegex.test(result)) {
|
|
695
|
+
result = result.replace(summaryRegex, `### RingSense summary\n${summary}\n`);
|
|
696
|
+
} else {
|
|
697
|
+
result += `### RingSense summary\n${summary}\n`;
|
|
698
|
+
}
|
|
699
|
+
} else {
|
|
700
|
+
const summaryRegex = /- RingSense summary:([\s\S]*?)--- END/;
|
|
701
|
+
if (summaryRegex.test(result)) {
|
|
702
|
+
result = result.replace(summaryRegex, `- RingSense summary:\n${summary}\n--- END`);
|
|
703
|
+
} else {
|
|
704
|
+
result += `\n- RingSense summary:\n${summary}\n--- END\n`;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
return result;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
function upsertRingSenseAIScore({ body, score, logFormat }) {
|
|
711
|
+
if (!score) return body;
|
|
712
|
+
|
|
713
|
+
let result = body;
|
|
714
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
715
|
+
const scoreRegex = /(?:<li>)?<b>Call score<\/b>:\s*([^<\n]+)(?:<\/li>|(?=<|$))/i;
|
|
716
|
+
if (scoreRegex.test(result)) {
|
|
717
|
+
result = result.replace(scoreRegex, `<li><b>Call score</b>: ${score}</li>`);
|
|
718
|
+
} else {
|
|
719
|
+
result += `<li><b>Call score</b>: ${score}</li>`;
|
|
720
|
+
}
|
|
721
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
722
|
+
const scoreRegex = /\*\*Call score\*\*: [^\n]*\n*/;
|
|
723
|
+
if (scoreRegex.test(result)) {
|
|
724
|
+
result = result.replace(scoreRegex, `**Call score**: ${score}\n`);
|
|
725
|
+
} else {
|
|
726
|
+
result += `**Call score**: ${score}\n`;
|
|
727
|
+
}
|
|
728
|
+
} else {
|
|
729
|
+
const scoreRegex = /- Call score:\s*([^<\n]+)(?=\n|$)/i;
|
|
730
|
+
if (scoreRegex.test(result)) {
|
|
731
|
+
result = result.replace(scoreRegex, `- Call score: ${score}`);
|
|
732
|
+
} else {
|
|
733
|
+
result += `- Call score: ${score}\n`;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
return result;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
function upsertRingSenseBulletedSummary({ body, summary, logFormat }) {
|
|
740
|
+
if (!summary) return body;
|
|
741
|
+
|
|
742
|
+
let result = body;
|
|
743
|
+
const clearedSummary = summary.replace(/\n+$/, '');
|
|
744
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
745
|
+
const summaryRegex = /<div><b>RingSense bulleted summary<\/b><br>(.+?)<\/div>/;
|
|
746
|
+
const formattedSummary = clearedSummary.replace(/(?:\r\n|\r|\n)/g, '<br>');
|
|
747
|
+
if (summaryRegex.test(result)) {
|
|
748
|
+
result = result.replace(summaryRegex, `<div><b>RingSense bulleted summary</b><br>${formattedSummary}</div>`);
|
|
749
|
+
} else {
|
|
750
|
+
result += `<div><b>RingSense bulleted summary</b><br>${formattedSummary}</div>`;
|
|
751
|
+
}
|
|
752
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
753
|
+
const summaryRegex = /### RingSense bulleted summary\n([\s\S]*?)(?=\n### |\n$|$)/;
|
|
754
|
+
if (summaryRegex.test(result)) {
|
|
755
|
+
result = result.replace(summaryRegex, `### RingSense bulleted summary\n${summary}\n`);
|
|
756
|
+
} else {
|
|
757
|
+
result += `### RingSense bulleted summary\n${summary}\n`;
|
|
758
|
+
}
|
|
759
|
+
} else {
|
|
760
|
+
const summaryRegex = /- RingSense bulleted summary:\s*([^<\n]+)(?=\n|$)/i;
|
|
761
|
+
if (summaryRegex.test(result)) {
|
|
762
|
+
result = result.replace(summaryRegex, `- RingSense bulleted summary:\n${summary}\n--- END`);
|
|
763
|
+
} else {
|
|
764
|
+
result += `\n- RingSense bulleted summary:\n${summary}\n--- END\n`;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
return result;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
function upsertRingSenseLink({ body, link, logFormat }) {
|
|
771
|
+
if (!link) return body;
|
|
772
|
+
|
|
773
|
+
let result = body;
|
|
774
|
+
if (logFormat === LOG_DETAILS_FORMAT_TYPE.HTML) {
|
|
775
|
+
const linkRegex = /(?:<li>)?<b>RingSense recording link<\/b>:\s*(?:<a[^>]*>[^<]*<\/a>|[^<]+)(?:<\/li>|(?=<|$))/i;
|
|
776
|
+
if (linkRegex.test(result)) {
|
|
777
|
+
result = result.replace(linkRegex, `<li><b>RingSense recording link</b>: <a target="_blank" href="${link}">open</a></li>`);
|
|
778
|
+
} else {
|
|
779
|
+
result += `<li><b>RingSense recording link</b>: <a target="_blank" href="${link}">open</a></li>`;
|
|
780
|
+
}
|
|
781
|
+
} else if (logFormat === LOG_DETAILS_FORMAT_TYPE.MARKDOWN) {
|
|
782
|
+
const linkRegex = /\*\*RingSense recording link\*\*:\s*([^<\n]+)(?=\n|$)/i;
|
|
783
|
+
if (linkRegex.test(result)) {
|
|
784
|
+
result = result.replace(linkRegex, `**RingSense recording link**: ${link}\n`);
|
|
785
|
+
} else {
|
|
786
|
+
result += `**RingSense recording link**: ${link}\n`;
|
|
787
|
+
}
|
|
788
|
+
} else {
|
|
789
|
+
const linkRegex = /- RingSense recording link:\s*([^<\n]+)(?=\n|$)/i;
|
|
790
|
+
if (linkRegex.test(result)) {
|
|
791
|
+
result = result.replace(linkRegex, `- RingSense recording link: ${link}`);
|
|
792
|
+
} else {
|
|
793
|
+
result += `- RingSense recording link: ${link}\n`;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
return result;
|
|
797
|
+
}
|
|
798
|
+
|
|
618
799
|
module.exports = {
|
|
619
800
|
composeCallLog,
|
|
620
801
|
// Export individual upsert functions for backward compatibility
|
|
@@ -631,4 +812,9 @@ module.exports = {
|
|
|
631
812
|
upsertAiNote,
|
|
632
813
|
upsertTranscript,
|
|
633
814
|
upsertLegs,
|
|
815
|
+
upsertRingSenseTranscript,
|
|
816
|
+
upsertRingSenseSummary,
|
|
817
|
+
upsertRingSenseAIScore,
|
|
818
|
+
upsertRingSenseBulletedSummary,
|
|
819
|
+
upsertRingSenseLink,
|
|
634
820
|
};
|
package/lib/oauth.js
CHANGED
|
@@ -3,7 +3,6 @@ const ClientOAuth2 = require('client-oauth2');
|
|
|
3
3
|
const moment = require('moment');
|
|
4
4
|
const { UserModel } = require('../models/userModel');
|
|
5
5
|
const connectorRegistry = require('../connector/registry');
|
|
6
|
-
const dynamoose = require('dynamoose');
|
|
7
6
|
|
|
8
7
|
// oauthApp strategy is default to 'code' which use credentials to get accessCode, then exchange for accessToken and refreshToken.
|
|
9
8
|
// To change to other strategies, please refer to: https://github.com/mulesoft-labs/js-client-oauth2
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
const dynamoose = require('dynamoose');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
|
|
4
|
+
const CONNECTOR_STATUS = {
|
|
5
|
+
PRIVATE: 'private',
|
|
6
|
+
UNDER_REVIEW: 'under_review',
|
|
7
|
+
APPROVED: 'approved',
|
|
8
|
+
REJECTED: 'rejected',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const connectorSchema = new dynamoose.Schema({
|
|
12
|
+
accountId: {
|
|
13
|
+
type: String,
|
|
14
|
+
hashKey: true,
|
|
15
|
+
},
|
|
16
|
+
id: {
|
|
17
|
+
type: String,
|
|
18
|
+
rangeKey: true,
|
|
19
|
+
},
|
|
20
|
+
// Reference to original connector (for partition records)
|
|
21
|
+
originalAccountId: {
|
|
22
|
+
type: String,
|
|
23
|
+
required: false, // Only set for partition records (under_review, approved)
|
|
24
|
+
},
|
|
25
|
+
// Basic Information
|
|
26
|
+
name: {
|
|
27
|
+
type: String,
|
|
28
|
+
required: true,
|
|
29
|
+
},
|
|
30
|
+
displayName: String,
|
|
31
|
+
description: String,
|
|
32
|
+
iconUrl: String,
|
|
33
|
+
// Status and Workflow
|
|
34
|
+
status: {
|
|
35
|
+
type: String,
|
|
36
|
+
required: true,
|
|
37
|
+
enum: Object.values(CONNECTOR_STATUS),
|
|
38
|
+
default: CONNECTOR_STATUS.PRIVATE,
|
|
39
|
+
index: {
|
|
40
|
+
name: 'statusIdIndex',
|
|
41
|
+
global: true,
|
|
42
|
+
rangeKey: 'id',
|
|
43
|
+
project: ['accountId', 'name', 'displayName', 'developer', 'originalAccountId'],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
creatorId: String,
|
|
47
|
+
// Developer Information
|
|
48
|
+
developer: {
|
|
49
|
+
type: Object,
|
|
50
|
+
schema: {
|
|
51
|
+
name: String,
|
|
52
|
+
websiteUrl: String,
|
|
53
|
+
supportUrl: String,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
// Manifest Management
|
|
57
|
+
manifest: {
|
|
58
|
+
type: Object,
|
|
59
|
+
required: true,
|
|
60
|
+
},
|
|
61
|
+
proxyConfig: {
|
|
62
|
+
type: Object,
|
|
63
|
+
required: false,
|
|
64
|
+
},
|
|
65
|
+
proxyId: {
|
|
66
|
+
type: String,
|
|
67
|
+
index: {
|
|
68
|
+
name: 'proxyIdIndex',
|
|
69
|
+
global: true,
|
|
70
|
+
project: ['id', 'accountId', 'creatorId', 'name', 'displayName', 'status', 'developer', 'originalAccountId', 'proxyConfig'],
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
// Review and Approval
|
|
74
|
+
submittedAt: Number,
|
|
75
|
+
reviewedBy: String,
|
|
76
|
+
reviewedAt: Number,
|
|
77
|
+
reviewNotes: String,
|
|
78
|
+
rejectionReason: String,
|
|
79
|
+
demoAccounts: String,
|
|
80
|
+
// Usage and Analytics
|
|
81
|
+
usageCount: {
|
|
82
|
+
type: Number,
|
|
83
|
+
default: 0,
|
|
84
|
+
},
|
|
85
|
+
lastUsedAt: Number,
|
|
86
|
+
allowedAccounts: {
|
|
87
|
+
type: Array,
|
|
88
|
+
schema: [String],
|
|
89
|
+
},
|
|
90
|
+
encodedSecretKey: String,
|
|
91
|
+
}, {
|
|
92
|
+
saveUnknown: ['manifest.**', 'proxyConfig.**'],
|
|
93
|
+
timestamps: true,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const tableOptions = {
|
|
97
|
+
prefix: process.env.DEVELOPER_DYNAMODB_TABLE_PREFIX,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
if (process.env.NODE_ENV === 'production') {
|
|
101
|
+
tableOptions.create = false;
|
|
102
|
+
tableOptions.waitForActive = false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const Connector = dynamoose.model('connectors', connectorSchema, tableOptions);
|
|
106
|
+
|
|
107
|
+
function getDeveloperCipherKey() {
|
|
108
|
+
if (!process.env.DEVELOPER_APP_SERVER_SECRET_KEY) {
|
|
109
|
+
throw new Error('DEVELOPER_APP_SERVER_SECRET_KEY is not defined');
|
|
110
|
+
}
|
|
111
|
+
if (process.env.DEVELOPER_APP_SERVER_SECRET_KEY.length < 32) {
|
|
112
|
+
// pad secret key with spaces if it is less than 32 bytes
|
|
113
|
+
return process.env.DEVELOPER_APP_SERVER_SECRET_KEY.padEnd(32, ' ');
|
|
114
|
+
}
|
|
115
|
+
if (process.env.DEVELOPER_APP_SERVER_SECRET_KEY.length > 32) {
|
|
116
|
+
// truncate secret key if it is more than 32 bytes
|
|
117
|
+
return process.env.DEVELOPER_APP_SERVER_SECRET_KEY.slice(0, 32);
|
|
118
|
+
}
|
|
119
|
+
return process.env.DEVELOPER_APP_SERVER_SECRET_KEY;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function decode(encryptedData) {
|
|
123
|
+
const decipher = crypto.createDecipheriv('aes-256-cbc', getDeveloperCipherKey(), Buffer.alloc(16, 0));
|
|
124
|
+
return decipher.update(encryptedData, 'hex', 'utf8') + decipher.final('utf8');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ADD static method to get connector by proxyId
|
|
128
|
+
Connector.getProxyConfig = async (proxyId) => {
|
|
129
|
+
const connectors = await Connector
|
|
130
|
+
.query('proxyId')
|
|
131
|
+
.eq(proxyId)
|
|
132
|
+
.using('proxyIdIndex')
|
|
133
|
+
.exec();
|
|
134
|
+
if (connectors.length > 0) {
|
|
135
|
+
const proxyConfig = connectors[0].proxyConfig;
|
|
136
|
+
const encodedSecretKey = connectors[0].encodedSecretKey;
|
|
137
|
+
const secretKey = encodedSecretKey ? decode(encodedSecretKey) : null;
|
|
138
|
+
if (secretKey) {
|
|
139
|
+
proxyConfig.secretKey = secretKey;
|
|
140
|
+
}
|
|
141
|
+
return proxyConfig;
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
exports.Connector = Connector;
|
package/package.json
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@app-connect/core",
|
|
3
|
-
"version": "1.7.
|
|
4
|
-
"description": "RingCentral App Connect Core",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/ringcentral/rc-unified-crm-extension.git"
|
|
9
|
-
},
|
|
10
|
-
"keywords": [
|
|
11
|
-
"RingCentral",
|
|
12
|
-
"App Connect"
|
|
13
|
-
],
|
|
14
|
-
"author": "RingCentral Labs",
|
|
15
|
-
"license": "MIT",
|
|
16
|
-
"peerDependencies": {
|
|
17
|
-
"axios": "^1.12.2",
|
|
18
|
-
"express": "^4.21.2",
|
|
19
|
-
"pg": "^8.8.0",
|
|
20
|
-
"sequelize": "^6.29.0",
|
|
21
|
-
"moment": "^2.29.4",
|
|
22
|
-
"moment-timezone": "^0.5.39"
|
|
23
|
-
},
|
|
24
|
-
"dependencies": {
|
|
25
|
-
"@aws-sdk/client-dynamodb": "^3.751.0",
|
|
26
|
-
"body-parser": "^1.20.3",
|
|
27
|
-
"client-oauth2": "^4.3.3",
|
|
28
|
-
"cors": "^2.8.5",
|
|
29
|
-
"country-state-city": "^3.2.1",
|
|
30
|
-
"dotenv": "^16.0.3",
|
|
31
|
-
"dynamoose": "^4.0.3",
|
|
32
|
-
"jsonwebtoken": "^9.0.0",
|
|
33
|
-
"mixpanel": "^0.18.0",
|
|
34
|
-
"shortid": "^2.2.17",
|
|
35
|
-
"tz-lookup": "^6.1.25",
|
|
36
|
-
"ua-parser-js": "^1.0.38"
|
|
37
|
-
},
|
|
38
|
-
"scripts": {
|
|
39
|
-
"test": "jest",
|
|
40
|
-
"test:watch": "jest --watch",
|
|
41
|
-
"test:coverage": "jest --coverage",
|
|
42
|
-
"test:ci": "jest --ci --coverage --watchAll=false"
|
|
43
|
-
},
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"@eslint/js": "^9.22.0",
|
|
46
|
-
"@octokit/rest": "^19.0.5",
|
|
47
|
-
"axios": "^1.12.2",
|
|
48
|
-
"express": "^4.21.2",
|
|
49
|
-
"eslint": "^9.22.0",
|
|
50
|
-
"globals": "^16.0.0",
|
|
51
|
-
"jest": "^29.3.1",
|
|
52
|
-
"moment": "^2.29.4",
|
|
53
|
-
"moment-timezone": "^0.5.39",
|
|
54
|
-
"nock": "^13.2.9",
|
|
55
|
-
"pg": "^8.8.0",
|
|
56
|
-
"sequelize": "^6.29.0",
|
|
57
|
-
"sqlite3": "^5.1.2",
|
|
58
|
-
"supertest": "^6.3.1"
|
|
59
|
-
},
|
|
60
|
-
"overrides": {
|
|
61
|
-
"js-object-utilities": "2.2.1"
|
|
62
|
-
},
|
|
63
|
-
"bugs": {
|
|
64
|
-
"url": "https://github.com/ringcentral/rc-unified-crm-extension/issues"
|
|
65
|
-
},
|
|
66
|
-
"homepage": "https://github.com/ringcentral/rc-unified-crm-extension#readme"
|
|
67
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@app-connect/core",
|
|
3
|
+
"version": "1.7.4",
|
|
4
|
+
"description": "RingCentral App Connect Core",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/ringcentral/rc-unified-crm-extension.git"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"RingCentral",
|
|
12
|
+
"App Connect"
|
|
13
|
+
],
|
|
14
|
+
"author": "RingCentral Labs",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"axios": "^1.12.2",
|
|
18
|
+
"express": "^4.21.2",
|
|
19
|
+
"pg": "^8.8.0",
|
|
20
|
+
"sequelize": "^6.29.0",
|
|
21
|
+
"moment": "^2.29.4",
|
|
22
|
+
"moment-timezone": "^0.5.39"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@aws-sdk/client-dynamodb": "^3.751.0",
|
|
26
|
+
"body-parser": "^1.20.3",
|
|
27
|
+
"client-oauth2": "^4.3.3",
|
|
28
|
+
"cors": "^2.8.5",
|
|
29
|
+
"country-state-city": "^3.2.1",
|
|
30
|
+
"dotenv": "^16.0.3",
|
|
31
|
+
"dynamoose": "^4.0.3",
|
|
32
|
+
"jsonwebtoken": "^9.0.0",
|
|
33
|
+
"mixpanel": "^0.18.0",
|
|
34
|
+
"shortid": "^2.2.17",
|
|
35
|
+
"tz-lookup": "^6.1.25",
|
|
36
|
+
"ua-parser-js": "^1.0.38"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"test": "jest",
|
|
40
|
+
"test:watch": "jest --watch",
|
|
41
|
+
"test:coverage": "jest --coverage",
|
|
42
|
+
"test:ci": "jest --ci --coverage --watchAll=false"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@eslint/js": "^9.22.0",
|
|
46
|
+
"@octokit/rest": "^19.0.5",
|
|
47
|
+
"axios": "^1.12.2",
|
|
48
|
+
"express": "^4.21.2",
|
|
49
|
+
"eslint": "^9.22.0",
|
|
50
|
+
"globals": "^16.0.0",
|
|
51
|
+
"jest": "^29.3.1",
|
|
52
|
+
"moment": "^2.29.4",
|
|
53
|
+
"moment-timezone": "^0.5.39",
|
|
54
|
+
"nock": "^13.2.9",
|
|
55
|
+
"pg": "^8.8.0",
|
|
56
|
+
"sequelize": "^6.29.0",
|
|
57
|
+
"sqlite3": "^5.1.2",
|
|
58
|
+
"supertest": "^6.3.1"
|
|
59
|
+
},
|
|
60
|
+
"overrides": {
|
|
61
|
+
"js-object-utilities": "2.2.1"
|
|
62
|
+
},
|
|
63
|
+
"bugs": {
|
|
64
|
+
"url": "https://github.com/ringcentral/rc-unified-crm-extension/issues"
|
|
65
|
+
},
|
|
66
|
+
"homepage": "https://github.com/ringcentral/rc-unified-crm-extension#readme"
|
|
67
|
+
}
|
package/releaseNotes.json
CHANGED
|
@@ -1,4 +1,52 @@
|
|
|
1
1
|
{
|
|
2
|
+
"1.7.4": {
|
|
3
|
+
"global": [
|
|
4
|
+
{
|
|
5
|
+
"type": "New",
|
|
6
|
+
"description": "Auto restart server-side logging when call log details setting changed"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"type": "New",
|
|
10
|
+
"description": "Support to change quick access button size"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"type": "New",
|
|
14
|
+
"description": "Support to open log form when during a call"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"type": "Fix",
|
|
18
|
+
"description": "An edge case of unwanted call log in call queue scenario"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
"1.7.3": {
|
|
23
|
+
"global": [
|
|
24
|
+
{
|
|
25
|
+
"type": "New",
|
|
26
|
+
"description": "RingSense data logging in server side logging"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"type": "New",
|
|
30
|
+
"description": "New phone setting item to group phone related settings"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"type": "Better",
|
|
34
|
+
"description": "HUD enabled by default"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"type": "Fix",
|
|
38
|
+
"description": "A small issue on contact search feature"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"type": "Fix",
|
|
42
|
+
"description": "A small issue on embedded URLs"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"type": "Fix",
|
|
46
|
+
"description": "Server-side logging logged calls cannot be edited for the first attempt"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
2
50
|
"1.7.1": {
|
|
3
51
|
"global": [
|
|
4
52
|
{
|
|
@@ -11,6 +59,30 @@
|
|
|
11
59
|
}
|
|
12
60
|
]
|
|
13
61
|
},
|
|
62
|
+
"1.6.12": {
|
|
63
|
+
"global": [
|
|
64
|
+
{
|
|
65
|
+
"type": "New",
|
|
66
|
+
"description": "Support RingSense logging with server-side logging"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"type": "Fix",
|
|
70
|
+
"description": "An edge case of unwanted call log in call queue scenario"
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
"1.6.11":{
|
|
75
|
+
"global": [
|
|
76
|
+
{
|
|
77
|
+
"type": "Fix",
|
|
78
|
+
"description": "A small issue on contact search feature"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"type": "Fix",
|
|
82
|
+
"description": "A small issue on embedded URLs"
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
},
|
|
14
86
|
"1.6.10": {
|
|
15
87
|
"global": [
|
|
16
88
|
{
|