@pipedream/twilio 0.3.3 → 0.3.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/actions/delete-call/delete-call.mjs +23 -0
- package/actions/delete-message/delete-message.mjs +23 -0
- package/actions/download-recording-media/download-recording-media.mjs +50 -0
- package/actions/get-call/get-call.mjs +23 -0
- package/actions/get-message/get-message.mjs +23 -0
- package/actions/list-calls/list-calls.mjs +60 -0
- package/actions/list-message-media/list-message-media.mjs +34 -0
- package/actions/list-messages/list-messages.mjs +60 -0
- package/actions/list-recording-transcriptions/list-recording-transcriptions.mjs +37 -0
- package/actions/make-phone-call/make-phone-call.mjs +52 -0
- package/actions/send-mms/send-mms.mjs +59 -0
- package/actions/send-sms/send-sms.mjs +52 -0
- package/package.json +19 -19
- package/sources/common-polling.mjs +44 -0
- package/sources/common-webhook.mjs +102 -0
- package/sources/new-call/new-call.mjs +33 -0
- package/sources/new-incoming-sms/new-incoming-sms.mjs +46 -0
- package/sources/new-phone-number/new-phone-number.mjs +29 -0
- package/sources/new-recording/new-recording.mjs +28 -0
- package/sources/new-transcription/new-transcription.mjs +28 -0
- package/twilio.app.mjs +343 -0
- package/utils.mjs +147 -0
- package/sources/new-incoming-sms/new-incoming-sms.js +0 -86
- package/twilio.app.js +0 -52
package/utils.mjs
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format a number of seconds into a time elapsed string
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* // returns "15s"
|
|
6
|
+
* formatTimeElapsed(15);
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* // returns "35min"
|
|
10
|
+
* formatTimeElapsed(60 * 35.5);
|
|
11
|
+
*
|
|
12
|
+
* @param {Number} seconds - the number of seconds
|
|
13
|
+
* @returns the formatted time elapsed string
|
|
14
|
+
*/
|
|
15
|
+
function formatTimeElapsed(seconds) {
|
|
16
|
+
var interval = seconds / 31536000;
|
|
17
|
+
|
|
18
|
+
if (interval > 1) {
|
|
19
|
+
return Math.floor(interval) + " years";
|
|
20
|
+
}
|
|
21
|
+
interval = seconds / 2592000;
|
|
22
|
+
if (interval > 1) {
|
|
23
|
+
return Math.floor(interval) + " months";
|
|
24
|
+
}
|
|
25
|
+
interval = seconds / 86400;
|
|
26
|
+
if (interval > 1) {
|
|
27
|
+
return Math.floor(interval) + "d";
|
|
28
|
+
}
|
|
29
|
+
interval = seconds / 3600;
|
|
30
|
+
if (interval > 1) {
|
|
31
|
+
return Math.floor(interval) + "h";
|
|
32
|
+
}
|
|
33
|
+
interval = seconds / 60;
|
|
34
|
+
if (interval > 1) {
|
|
35
|
+
return Math.floor(interval) + "min";
|
|
36
|
+
}
|
|
37
|
+
return Math.floor(seconds) + "s";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get the time between two dates as a time-elapsed string
|
|
42
|
+
*
|
|
43
|
+
* @param {Date} date1 the earlier date
|
|
44
|
+
* @param {Date} date2 the later date
|
|
45
|
+
* @returns the time elapsed between two dates
|
|
46
|
+
*/
|
|
47
|
+
function timeBetween(date1, date2) {
|
|
48
|
+
var seconds = Math.floor((date2 - date1) / 1000);
|
|
49
|
+
|
|
50
|
+
return formatTimeElapsed(seconds);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Return a copy of `obj` with properties omitted whose value is an empty string
|
|
55
|
+
*
|
|
56
|
+
* @param {Object} obj - the base object
|
|
57
|
+
* @returns the new object
|
|
58
|
+
*/
|
|
59
|
+
function omitEmptyStringValues(obj) {
|
|
60
|
+
return Object.fromEntries(
|
|
61
|
+
Object.entries(obj).filter((kVpair) => kVpair[1] !== ""),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Return `value` if `condition` or an empty string otherwise
|
|
67
|
+
*
|
|
68
|
+
* @param {*} condition - the condition
|
|
69
|
+
* @param {*} value - the value to conditionally return
|
|
70
|
+
* @returns the value, if the condition is true, and empty string otherwise
|
|
71
|
+
*/
|
|
72
|
+
function valueOrEmptyString(condition, value) {
|
|
73
|
+
return condition
|
|
74
|
+
? value
|
|
75
|
+
: "";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Format a date as a human-readable string
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* // returns "2021-10-01"
|
|
83
|
+
* formatDateString("2021-10-01T01:06:45.000Z");
|
|
84
|
+
*
|
|
85
|
+
* @param {Date|String} date - the date to format
|
|
86
|
+
* @returns the formatted date string
|
|
87
|
+
*/
|
|
88
|
+
function formatDateString(date) {
|
|
89
|
+
const dateObj = new Date(date);
|
|
90
|
+
return dateObj.toISOString().split("T")[0];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Format a [Twilio Call object]{@link https://www.twilio.com/docs/voice/api/call-resource} as a
|
|
95
|
+
* string
|
|
96
|
+
*
|
|
97
|
+
* @param {Object} call - The Twilio Call object
|
|
98
|
+
* @returns the string representing a call
|
|
99
|
+
*/
|
|
100
|
+
function callToString(call) {
|
|
101
|
+
const fromPart = valueOrEmptyString(call.fromFormatted, call.fromFormatted);
|
|
102
|
+
const toPart = valueOrEmptyString(call.toFormatted, ` to ${call.toFormatted}`);
|
|
103
|
+
const datePart = valueOrEmptyString(call.startTime, ` on ${formatDateString(call.startTime)}`);
|
|
104
|
+
const durationPart = valueOrEmptyString(call.duration, ` for ${formatTimeElapsed(call.duration)}`);
|
|
105
|
+
return fromPart + toPart + datePart + durationPart;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Format a [Twilio Message object]{@link https://www.twilio.com/docs/sms/api/message-resource} as a
|
|
110
|
+
* string
|
|
111
|
+
*
|
|
112
|
+
* @param {Object} call - The Twilio Message object
|
|
113
|
+
* @returns the string representing a message
|
|
114
|
+
*/
|
|
115
|
+
function messageToString(message) {
|
|
116
|
+
const MAX_LENGTH = 30;
|
|
117
|
+
const messageText = message.body.length > MAX_LENGTH
|
|
118
|
+
? `${message.body.slice(0, MAX_LENGTH)}...`
|
|
119
|
+
: message.body; // truncate long text
|
|
120
|
+
const messageDate = message.dateSent || message.dateCreated;
|
|
121
|
+
const dateString = formatDateString(messageDate);
|
|
122
|
+
return `${message.from} to ${message.to} on ${dateString}: ${messageText}`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Format a [Twilio Recording object]{@link https://www.twilio.com/docs/voice/api/recording} as a
|
|
127
|
+
* string
|
|
128
|
+
*
|
|
129
|
+
* @param {Object} call - The Twilio Recording object
|
|
130
|
+
* @returns the string representing a recording
|
|
131
|
+
*/
|
|
132
|
+
function recordingToString(recording) {
|
|
133
|
+
const datePart = valueOrEmptyString(recording.startTime, ` ${formatDateString(recording.startTime)}`);
|
|
134
|
+
const durationPart = valueOrEmptyString(recording.duration, ` - ${formatTimeElapsed(recording.duration)}`);
|
|
135
|
+
return datePart + durationPart;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export {
|
|
139
|
+
formatTimeElapsed,
|
|
140
|
+
timeBetween,
|
|
141
|
+
omitEmptyStringValues,
|
|
142
|
+
valueOrEmptyString,
|
|
143
|
+
formatDateString,
|
|
144
|
+
callToString,
|
|
145
|
+
messageToString,
|
|
146
|
+
recordingToString,
|
|
147
|
+
};
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
const twilio = require("../../twilio.app.js");
|
|
2
|
-
const MessagingResponse = require("twilio").twiml.MessagingResponse;
|
|
3
|
-
const twilioClient = require("twilio");
|
|
4
|
-
|
|
5
|
-
module.exports = {
|
|
6
|
-
key: "twilio-new-incoming-sms",
|
|
7
|
-
name: "New Incoming SMS",
|
|
8
|
-
description:
|
|
9
|
-
"Configures a webhook in Twilio, tied to an incoming phone number, and emits an event each time an SMS is sent to that number",
|
|
10
|
-
version: "0.0.4",
|
|
11
|
-
dedupe: "unique",
|
|
12
|
-
props: {
|
|
13
|
-
twilio,
|
|
14
|
-
incomingPhoneNumber: { propDefinition: [twilio, "incomingPhoneNumber"] },
|
|
15
|
-
authToken: { propDefinition: [twilio, "authToken"] },
|
|
16
|
-
responseMessage: { propDefinition: [twilio, "responseMessage"] },
|
|
17
|
-
http: {
|
|
18
|
-
type: "$.interface.http",
|
|
19
|
-
customResponse: true,
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
hooks: {
|
|
23
|
-
async activate() {
|
|
24
|
-
console.log(
|
|
25
|
-
`Creating webhook for phone number ${this.incomingPhoneNumber}`
|
|
26
|
-
);
|
|
27
|
-
const createWebhookResp = await this.twilio.setIncomingSMSWebhookURL(
|
|
28
|
-
this.incomingPhoneNumber,
|
|
29
|
-
this.http.endpoint
|
|
30
|
-
);
|
|
31
|
-
console.log(createWebhookResp);
|
|
32
|
-
},
|
|
33
|
-
async deactivate() {
|
|
34
|
-
console.log(
|
|
35
|
-
`Removing webhook from phone number ${this.incomingPhoneNumber}`
|
|
36
|
-
);
|
|
37
|
-
const deleteWebhookResp = await this.twilio.setIncomingSMSWebhookURL(
|
|
38
|
-
this.incomingPhoneNumber,
|
|
39
|
-
"" // remove the webhook URL
|
|
40
|
-
);
|
|
41
|
-
console.log(deleteWebhookResp);
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
async run(event) {
|
|
45
|
-
const { body, headers } = event;
|
|
46
|
-
const twiml = new MessagingResponse();
|
|
47
|
-
|
|
48
|
-
// https://support.twilio.com/hc/en-us/articles/223134127-Receive-SMS-and-MMS-Messages-without-Responding
|
|
49
|
-
let responseBody = "<Response></Response>";
|
|
50
|
-
if (this.responseMessage) {
|
|
51
|
-
twiml.message(this.responseMessage);
|
|
52
|
-
responseBody = twiml.toString();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
this.http.respond({
|
|
56
|
-
status: 200,
|
|
57
|
-
headers: { "Content-Type": "text/xml" },
|
|
58
|
-
body: responseBody,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
const twilioSignature = headers["x-twilio-signature"];
|
|
62
|
-
if (!twilioSignature) {
|
|
63
|
-
console.log("No x-twilio-signature header in request. Exiting.");
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// See https://www.twilio.com/docs/usage/webhooks/webhooks-security
|
|
68
|
-
if (
|
|
69
|
-
!twilioClient.validateRequest(
|
|
70
|
-
this.authToken,
|
|
71
|
-
twilioSignature,
|
|
72
|
-
`${this.http.endpoint}/`, // This must match the incoming URL exactly, which contains a /
|
|
73
|
-
body
|
|
74
|
-
)
|
|
75
|
-
) {
|
|
76
|
-
throw new Error(
|
|
77
|
-
"Computed Twilio signature doesn't match signature received in header"
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
this.$emit(body, {
|
|
82
|
-
summary: body.Body, // the content of the text message
|
|
83
|
-
id: headers["i-twilio-idempotency-token"], // if Twilio retries a message, but we've already emitted, dedupe
|
|
84
|
-
});
|
|
85
|
-
},
|
|
86
|
-
};
|
package/twilio.app.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
const twilioClient = require("twilio");
|
|
2
|
-
|
|
3
|
-
module.exports = {
|
|
4
|
-
type: "app",
|
|
5
|
-
app: "twilio",
|
|
6
|
-
propDefinitions: {
|
|
7
|
-
authToken: {
|
|
8
|
-
type: "string",
|
|
9
|
-
secret: true,
|
|
10
|
-
label: "Twilio Auth Token",
|
|
11
|
-
description:
|
|
12
|
-
"Your Twilio auth token, found [in your Twilio console](https://www.twilio.com/console). Required for validating Twilio events.",
|
|
13
|
-
},
|
|
14
|
-
incomingPhoneNumber: {
|
|
15
|
-
type: "string",
|
|
16
|
-
label: "Incoming Phone Number",
|
|
17
|
-
description:
|
|
18
|
-
"The Twilio phone number where you'll receive messages. This source creates a webhook tied to this incoming phone number, **overwriting any existing webhook URL**.",
|
|
19
|
-
async options() {
|
|
20
|
-
return await this.listIncomingPhoneNumbers();
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
responseMessage: {
|
|
24
|
-
type: "string",
|
|
25
|
-
optional: true,
|
|
26
|
-
label: "SMS Response Message",
|
|
27
|
-
description:
|
|
28
|
-
"The message you want to send in response to incoming messages. Leave this blank if you don't need to issue a response.",
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
methods: {
|
|
32
|
-
getClient() {
|
|
33
|
-
return twilioClient(this.$auth.Sid, this.$auth.Secret, {
|
|
34
|
-
accountSid: this.$auth.AccountSid,
|
|
35
|
-
});
|
|
36
|
-
},
|
|
37
|
-
async setIncomingSMSWebhookURL(phoneNumberSid, url) {
|
|
38
|
-
const client = this.getClient();
|
|
39
|
-
return await client.incomingPhoneNumbers(phoneNumberSid).update({
|
|
40
|
-
smsMethod: "POST",
|
|
41
|
-
smsUrl: url,
|
|
42
|
-
});
|
|
43
|
-
},
|
|
44
|
-
async listIncomingPhoneNumbers() {
|
|
45
|
-
const client = this.getClient();
|
|
46
|
-
const numbers = await client.incomingPhoneNumbers.list();
|
|
47
|
-
return numbers.map((number) => {
|
|
48
|
-
return { label: number.friendlyName, value: number.sid };
|
|
49
|
-
});
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
};
|