diff --git a/components/smartsuite/.gitignore b/components/smartsuite/.gitignore deleted file mode 100644 index ec761ccab7595..0000000000000 --- a/components/smartsuite/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.js -*.mjs -dist \ No newline at end of file diff --git a/components/smartsuite/actions/create-record/create-record.mjs b/components/smartsuite/actions/create-record/create-record.mjs new file mode 100644 index 0000000000000..bd49af35ab414 --- /dev/null +++ b/components/smartsuite/actions/create-record/create-record.mjs @@ -0,0 +1,66 @@ +import smartsuite from "../../smartsuite.app.mjs"; + +export default { + key: "smartsuite-create-record", + name: "Create Record", + description: "Creates a new record. [See the documentation](https://developers.smartsuite.com/docs/solution-data/records/create-record)", + version: "0.0.1", + type: "action", + props: { + smartsuite, + tableId: { + propDefinition: [ + smartsuite, + "tableId", + ], + reloadProps: true, + }, + }, + async additionalProps() { + const props = {}; + if (!this.tableId) { + return props; + } + const { structure: fields } = await this.smartsuite.listFields({ + tableId: this.tableId, + }); + for (const field of fields) { + if (!field.params.is_auto_generated + && !field.params.system + && field.field_type !== "linkedrecordfield" + && field.field_type !== "filefield" + && field.field_type !== "userfield" + ) { + props[field.slug] = { + type: "string", + label: field.label, + optional: !field.params.required, + options: field.params.choices + ? field.params.choices.map(({ + value, label, + }) => ({ + value, + label, + })) + : undefined, + }; + } + } + return props; + }, + async run({ $ }) { + const { + smartsuite, + tableId, + ...data + } = this; + + const response = await smartsuite.createRecord({ + $, + tableId, + data, + }); + $.export("$summary", `Successfully created record with ID: ${response.id}`); + return response; + }, +}; diff --git a/components/smartsuite/actions/find-records/find-records.mjs b/components/smartsuite/actions/find-records/find-records.mjs new file mode 100644 index 0000000000000..ed69c6de3af56 --- /dev/null +++ b/components/smartsuite/actions/find-records/find-records.mjs @@ -0,0 +1,70 @@ +import smartsuite from "../../smartsuite.app.mjs"; + +export default { + key: "smartsuite-find-records", + name: "Find Records", + description: "Search for records based on matching field(s). [See the documentation](https://developers.smartsuite.com/docs/solution-data/records/list-records)", + version: "0.0.1", + type: "action", + props: { + smartsuite, + tableId: { + propDefinition: [ + smartsuite, + "tableId", + ], + }, + fieldIds: { + propDefinition: [ + smartsuite, + "fieldIds", + (c) => ({ + tableId: c.tableId, + }), + ], + reloadProps: true, + }, + }, + async additionalProps() { + const props = {}; + if (!this.tableId || !this.fieldIds?.length) { + return props; + } + const { structure: fields } = await this.smartsuite.listFields({ + tableId: this.tableId, + }); + for (const fieldId of this.fieldIds) { + const field = fields.find(({ slug }) => slug === fieldId); + props[fieldId] = { + type: "string", + label: field.label, + }; + } + return props; + }, + async run({ $ }) { + const fields = this.fieldIds?.length + ? this.fieldIds.map((field) => ({ + comparison: "is", + field, + value: this[field], + })) + : undefined; + const { items } = await this.smartsuite.listRecords({ + $, + tableId: this.tableId, + data: { + filter: { + operator: "and", + fields, + }, + }, + }); + if (items?.length) { + $.export("$summary", `Successfully found ${items.length} record${items.length === 1 + ? "" + : "s"}`); + } + return items; + }, +}; diff --git a/components/smartsuite/app/smartsuite.app.ts b/components/smartsuite/app/smartsuite.app.ts deleted file mode 100644 index c025f3008e762..0000000000000 --- a/components/smartsuite/app/smartsuite.app.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { defineApp } from "@pipedream/types"; - -export default defineApp({ - type: "app", - app: "smartsuite", - propDefinitions: {}, - methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); - }, - }, -}); \ No newline at end of file diff --git a/components/smartsuite/package.json b/components/smartsuite/package.json index 9808f0cd5001b..97321cd418ca0 100644 --- a/components/smartsuite/package.json +++ b/components/smartsuite/package.json @@ -1,16 +1,18 @@ { "name": "@pipedream/smartsuite", - "version": "0.0.2", + "version": "0.1.0", "description": "Pipedream SmartSuite Components", - "main": "dist/app/smartsuite.app.mjs", + "main": "smartsuite.app.mjs", "keywords": [ "pipedream", "smartsuite" ], - "files": ["dist"], "homepage": "https://pipedream.com/apps/smartsuite", "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } } diff --git a/components/smartsuite/smartsuite.app.mjs b/components/smartsuite/smartsuite.app.mjs new file mode 100644 index 0000000000000..c5b46ee0b6ebb --- /dev/null +++ b/components/smartsuite/smartsuite.app.mjs @@ -0,0 +1,145 @@ +import { axios } from "@pipedream/platform"; +const DEFAULT_LIMIT = 50; + +export default { + type: "app", + app: "smartsuite", + propDefinitions: { + tableId: { + type: "string", + label: "Table ID", + description: "The identifier of a table", + async options({ page }) { + const { results: tables } = await this.listTables({ + params: { + limit: DEFAULT_LIMIT, + offset: page * DEFAULT_LIMIT, + }, + }); + return tables?.map(({ + id: value, name: label, + }) => ({ + value, + label, + })) || []; + }, + }, + fieldIds: { + type: "string[]", + label: "Field IDs", + description: "The field ID(s) (\"slug\") to search by", + optional: true, + async options({ tableId }) { + const { structure: fields } = await this.listFields({ + tableId, + }); + return fields?.map(({ + slug: value, label, + }) => ({ + value, + label, + })) || []; + }, + }, + solutionId: { + type: "string", + label: "Solution ID", + description: "The identifier of a solution", + async options() { + const solutions = await this.listSolutions(); + return solutions?.map(({ + id: value, name: label, + }) => ({ + value, + label, + })) || []; + }, + }, + }, + methods: { + _baseUrl() { + return "https://app.smartsuite.com/api/v1"; + }, + _baseWebhookUrl() { + return "https://webhooks.smartsuite.com/smartsuite.webhooks.engine.Webhooks"; + }, + _headers() { + return { + "Authorization": `Token ${this.$auth.api_token}`, + "ACCOUNT-ID": `${this.$auth.account_id}`, + "Content-Type": "application/json", + }; + }, + _makeRequest({ + $ = this, + url, + path, + ...opts + }) { + return axios($, { + url: url || `${this._baseUrl()}${path}`, + headers: this._headers(), + ...opts, + }); + }, + createWebhook(opts = {}) { + return this._makeRequest({ + method: "POST", + url: `${this._baseWebhookUrl()}/CreateWebhook`, + ...opts, + }); + }, + deleteWebhook(opts = {}) { + return this._makeRequest({ + method: "POST", + url: `${this._baseWebhookUrl()}/DeleteWebhook`, + ...opts, + }); + }, + listWebhookEvents(opts = {}) { + return this._makeRequest({ + method: "POST", + url: `${this._baseWebhookUrl()}/ListEvents`, + ...opts, + }); + }, + listTables(opts = {}) { + return this._makeRequest({ + path: "/applications", + ...opts, + }); + }, + listSolutions(opts = {}) { + return this._makeRequest({ + path: "/solutions", + ...opts, + }); + }, + listFields({ + tableId, ...opts + }) { + return this._makeRequest({ + path: `/applications/${tableId}`, + ...opts, + }); + }, + listRecords({ + tableId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/applications/${tableId}/records/list/`, + ...opts, + }); + }, + createRecord({ + tableId, ...opts + }) { + return this._makeRequest({ + method: "POST", + path: `/applications/${tableId}/records/`, + ...opts, + }); + }, + }, +}; diff --git a/components/smartsuite/sources/common/base.mjs b/components/smartsuite/sources/common/base.mjs new file mode 100644 index 0000000000000..0aa060f46bdae --- /dev/null +++ b/components/smartsuite/sources/common/base.mjs @@ -0,0 +1,102 @@ +import smartsuite from "../../smartsuite.app.mjs"; + +export default { + props: { + smartsuite, + db: "$.service.db", + http: "$.interface.http", + solutionId: { + propDefinition: [ + smartsuite, + "solutionId", + ], + }, + }, + hooks: { + async activate() { + const { webhook: { webhook_id: hookId } } = await this.smartsuite.createWebhook({ + data: { + webhook: { + filter: { + solution: {}, + }, + kinds: [ + this.getEventType(), + ], + locator: { + account_id: this.smartsuite.$auth.account_id, + solution_id: this.solutionId, + }, + notification_status: { + enabled: { + url: this.http.endpoint, + }, + }, + }, + }, + }); + this._setHookId(hookId); + }, + async deactivate() { + const hookId = this._getHookId(); + if (hookId) { + await this.smartsuite.deleteWebhook({ + data: { + webhook_id: hookId, + }, + }); + } + }, + }, + methods: { + _getHookId() { + return this.db.get("hookId"); + }, + _setHookId(hookId) { + this.db.set("hookId", hookId); + }, + _getPageToken() { + return this.db.get("pageToken"); + }, + _setPageToken(pageToken) { + this.db.set("pageToken", pageToken); + }, + generateMeta(event) { + return { + id: event.event_id, + summary: this.getSummary(event), + ts: Date.parse(event.event_at), + }; + }, + getEventType() { + throw new Error("getEventType is not implemented"); + }, + getSummary() { + throw new Error("getSummary is not implemented"); + }, + }, + async run() { + const hookId = this._getHookId(); + const pageToken = this._getPageToken(); + + const { + events, next_page_token: nextPageToken, + } = await this.smartsuite.listWebhookEvents({ + data: { + webhook_id: hookId, + page_token: pageToken, + }, + }); + + this._setPageToken(nextPageToken); + + if (!events?.length) { + return; + } + + events.forEach((event) => { + const meta = this.generateMeta(event); + this.$emit(event, meta); + }); + }, +}; diff --git a/components/smartsuite/sources/new-record-created-instant/new-record-created-instant.mjs b/components/smartsuite/sources/new-record-created-instant/new-record-created-instant.mjs new file mode 100644 index 0000000000000..08e2ea1e249c8 --- /dev/null +++ b/components/smartsuite/sources/new-record-created-instant/new-record-created-instant.mjs @@ -0,0 +1,22 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "smartsuite-new-record-created-instant", + name: "New Record Created (Instant)", + description: "Emit new event when a new record is created", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return "RECORD_CREATED"; + }, + getSummary({ record_event_data: data }) { + return `New record created with ID: ${data.record_id}`; + }, + }, + sampleEmit, +}; diff --git a/components/smartsuite/sources/new-record-created-instant/test-event.mjs b/components/smartsuite/sources/new-record-created-instant/test-event.mjs new file mode 100644 index 0000000000000..759834836f3a7 --- /dev/null +++ b/components/smartsuite/sources/new-record-created-instant/test-event.mjs @@ -0,0 +1,79 @@ +export default { + "webhook_id": "2f7cc6e0-b709-4b04-964a-3706c89c78e3", + "locator": { + "account_id": "WORKSPACE_ID", + "solution_id": "63b87cad645b3949631b55bf", + }, + "event_id": "2f7cc6e0-b709-4b04-964a-3706c89c78e3.994", + "kind": "RECORD_CREATED", + "event_at": "2023-06-21T21:14:06.263Z", + "record_event_data": { + "record_id": "6493681eba09b400816eb754", + "locator": { + "account_id": "WORKSPACE_ID", + "solution_id": "63b87cad645b3949631b55bf", + "application_id": "63b87cad645b3949631b55c1", + }, + "data": { + "last_updated": { + "on": "2023-06-21T21:14:06.247000Z", + "by": "63a1f65723aaf6bcb564b1f1", + }, + "due_date": { + "is_overdue": false, + "status_updated_on": "2023-06-21T21:14:06.248000Z", + "from_date": { + "date": null, + "include_time": false, + }, + "to_date": { + "date": null, + "include_time": false, + }, + "status_is_completed": false, + }, + "description": { + "data": { + "type": "doc", + "content": [], + }, + "preview": "", + "html": "
\n \n
", + }, + "deleted_by": null, + "title": "test", + "priority": "", + "application_id": "63b87cad645b3949631b55c1", + "followed_by": [], + "application_slug": "ssb9kaxn", + "deleted_date": { + "date": null, + "include_time": false, + }, + "comments_count": 0, + "autonumber": 2, + "ranking": { + "default": "aagckvkhyq", + }, + "id": "6493681eba09b400816eb754", + "first_created": { + "on": "2023-06-21T21:14:06.247000Z", + "by": "63a1f65723aaf6bcb564b1f1", + }, + "assigned_to": [], + "status": { + "updated_on": "2023-06-21T21:14:06.248000Z", + "value": "backlog", + }, + }, + "previous": {}, + }, + "ctx": { + "change_id": "ba1ffa93-0c51-48ab-aff2-64d9128d6c35", + "change_size": 1, + "batch_id": "65832e55206fdfd247b84abd", + "batch_size": 1, + "source": "UNKNOWN", + "handler": "INTERACTIVE", + }, +}; diff --git a/components/smartsuite/sources/record-updated-instant/record-updated-instant.mjs b/components/smartsuite/sources/record-updated-instant/record-updated-instant.mjs new file mode 100644 index 0000000000000..97dfe46577e61 --- /dev/null +++ b/components/smartsuite/sources/record-updated-instant/record-updated-instant.mjs @@ -0,0 +1,22 @@ +import common from "../common/base.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "smartsuite-record-updated-instant", + name: "Record Updated (Instant)", + description: "Emit new event when an existing record is updated", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEventType() { + return "RECORD_UPDATED"; + }, + getSummary({ record_event_data: data }) { + return `Record updated with ID: ${data.record_id}`; + }, + }, + sampleEmit, +}; diff --git a/components/smartsuite/sources/record-updated-instant/test-event.mjs b/components/smartsuite/sources/record-updated-instant/test-event.mjs new file mode 100644 index 0000000000000..35918dfb6e395 --- /dev/null +++ b/components/smartsuite/sources/record-updated-instant/test-event.mjs @@ -0,0 +1,79 @@ +export default { + "webhook_id": "2f7cc6e0-b709-4b04-964a-3706c89c78e3", + "locator": { + "account_id": "WORKSPACE_ID", + "solution_id": "63b87cad645b3949631b55bf", + }, + "event_id": "2f7cc6e0-b709-4b04-964a-3706c89c78e3.994", + "kind": "RECORD_UPDATED", + "event_at": "2023-06-21T21:14:06.263Z", + "record_event_data": { + "record_id": "6493681eba09b400816eb754", + "locator": { + "account_id": "WORKSPACE_ID", + "solution_id": "63b87cad645b3949631b55bf", + "application_id": "63b87cad645b3949631b55c1", + }, + "data": { + "last_updated": { + "on": "2023-06-21T21:14:06.247000Z", + "by": "63a1f65723aaf6bcb564b1f1", + }, + "due_date": { + "is_overdue": false, + "status_updated_on": "2023-06-21T21:14:06.248000Z", + "from_date": { + "date": null, + "include_time": false, + }, + "to_date": { + "date": null, + "include_time": false, + }, + "status_is_completed": false, + }, + "description": { + "data": { + "type": "doc", + "content": [], + }, + "preview": "", + "html": "
\n \n
", + }, + "deleted_by": null, + "title": "test", + "priority": "", + "application_id": "63b87cad645b3949631b55c1", + "followed_by": [], + "application_slug": "ssb9kaxn", + "deleted_date": { + "date": null, + "include_time": false, + }, + "comments_count": 0, + "autonumber": 2, + "ranking": { + "default": "aagckvkhyq", + }, + "id": "6493681eba09b400816eb754", + "first_created": { + "on": "2023-06-21T21:14:06.247000Z", + "by": "63a1f65723aaf6bcb564b1f1", + }, + "assigned_to": [], + "status": { + "updated_on": "2023-06-21T21:14:06.248000Z", + "value": "backlog", + }, + }, + "previous": {}, + }, + "ctx": { + "change_id": "ba1ffa93-0c51-48ab-aff2-64d9128d6c35", + "change_size": 1, + "batch_id": "65832e55206fdfd247b84abd", + "batch_size": 1, + "source": "UNKNOWN", + "handler": "INTERACTIVE", + }, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fa0a44c2d4641..0492d8f671da1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9187,7 +9187,10 @@ importers: '@pipedream/platform': 1.5.1 components/smartsuite: - specifiers: {} + specifiers: + '@pipedream/platform': ^3.0.3 + dependencies: + '@pipedream/platform': 3.0.3 components/smarty: specifiers: {} @@ -12949,6 +12952,55 @@ packages: - aws-crt dev: false + /@aws-sdk/client-sso-oidc/3.600.0_tdq3komn4zwyd65w7klbptsu34: + resolution: {integrity: sha512-7+I8RWURGfzvChyNQSyj5/tKrqRbzRl7H+BnTOf/4Vsw1nFOi5ROhlhD4X/Y0QCTacxnaoNcIrqnY7uGGvVRzw==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/core': 3.598.0 + '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@smithy/config-resolver': 3.0.3 + '@smithy/core': 2.2.3 + '@smithy/fetch-http-handler': 3.2.1 + '@smithy/hash-node': 3.0.2 + '@smithy/invalid-dependency': 3.0.2 + '@smithy/middleware-content-length': 3.0.2 + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/middleware-retry': 3.0.6 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.3 + '@smithy/node-http-handler': 3.1.2 + '@smithy/protocol-http': 4.0.3 + '@smithy/smithy-client': 3.1.6 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.6 + '@smithy/util-defaults-mode-node': 3.0.6 + '@smithy/util-endpoints': 2.0.3 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.2 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + transitivePeerDependencies: + - '@aws-sdk/client-sts' + - aws-crt + dev: false + /@aws-sdk/client-sso/3.423.0: resolution: {integrity: sha512-znIufHkwhCIePgaYciIs3x/+BpzR57CZzbCKHR9+oOvGyufEPPpUT5bFLvbwTgfiVkTjuk6sG/ES3U5Bc+xtrA==} engines: {node: '>=14.0.0'} @@ -13184,7 +13236,7 @@ packages: dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.600.0 + '@aws-sdk/client-sso-oidc': 3.600.0_tdq3komn4zwyd65w7klbptsu34 '@aws-sdk/core': 3.598.0 '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 '@aws-sdk/middleware-host-header': 3.598.0 @@ -13226,55 +13278,6 @@ packages: - aws-crt dev: false - /@aws-sdk/client-sts/3.600.0_dseaa2p5u2yk67qiepewcq3hkq: - resolution: {integrity: sha512-KQG97B7LvTtTiGmjlrG1LRAY8wUvCQzrmZVV5bjrJ/1oXAU7DITYwVbSJeX9NWg6hDuSk0VE3MFwIXS2SvfLIA==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-crypto/sha256-browser': 5.2.0 - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-sso-oidc': 3.600.0 - '@aws-sdk/core': 3.598.0 - '@aws-sdk/credential-provider-node': 3.600.0_f7n47caigsrjd2lr2szmwfuee4 - '@aws-sdk/middleware-host-header': 3.598.0 - '@aws-sdk/middleware-logger': 3.598.0 - '@aws-sdk/middleware-recursion-detection': 3.598.0 - '@aws-sdk/middleware-user-agent': 3.598.0 - '@aws-sdk/region-config-resolver': 3.598.0 - '@aws-sdk/types': 3.598.0 - '@aws-sdk/util-endpoints': 3.598.0 - '@aws-sdk/util-user-agent-browser': 3.598.0 - '@aws-sdk/util-user-agent-node': 3.598.0 - '@smithy/config-resolver': 3.0.3 - '@smithy/core': 2.2.3 - '@smithy/fetch-http-handler': 3.2.1 - '@smithy/hash-node': 3.0.2 - '@smithy/invalid-dependency': 3.0.2 - '@smithy/middleware-content-length': 3.0.2 - '@smithy/middleware-endpoint': 3.0.4 - '@smithy/middleware-retry': 3.0.6 - '@smithy/middleware-serde': 3.0.3 - '@smithy/middleware-stack': 3.0.3 - '@smithy/node-config-provider': 3.1.3 - '@smithy/node-http-handler': 3.1.2 - '@smithy/protocol-http': 4.0.3 - '@smithy/smithy-client': 3.1.6 - '@smithy/types': 3.3.0 - '@smithy/url-parser': 3.0.3 - '@smithy/util-base64': 3.0.0 - '@smithy/util-body-length-browser': 3.0.0 - '@smithy/util-body-length-node': 3.0.0 - '@smithy/util-defaults-mode-browser': 3.0.6 - '@smithy/util-defaults-mode-node': 3.0.6 - '@smithy/util-endpoints': 2.0.3 - '@smithy/util-middleware': 3.0.3 - '@smithy/util-retry': 3.0.2 - '@smithy/util-utf8': 3.0.0 - tslib: 2.6.3 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - dev: false - /@aws-sdk/core/3.556.0: resolution: {integrity: sha512-vJaSaHw2kPQlo11j/Rzuz0gk1tEaKdz+2ser0f0qZ5vwFlANjt08m/frU17ctnVKC1s58bxpctO/1P894fHLrA==} engines: {node: '>=14.0.0'} @@ -17601,7 +17604,7 @@ packages: '@aws-sdk/client-sns': 3.423.0 '@aws-sdk/client-sqs': 3.423.0 '@aws-sdk/client-ssm': 3.423.0 - '@aws-sdk/client-sts': 3.600.0_dseaa2p5u2yk67qiepewcq3hkq + '@aws-sdk/client-sts': 3.600.0 '@aws-sdk/s3-request-presigner': 3.609.0 '@pipedream/helper_functions': 0.3.12 '@pipedream/platform': 1.6.6