diff --git a/components/inmobile/actions/send-sms-messages/send-sms-messages.mjs b/components/inmobile/actions/send-sms-messages/send-sms-messages.mjs new file mode 100644 index 0000000000000..15d02f7f64829 --- /dev/null +++ b/components/inmobile/actions/send-sms-messages/send-sms-messages.mjs @@ -0,0 +1,73 @@ +import app from "../../inmobile.app.mjs"; +import utils from "../../common/utils.mjs"; + +export default { + key: "inmobile-send-sms-messages", + name: "Send SMS Messages", + description: "Send one or more SMS messages using the InMobile API. [See the documentation](https://www.inmobile.com/docs/rest-api)", + version: "0.0.1", + type: "action", + annotations: { + readOnlyHint: false, + destructiveHint: true, + openWorldHint: true, + }, + props: { + app, + messages: { + type: "string[]", + label: "Messages", + description: `An array of message objects (1-250 messages). Each message object supports the following properties: + +**Required Fields:** +- \`to\` (string): The msisdn (country code and number) to send to. Remember to include country code, e.g. \`4512345678\` +- \`text\` (string): The text message (1-10000 characters) +- \`from\` (string): The sender. Can be a 3-11 character text sender or up to 14 digit sender number + +**Optional Fields:** +- \`countryHint\` (string): Country code for optimal phone number validation, e.g. \`44\` or \`GB\` +- \`messageId\` (string): Optional message ID to identify the message (1-50 characters, must be unique) +- \`respectBlacklist\` (boolean): Block message if target number is blacklisted. Default: \`true\` +- \`validityPeriodInSeconds\` (integer): Validity period (60-172800 seconds). Default: \`172800\` (48 hours) +- \`statusCallbackUrl\` (string): URL for delivery status callbacks +- \`sendTime\` (string): Schedule message for future sending, e.g. \`2024-12-31T14:50:23Z\` (UTC time) +- \`msisdnCooldownInMinutes\` (integer): Prevent sending to same number within period (60-43200 minutes) +- \`flash\` (boolean): Send as flash message (class0). Default: \`false\` +- \`encoding\` (string): Message encoding - \`gsm7\` (default, 160 chars), \`ucs2\` (70 chars), or \`auto\` + +**Example:** +\`\`\`json +[ + { + "to": "4512345678", + "text": "Hello World", + "from": "YourSender", + "encoding": "gsm7" + }, + { + "to": "4587654321", + "text": "Another message", + "from": "YourSender", + "flash": true + } +] +\`\`\``, + }, + }, + async run({ $ }) { + const { + app, + messages, + } = this; + + const response = await app.sendSms({ + $, + data: { + messages: utils.parseArray(messages), + }, + }); + + $.export("$summary", "Successfully sent SMS messages"); + return response; + }, +}; diff --git a/components/inmobile/common/utils.mjs b/components/inmobile/common/utils.mjs new file mode 100644 index 0000000000000..741295400be78 --- /dev/null +++ b/components/inmobile/common/utils.mjs @@ -0,0 +1,68 @@ +const parseJson = (input, maxDepth = 100) => { + const seen = new WeakSet(); + const parse = (value) => { + if (maxDepth <= 0) { + return value; + } + if (typeof(value) === "string") { + // Only parse if the string looks like a JSON object or array + const trimmed = value.trim(); + if ( + (trimmed.startsWith("{") && trimmed.endsWith("}")) || + (trimmed.startsWith("[") && trimmed.endsWith("]")) + ) { + try { + return parseJson(JSON.parse(value), maxDepth - 1); + } catch (e) { + return value; + } + } + return value; + } else if (typeof(value) === "object" && value !== null && !Array.isArray(value)) { + if (seen.has(value)) { + return value; + } + seen.add(value); + return Object.entries(value) + .reduce((acc, [ + key, + val, + ]) => Object.assign(acc, { + [key]: parse(val), + }), {}); + } else if (Array.isArray(value)) { + return value.map((item) => parse(item)); + } + return value; + }; + + return parse(input); +}; + +function parseArray(input, maxDepth = 100) { + if (typeof input === "string") { + const trimmed = input.trim(); + if (trimmed.startsWith("[") && trimmed.endsWith("]")) { + try { + const parsed = JSON.parse(trimmed); + if (Array.isArray(parsed)) { + return parsed.map((item) => parseArray(item, maxDepth - 1)); + } + } catch (e) { + throw new Error(`Invalid JSON array format: ${e.message}`); + } + } + return parseJson(input, maxDepth); + } + + if (Array.isArray(input)) { + return input.map((item) => parseArray(item, maxDepth)); + } + + return input; +} + +export default { + parseJson, + parseArray, +}; diff --git a/components/inmobile/inmobile.app.mjs b/components/inmobile/inmobile.app.mjs index dea1cf6133cf1..2d481ffde5223 100644 --- a/components/inmobile/inmobile.app.mjs +++ b/components/inmobile/inmobile.app.mjs @@ -1,11 +1,38 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "inmobile", - propDefinitions: {}, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + getUrl(path) { + return `https://api.inmobile.com/v4${path}`; + }, + getAuth() { + return { + username: "x", + password: this.$auth.api_key, + }; + }, + makeRequest({ + $ = this, path, ...args + }) { + return axios($, { + url: this.getUrl(path), + auth: this.getAuth(), + ...args, + }); + }, + post(args = {}) { + return this.makeRequest({ + method: "POST", + ...args, + }); + }, + sendSms(args = {}) { + return this.post({ + path: "/sms/outgoing", + ...args, + }); }, }, }; diff --git a/components/inmobile/package.json b/components/inmobile/package.json index 7197bea82766e..8b155ecedf45f 100644 --- a/components/inmobile/package.json +++ b/components/inmobile/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/inmobile", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream InMobile Components", "main": "inmobile.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.1.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3833634c633c6..aa164dc7b7030 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7135,7 +7135,11 @@ importers: specifier: ^1.2.0 version: 1.6.6 - components/inmobile: {} + components/inmobile: + dependencies: + '@pipedream/platform': + specifier: ^3.1.0 + version: 3.1.0 components/inoreader: dependencies: