Skip to content

Commit 82f5551

Browse files
authored
Sinch - new components (#18635)
* new components * pnpm-lock.yaml
1 parent d62e552 commit 82f5551

File tree

11 files changed

+505
-12
lines changed

11 files changed

+505
-12
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import sinch from "../../sinch.app.mjs";
2+
import { getFileStreamAndMetadata } from "@pipedream/platform";
3+
import FormData from "form-data";
4+
5+
export default {
6+
key: "sinch-send-fax",
7+
name: "Send Fax",
8+
description: "Send a fax to a contact. [See the documentation](https://developers.sinch.com/docs/fax/api-reference/fax/tag/Faxes/#tag/Faxes/operation/sendFax)",
9+
version: "0.0.1",
10+
type: "action",
11+
annotations: {
12+
destructiveHint: false,
13+
openWorldHint: true,
14+
readOnlyHint: false,
15+
},
16+
props: {
17+
sinch,
18+
to: {
19+
type: "string",
20+
label: "To",
21+
description: "The phone number to send the fax to",
22+
},
23+
file: {
24+
type: "string",
25+
label: "File Path or URL",
26+
description: "Provide either a file URL or a path to a file in the /tmp directory (for example, /tmp/myFile.pdf).",
27+
},
28+
from: {
29+
type: "string",
30+
label: "From",
31+
description: "The phone number of the sender",
32+
optional: true,
33+
},
34+
headerText: {
35+
type: "string",
36+
label: "Header Text",
37+
description: "Text that will be displayed at the top of each page of the fax. 50 characters maximum.",
38+
optional: true,
39+
},
40+
retryDelaySeconds: {
41+
type: "integer",
42+
label: "Retry Delay Seconds",
43+
description: "The number of seconds to wait between retries if the fax is not yet completed",
44+
optional: true,
45+
},
46+
syncDir: {
47+
type: "dir",
48+
accessMode: "read",
49+
sync: true,
50+
optional: true,
51+
},
52+
},
53+
async run({ $ }) {
54+
const data = new FormData();
55+
56+
const {
57+
stream, metadata,
58+
} = await getFileStreamAndMetadata(this.file);
59+
60+
data.append("file", stream, {
61+
contentType: metadata.contentType,
62+
knownLength: metadata.size,
63+
filename: metadata.name,
64+
});
65+
66+
data.append("to", this.to);
67+
if (this.from) {
68+
data.append("from", this.from);
69+
}
70+
if (this.headerText) {
71+
data.append("headerText", this.headerText);
72+
}
73+
if (this.retryDelaySeconds) {
74+
data.append("retryDelaySeconds", this.retryDelaySeconds);
75+
}
76+
77+
const response = await this.sinch.sendFax({
78+
$,
79+
data,
80+
headers: data.getHeaders(),
81+
});
82+
83+
$.export("$summary", `Successfully sent fax to ${this.to}`);
84+
return response;
85+
},
86+
};
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import sinch from "../../sinch.app.mjs";
2+
import constants from "../../common/constants.mjs";
3+
import { ConfigurationError } from "@pipedream/platform";
4+
5+
export default {
6+
key: "sinch-send-message",
7+
name: "Send Message",
8+
description: "Send a message to a contact. [See the documentation](https://developers.sinch.com/docs/conversation/api-reference/conversation/tag/Messages/#tag/Messages/operation/Messages_SendMessage)",
9+
version: "0.0.1",
10+
type: "action",
11+
annotations: {
12+
destructiveHint: false,
13+
openWorldHint: true,
14+
readOnlyHint: false,
15+
},
16+
props: {
17+
sinch,
18+
appId: {
19+
propDefinition: [
20+
sinch,
21+
"appId",
22+
],
23+
},
24+
message: {
25+
type: "string",
26+
label: "Message",
27+
description: "The message to send",
28+
},
29+
contactId: {
30+
propDefinition: [
31+
sinch,
32+
"contactId",
33+
],
34+
description: "The ID of the recipient. Overrides channel and identity",
35+
optional: true,
36+
},
37+
channel: {
38+
type: "string",
39+
label: "Channel",
40+
description: "The channel to send the message to",
41+
options: constants.CHANNELS,
42+
optional: true,
43+
},
44+
identity: {
45+
type: "string",
46+
label: "Identity",
47+
description: "The channel identity. This will differ from channel to channel. For example, a phone number for SMS, WhatsApp, and Viber Business.",
48+
optional: true,
49+
},
50+
},
51+
async run({ $ }) {
52+
if (!this.contactId && !this.identity) {
53+
throw new ConfigurationError("You must provide either a contact ID or an identity.");
54+
}
55+
56+
if (this.identity && !this.channel) {
57+
throw new ConfigurationError("You must provide a channel when providing an identity.");
58+
}
59+
60+
const response = await this.sinch.sendMessage({
61+
$,
62+
data: {
63+
app_id: this.appId,
64+
recipient: this.contactId
65+
? {
66+
contact_id: this.contactId,
67+
}
68+
: {
69+
identified_by: {
70+
channel_identities: [
71+
{
72+
channel: this.channel,
73+
identity: this.identity,
74+
},
75+
],
76+
},
77+
},
78+
message: {
79+
text_message: {
80+
text: this.message,
81+
},
82+
},
83+
},
84+
});
85+
$.export("$summary", "Successfully sent message");
86+
return response;
87+
},
88+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const CHANNELS = [
2+
"WHATSAPP",
3+
"RCS",
4+
"SMS",
5+
"MESSENGER",
6+
"VIBER",
7+
"VIBERBM",
8+
"MMS",
9+
"INSTAGRAM",
10+
"TELEGRAM",
11+
"KAKAOTALK",
12+
"KAKAOTALKCHAT",
13+
"LINE",
14+
"WECHAT",
15+
"APPLEBC",
16+
];
17+
18+
export default {
19+
CHANNELS,
20+
};

components/sinch/package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pipedream/sinch",
3-
"version": "0.0.1",
3+
"version": "0.1.0",
44
"description": "Pipedream Sinch Components",
55
"main": "sinch.app.mjs",
66
"keywords": [
@@ -11,5 +11,9 @@
1111
"author": "Pipedream <support@pipedream.com> (https://pipedream.com/)",
1212
"publishConfig": {
1313
"access": "public"
14+
},
15+
"dependencies": {
16+
"@pipedream/platform": "^3.1.0",
17+
"form-data": "^4.0.4"
1418
}
15-
}
19+
}

components/sinch/sinch.app.mjs

Lines changed: 129 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,135 @@
1+
import { axios } from "@pipedream/platform";
2+
13
export default {
24
type: "app",
35
app: "sinch",
4-
propDefinitions: {},
6+
propDefinitions: {
7+
appId: {
8+
type: "string",
9+
label: "App ID",
10+
description: "The ID of an app",
11+
async options() {
12+
const { apps } = await this.listApps();
13+
return apps?.map(({
14+
id: value, display_name: label,
15+
}) => ({
16+
label,
17+
value,
18+
})) || [];
19+
},
20+
},
21+
contactId: {
22+
type: "string",
23+
label: "Contact ID",
24+
description: "The ID of a contact",
25+
async options({ prevContext }) {
26+
const {
27+
contacts, next_page_token: next,
28+
} = await this.listContacts({
29+
params: {
30+
page_token: prevContext?.nextPageToken,
31+
},
32+
});
33+
return {
34+
options: contacts?.map(({
35+
id: value, display_name: label,
36+
}) => ({
37+
label,
38+
value,
39+
})) || [],
40+
context: {
41+
nextPageToken: next,
42+
},
43+
};
44+
},
45+
},
46+
},
547
methods: {
6-
// this.$auth contains connected account data
7-
authKeys() {
8-
console.log(Object.keys(this.$auth));
48+
_getBaseUrl(api) {
49+
if (api === "conversation") {
50+
return `https://${this.$auth.region}.conversation.api.sinch.com/v1`;
51+
}
52+
if (api === "fax") {
53+
return "https://fax.api.sinch.com/v3";
54+
}
55+
},
56+
_makeRequest({
57+
$ = this, path, api = "conversation", headers, ...opts
58+
}) {
59+
return axios($, {
60+
url: `${this._getBaseUrl(api)}/projects/${this.$auth.project_id}${path}`,
61+
headers: {
62+
...headers,
63+
Authorization: `Bearer ${this.$auth.oauth_access_token}`,
64+
},
65+
...opts,
66+
});
67+
},
68+
createWebhook(opts = {}) {
69+
return this._makeRequest({
70+
method: "POST",
71+
api: "conversation",
72+
path: "/webhooks",
73+
...opts,
74+
});
75+
},
76+
deleteWebhook({
77+
webhookId, ...opts
78+
}) {
79+
return this._makeRequest({
80+
method: "DELETE",
81+
api: "conversation",
82+
path: `/webhooks/${webhookId}`,
83+
...opts,
84+
});
85+
},
86+
createService(opts = {}) {
87+
return this._makeRequest({
88+
method: "POST",
89+
api: "fax",
90+
path: "/services",
91+
...opts,
92+
});
93+
},
94+
deleteService({
95+
serviceId, ...opts
96+
}) {
97+
return this._makeRequest({
98+
method: "DELETE",
99+
api: "fax",
100+
path: `/services/${serviceId}`,
101+
...opts,
102+
});
103+
},
104+
listApps(opts = {}) {
105+
return this._makeRequest({
106+
api: "conversation",
107+
path: "/apps",
108+
...opts,
109+
});
110+
},
111+
listContacts(opts = {}) {
112+
return this._makeRequest({
113+
api: "conversation",
114+
path: "/contacts",
115+
...opts,
116+
});
117+
},
118+
sendMessage(opts = {}) {
119+
return this._makeRequest({
120+
method: "POST",
121+
api: "conversation",
122+
path: "/messages:send",
123+
...opts,
124+
});
125+
},
126+
sendFax(opts = {}) {
127+
return this._makeRequest({
128+
method: "POST",
129+
api: "fax",
130+
path: "/faxes",
131+
...opts,
132+
});
9133
},
10134
},
11-
};
135+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import sinch from "../../sinch.app.mjs";
2+
import { ConfigurationError } from "@pipedream/platform";
3+
4+
export default {
5+
props: {
6+
sinch,
7+
db: "$.service.db",
8+
http: "$.interface.http",
9+
},
10+
methods: {
11+
_getHookId() {
12+
return this.db.get("hookId");
13+
},
14+
_setHookId(hookId) {
15+
this.db.set("hookId", hookId);
16+
},
17+
generateMeta() {
18+
throw new ConfigurationError("generateMeta is not implemented");
19+
},
20+
},
21+
async run(event) {
22+
const { body } = event;
23+
if (!body) {
24+
return;
25+
}
26+
this.$emit(body, this.generateMeta(body));
27+
},
28+
};

0 commit comments

Comments
 (0)