diff --git a/components/tinyurl/actions/create-shortened-link/create-shortened-link.mjs b/components/tinyurl/actions/create-shortened-link/create-shortened-link.mjs new file mode 100644 index 0000000000000..01d013847387f --- /dev/null +++ b/components/tinyurl/actions/create-shortened-link/create-shortened-link.mjs @@ -0,0 +1,74 @@ +import { ConfigurationError } from "@pipedream/platform"; +import { parseObject } from "../../common/utils.mjs"; +import tinyurl from "../../tinyurl.app.mjs"; + +export default { + key: "tinyurl-create-shortened-link", + name: "Create Shortened Link", + description: "Creates a new shortened link. [See the documentation]()", + version: "0.0.1", + type: "action", + props: { + tinyurl, + url: { + propDefinition: [ + tinyurl, + "url", + ], + }, + domain: { + propDefinition: [ + tinyurl, + "domain", + ], + optional: true, + }, + alias: { + propDefinition: [ + tinyurl, + "alias", + ], + optional: true, + }, + tags: { + propDefinition: [ + tinyurl, + "tags", + ], + optional: true, + }, + expiresAt: { + propDefinition: [ + tinyurl, + "expiresAt", + ], + optional: true, + }, + description: { + type: "string", + label: "Description", + description: "The alias description", + optional: true, + }, + }, + async run({ $ }) { + try { + const response = await this.tinyurl.createTinyURL({ + $, + data: { + url: this.url, + domain: this.domain, + alias: this.alias, + tags: parseObject(this.tags)?.join(","), + expires_at: this.expiresAt, + description: this.description, + }, + }); + $.export("$summary", `Created TinyURL: ${response.data.tiny_url}`); + return response; + } catch ({ response }) { + throw new ConfigurationError(response?.data?.errors[0]); + } + }, +}; + diff --git a/components/tinyurl/actions/retrieve-link-analytics/retrieve-link-analytics.mjs b/components/tinyurl/actions/retrieve-link-analytics/retrieve-link-analytics.mjs new file mode 100644 index 0000000000000..dca5af02f93ca --- /dev/null +++ b/components/tinyurl/actions/retrieve-link-analytics/retrieve-link-analytics.mjs @@ -0,0 +1,67 @@ +import { ConfigurationError } from "@pipedream/platform"; +import tinyurl from "../../tinyurl.app.mjs"; + +export default { + key: "tinyurl-retrieve-link-analytics", + name: "Retrieve Link Analytics", + description: "Retrieves analytics for a specific TinyURL link, including total clicks, geographic breakdowns, and device types. [See the documentation]()", + version: "0.0.1", + type: "action", + props: { + tinyurl, + alert: { + type: "alert", + alertType: "info", + content: "This action is only allowed for paid accounts.", + }, + domain: { + propDefinition: [ + tinyurl, + "domain", + ], + }, + urls: { + propDefinition: [ + tinyurl, + "urls", + ({ domain }) => ({ + domain, + }), + ], + }, + from: { + type: "string", + label: "From", + description: "The start datetime of analitics report", + }, + to: { + type: "string", + label: "To", + description: "The end datetime of analitics report. Default is now", + optional: true, + }, + tag: { + type: "string", + label: "Tag", + description: "Tag to get analytics for", + optional: true, + }, + }, + async run({ $ }) { + try { + const analytics = await this.tinyurl.retrieveAnalytics({ + $, + params: { + from: this.from, + to: this.to, + alias: this.urls, + tag: this.tag, + }, + }); + $.export("$summary", `Retrieved analytics for link ${this.urls}`); + return analytics; + } catch ({ response }) { + throw new ConfigurationError(response?.data?.errors[0]); + } + }, +}; diff --git a/components/tinyurl/actions/update-link-metadata/update-link-metadata.mjs b/components/tinyurl/actions/update-link-metadata/update-link-metadata.mjs new file mode 100644 index 0000000000000..02a163c0506f5 --- /dev/null +++ b/components/tinyurl/actions/update-link-metadata/update-link-metadata.mjs @@ -0,0 +1,86 @@ +import { ConfigurationError } from "@pipedream/platform"; +import { parseObject } from "../../common/utils.mjs"; +import tinyurl from "../../tinyurl.app.mjs"; + +export default { + key: "tinyurl-update-link-metadata", + name: "Update Link Metadata", + description: "Updates the metadata of an existing TinyURL. [See the documentation]()", + version: "0.0.1", + type: "action", + props: { + tinyurl, + domain: { + propDefinition: [ + tinyurl, + "domain", + ], + }, + urls: { + propDefinition: [ + tinyurl, + "urls", + ({ domain }) => ({ + domain, + }), + ], + }, + newDomain: { + type: "string", + label: "New Domain", + description: "The new domain you would like to switch to", + optional: true, + }, + newAlias: { + type: "string", + label: "New Alias", + description: "The new alias you would like to switch to", + optional: true, + }, + newStats: { + type: "boolean", + label: "New Stats", + description: "Turns on/off the collection of click analytics", + optional: true, + }, + newTags: { + type: "string[]", + label: "New Tags", + description: "Tags you would like this TinyURL to have. Overwrites the existing tags. **Paid accounts only**", + optional: true, + }, + newExpiresAt: { + type: "string", + label: "New Expires At", + description: "TinyURL expiration in ISO8601 format. If not set so TinyURL never expires, **Paid accounts only**", + optional: true, + }, + newDescription: { + type: "string", + label: "New Description", + description: "The new description", + optional: true, + }, + }, + async run({ $ }) { + try { + const response = await this.tinyurl.updateTinyURLMetadata({ + $, + data: { + domain: this.domain, + alias: this.urls, + new_domain: this.newDomain, + new_alias: this.newAlias, + new_stats: this.newStats, + new_tags: parseObject(this.newTags), + new_expires_at: this.newExpiresAt, + new_description: this.newDescription, + }, + }); + $.export("$summary", `Updated TinyURL metadata for link: ${response.data.tiny_url}`); + return response; + } catch ({ response }) { + throw new ConfigurationError(response?.data?.errors[0]); + } + }, +}; diff --git a/components/tinyurl/common/utils.mjs b/components/tinyurl/common/utils.mjs new file mode 100644 index 0000000000000..dcc9cc61f6f41 --- /dev/null +++ b/components/tinyurl/common/utils.mjs @@ -0,0 +1,24 @@ +export const parseObject = (obj) => { + if (!obj) return undefined; + + if (Array.isArray(obj)) { + return obj.map((item) => { + if (typeof item === "string") { + try { + return JSON.parse(item); + } catch (e) { + return item; + } + } + return item; + }); + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + return obj; +}; diff --git a/components/tinyurl/package.json b/components/tinyurl/package.json new file mode 100644 index 0000000000000..690e2e46fb9ae --- /dev/null +++ b/components/tinyurl/package.json @@ -0,0 +1,18 @@ +{ + "name": "@pipedream/tinyurl", + "version": "0.1.0", + "description": "Pipedream TinyURL Components", + "main": "tinyurl.app.mjs", + "keywords": [ + "pipedream", + "tinyurl" + ], + "homepage": "https://pipedream.com/apps/tinyurl", + "author": "Pipedream (https://pipedream.com/)", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" + } +} diff --git a/components/tinyurl/sources/new-link-created/new-link-created.mjs b/components/tinyurl/sources/new-link-created/new-link-created.mjs new file mode 100644 index 0000000000000..3b711c45ee90a --- /dev/null +++ b/components/tinyurl/sources/new-link-created/new-link-created.mjs @@ -0,0 +1,62 @@ +import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform"; +import tinyurl from "../../tinyurl.app.mjs"; + +export default { + key: "tinyurl-new-link-created", + name: "New Shortened URL Created", + description: "Emit new event when a new shortened URL is created.", + version: "0.0.1", + type: "source", + dedupe: "unique", + props: { + tinyurl, + db: "$.service.db", + timer: { + type: "$.interface.timer", + default: { + intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL, + }, + }, + }, + methods: { + _getLastDate() { + return this.db.get("lastDate") || 0; + }, + _setLastDate(lastDate) { + this.db.set("lastDate", lastDate); + }, + async emitEvent(maxResults = false) { + const lastDate = this._getLastDate(); + + const { data } = await this.tinyurl.listURLs({ + type: "available", + params: { + from: lastDate, + }, + }); + + if (data.length) { + if (maxResults && (data.length > maxResults)) { + data.length = maxResults; + } + this._setLastDate(data[0].created_at); + } + + for (const item of data.reverse()) { + this.$emit(item, { + id: item.alias, + summary: `New TinyURL: ${item.tiny_url}`, + ts: Date.parse(item.created_at), + }); + } + }, + }, + hooks: { + async deploy() { + await this.emitEvent(25); + }, + }, + async run() { + await this.emitEvent(); + }, +}; diff --git a/components/tinyurl/tinyurl.app.mjs b/components/tinyurl/tinyurl.app.mjs index 1abdae8ba38be..4829e0381fae9 100644 --- a/components/tinyurl/tinyurl.app.mjs +++ b/components/tinyurl/tinyurl.app.mjs @@ -1,11 +1,100 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "tinyurl", - propDefinitions: {}, + propDefinitions: { + urls: { + type: "string", + label: "Alias", + description: "The existing alias for this TinyURL", + async options({ domain }) { + const { data } = await this.listURLs({ + type: "available", + }); + + return data + .filter((alias) => alias.domain === domain) + .map(({ + alias: value, tiny_url: label, + }) => ({ + label, + value, + })); + }, + }, + url: { + type: "string", + label: "URL", + description: "The long URL that will be shortened", + }, + domain: { + type: "string", + label: "Domain", + description: "The domain you would like the TinyURL to use. Select from TinyURL free domain tinyurl.com or subscribe and use TinyURL branded domains.", + default: "tinyurl.com", + }, + alias: { + type: "string", + label: "Custom Alias", + description: "A short string of characters to use in the TinyURL. If ommitted, one will be randomly generated. When using a branded domain, this has a minimum length of 1 character.", + optional: true, + }, + expiresAt: { + type: "string", + label: "Expires At", + description: "TinyURL expiration in ISO8601 format. If not set so TinyURL never expires. **Example: 2024-10-25 10:11:12**. **Paid accounts only**", + optional: true, + }, + tags: { + type: "string[]", + label: "Tags", + description: "Tags group and categorize TinyURLs together. **Paid accounts only**", + optional: true, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.tinyurl.com"; + }, + _headers() { + return { + "Authorization": `Bearer ${this.$auth.api_token}`, + "Content-Type": "application/json", + }; + }, + _makeRequest({ + $ = this, path, ...opts + }) { + const config = { + url: this._baseUrl() + path, + headers: this._headers(), + ...opts, + }; + console.log("config: ", config); + return axios($, config); + }, + createTinyURL(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/create", + ...opts, + }); + }, + updateTinyURLMetadata(opts = {}) { + return this._makeRequest({ + method: "PATCH", + path: "/update", + ...opts, + }); + }, + listURLs({ + type, ...opts + }) { + return this._makeRequest({ + path: `/urls/${type}`, + opts, + }); }, }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f5858a965ed2..77ec6b8ffe131 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -292,8 +292,7 @@ importers: specifier: ^3.0.1 version: 3.0.3 - components/adobe_document_generation_api: - specifiers: {} + components/adobe_document_generation_api: {} components/adobe_pdf_services: dependencies: @@ -10501,8 +10500,7 @@ importers: components/syncro: {} - components/synthflow: - specifiers: {} + components/synthflow: {} components/t2m_url_shortener: {} @@ -10915,6 +10913,12 @@ importers: specifier: ^0.12.5 version: 0.12.5 + components/tinyurl: + dependencies: + '@pipedream/platform': + specifier: ^3.0.3 + version: 3.0.3 + components/tisane_labs: dependencies: '@pipedream/platform': @@ -31754,6 +31758,8 @@ snapshots: '@putout/operator-filesystem': 5.0.0(putout@36.13.1(eslint@8.57.1)(typescript@5.6.3)) '@putout/operator-json': 2.2.0 putout: 36.13.1(eslint@8.57.1)(typescript@5.6.3) + transitivePeerDependencies: + - supports-color '@putout/operator-regexp@1.0.0(putout@36.13.1(eslint@8.57.1)(typescript@5.6.3))': dependencies: