From 79021b7bc73a0cec2d21a83f810ef336adcae832 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Fri, 7 Mar 2025 15:08:06 -0500 Subject: [PATCH 1/4] new bulk-import action --- .../actions/bulk-import/bulk-import.mjs | 139 ++++++++++++++++++ components/shopify/package.json | 3 +- 2 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 components/shopify/actions/bulk-import/bulk-import.mjs diff --git a/components/shopify/actions/bulk-import/bulk-import.mjs b/components/shopify/actions/bulk-import/bulk-import.mjs new file mode 100644 index 0000000000000..fa9c9dcd12f12 --- /dev/null +++ b/components/shopify/actions/bulk-import/bulk-import.mjs @@ -0,0 +1,139 @@ +import shopify from "../../shopify.app.mjs"; +import { axios } from "@pipedream/platform"; +import fs from "fs"; +import FormData from "form-data"; + +export default { + key: "shopify-bulk-import", + name: "Bulk Import", + description: "Add tags. [See the documentation](https://shopify.dev/docs/api/admin-graphql/latest/mutations/bulkoperationrunmutation)", + version: "0.0.1", + type: "action", + props: { + shopify, + alert: { + type: "alert", + alertType: "info", + content: "Use the Shopify trigger \"New Event Emitted (Instant)\" with event type `bulk_operations/finish` to receive notifications when bulk imports are completed", + }, + mutation: { + type: "string", + label: "Mutation", + description: "The mutation to be executed in bulk. [See the documentation](https://shopify.dev/docs/api/usage/bulk-operations/imports) for a list of supported mutations. Example: `mutation call($input: ProductInput!) { productCreate(input: $input) { product { id title } } }`", + }, + filePath: { + type: "string", + label: "File Path", + description: "File path in the `/tmp` directory of a JSONL file including the variables for the mutation. Each line in the JSONL file represents one input unit. The mutation runs once on each line of the input file. [See the documentation](https://shopify.dev/docs/api/usage/bulk-operations/imports) for more information.", + }, + clientIdentifier: { + type: "string", + label: "Client Identifier", + description: "An optional identifier which may be used for querying", + optional: true, + }, + }, + methods: { + stagedUploadQuery() { + return ` + mutation stagedUploadsCreate($input: [StagedUploadInput!]!) { + stagedUploadsCreate(input: $input) { + stagedTargets { + url + resourceUrl + parameters { + name + value + } + } + } + } + `; + }, + bulkImportMutation() { + return ` + mutation bulkOperationRunMutation($clientIdentifier: String, $mutation: String!, $stagedUploadPath: String!) { + bulkOperationRunMutation(clientIdentifier: $clientIdentifier, mutation: $mutation, stagedUploadPath: $stagedUploadPath) { + bulkOperation { + id + completedAt + createdAt + fileSize + objectCount + rootObjectCount + partialDataUrl + query + status + url + } + userErrors { + field + message + } + } + } + `; + }, + }, + async run({ $ }) { + const filePath = this.filePath.includes("/tmp") + ? this.filePath + : `/tmp/${this.filePath}`; + const filename = filePath.split("/").pop(); + + // create staged upload path + + const { stagedUploadsCreate: { stagedTargets } } + = await this.shopify._makeGraphQlRequest(this.stagedUploadQuery(), { + input: [ + { + resource: "BULK_MUTATION_VARIABLES", + filename, + mimeType: "text/jsonl", + httpMethod: "POST", + }, + ], + }); + + const { + url, parameters, + } = stagedTargets[0]; + + // upload file to staged upload path + + let stagedUploadPath; + const form = new FormData(); + parameters.forEach(({ + name, value, + }) => { + form.append(name, value); + if (name === "key") { + stagedUploadPath = value; + } + }); + form.append("file", fs.createReadStream(filePath)); + + await axios($, { + url, + method: "POST", + headers: form.getHeaders(), + data: form, + debug: true, + }); + + // perform bulk import + + const response = await this.shopify._makeGraphQlRequest(this.bulkImportMutation(), { + mutation: this.mutation, + stagedUploadPath, + clientIdentifier: this.clientIdentifier, + }); + + if (response.bulkOperationRunMutation.userErrors.length > 0) { + throw new Error(response.bulkOperationRunMutation.userErrors[0].message); + } + + $.export("$summary", "Successfully completed bulk import"); + return response; + }, +}; diff --git a/components/shopify/package.json b/components/shopify/package.json index 41ed5af0e5bc9..ecd3be4e51914 100644 --- a/components/shopify/package.json +++ b/components/shopify/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/shopify", - "version": "0.6.8", + "version": "0.6.9", "description": "Pipedream Shopify Components", "main": "shopify.app.mjs", "keywords": [ @@ -13,6 +13,7 @@ "@pipedream/platform": "^3.0.3", "async-retry": "^1.3.3", "bottleneck": "^2.19.5", + "form-data": "^4.0.2", "lodash.get": "^4.4.2", "lodash.topath": "^4.5.2", "shopify-api-node": "^3.14.2" From 8a34a780a2370da875b4616b2852c6d0a542d488 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Fri, 7 Mar 2025 15:10:19 -0500 Subject: [PATCH 2/4] pnpm-lock.yaml --- pnpm-lock.yaml | 128 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 114 insertions(+), 14 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 72803b66e9347..33cbefd59b79d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10079,8 +10079,7 @@ importers: components/qwilr: {} - components/rabbitmq: - specifiers: {} + components/rabbitmq: {} components/radar: {} @@ -11274,8 +11273,7 @@ importers: specifier: ^3.0.0 version: 3.0.3 - components/servicetitan: - specifiers: {} + components/servicetitan: {} components/serwersms_pl: {} @@ -11401,6 +11399,9 @@ importers: bottleneck: specifier: ^2.19.5 version: 2.19.5 + form-data: + specifier: ^4.0.2 + version: 4.0.2 lodash.get: specifier: ^4.4.2 version: 4.4.2 @@ -20564,6 +20565,10 @@ packages: resolution: {integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==} engines: {node: '>=6'} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} @@ -21721,6 +21726,10 @@ packages: peerDependencies: typescript: '>= 3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.7.0-dev || >= 3.8.0-dev || >= 3.9.0-dev || >= 4.0.0-dev' + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + duplexer3@0.1.5: resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==} @@ -21856,6 +21865,10 @@ packages: resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} engines: {node: '>= 0.4'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} @@ -21871,10 +21884,18 @@ packages: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} engines: {node: '>= 0.4'} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + es-set-tostringtag@2.0.3: resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} engines: {node: '>= 0.4'} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + es-shim-unscopables@1.0.2: resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} @@ -22589,6 +22610,10 @@ packages: resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} engines: {node: '>= 6'} + form-data@4.0.2: + resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} + engines: {node: '>= 6'} + format-io@2.0.0: resolution: {integrity: sha512-iQz8w2qr4f+doWBV6LsfScHbu1gXhccByjbmA1wjBTaKRhweH2baJL96UGR4C7Fjpr8zSkK7EXiLmbzZWTyQIA==} engines: {node: '>=8'} @@ -22749,10 +22774,18 @@ packages: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-stdin@7.0.0: resolution: {integrity: sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==} engines: {node: '>=8'} @@ -22960,6 +22993,10 @@ packages: gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + got@11.8.6: resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} engines: {node: '>=10.19.0'} @@ -23080,6 +23117,10 @@ packages: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} @@ -24637,6 +24678,10 @@ packages: engines: {node: '>= 12'} hasBin: true + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + mathjax-full@3.2.2: resolution: {integrity: sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w==} @@ -35039,7 +35084,7 @@ snapshots: '@types/retry': 0.12.0 axios: 1.7.7(debug@3.2.7) eventemitter3: 5.0.1 - form-data: 4.0.1 + form-data: 4.0.2 is-electron: 2.2.2 is-stream: 2.0.1 p-queue: 6.6.2 @@ -36580,7 +36625,7 @@ snapshots: datauri: 4.1.0 fetch-har: 5.0.5 find-cache-dir: 3.3.2 - form-data: 4.0.1 + form-data: 4.0.2 get-stream: 6.0.1 js-yaml: 4.1.0 make-dir: 3.1.0 @@ -36856,7 +36901,7 @@ snapshots: axios@0.28.1: dependencies: follow-redirects: 1.15.9(debug@3.2.7) - form-data: 4.0.1 + form-data: 4.0.2 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -36864,7 +36909,7 @@ snapshots: axios@1.6.0: dependencies: follow-redirects: 1.15.9(debug@3.2.7) - form-data: 4.0.1 + form-data: 4.0.2 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -36872,7 +36917,7 @@ snapshots: axios@1.6.7: dependencies: follow-redirects: 1.15.9(debug@3.2.7) - form-data: 4.0.1 + form-data: 4.0.2 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -36880,7 +36925,7 @@ snapshots: axios@1.6.8: dependencies: follow-redirects: 1.15.9(debug@3.2.7) - form-data: 4.0.1 + form-data: 4.0.2 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -36888,7 +36933,7 @@ snapshots: axios@1.7.4: dependencies: follow-redirects: 1.15.9(debug@3.2.7) - form-data: 4.0.1 + form-data: 4.0.2 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -36904,7 +36949,7 @@ snapshots: axios@1.7.9: dependencies: follow-redirects: 1.15.9(debug@3.2.7) - form-data: 4.0.1 + form-data: 4.0.2 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -37297,6 +37342,11 @@ snapshots: cachedir@2.4.0: {} + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + call-bind@1.0.7: dependencies: es-define-property: 1.0.0 @@ -38523,6 +38573,12 @@ snapshots: typescript: 5.7.2 yargs: 15.4.1 + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + duplexer3@0.1.5: {} duplexer@0.1.2: {} @@ -38695,6 +38751,8 @@ snapshots: dependencies: get-intrinsic: 1.2.4 + es-define-property@1.0.1: {} + es-errors@1.3.0: {} es-get-iterator@1.1.3: @@ -38731,12 +38789,23 @@ snapshots: dependencies: es-errors: 1.3.0 + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + es-set-tostringtag@2.0.3: dependencies: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 hasown: 2.0.2 + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + es-shim-unscopables@1.0.2: dependencies: hasown: 2.0.2 @@ -39683,6 +39752,13 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 + form-data@4.0.2: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + mime-types: 2.1.35 + format-io@2.0.0: dependencies: currify: 4.0.0 @@ -39895,8 +39971,26 @@ snapshots: has-symbols: 1.0.3 hasown: 2.0.2 + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + get-package-type@0.1.0: {} + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + get-stdin@7.0.0: {} get-stream@3.0.0: {} @@ -40255,6 +40349,8 @@ snapshots: dependencies: get-intrinsic: 1.2.4 + gopd@1.2.0: {} + got@11.8.6: dependencies: '@sindresorhus/is': 4.6.0 @@ -40452,6 +40548,8 @@ snapshots: has-symbols@1.0.3: {} + has-symbols@1.1.0: {} + has-tostringtag@1.0.2: dependencies: has-symbols: 1.0.3 @@ -42403,6 +42501,8 @@ snapshots: marked@4.3.0: {} + math-intrinsics@1.1.0: {} + mathjax-full@3.2.2: dependencies: esm: 3.2.25 @@ -46549,7 +46649,7 @@ snapshots: cookiejar: 2.1.4 debug: 4.4.0 fast-safe-stringify: 2.1.1 - form-data: 4.0.1 + form-data: 4.0.2 formidable: 2.1.2 methods: 1.1.2 mime: 2.6.0 @@ -47619,7 +47719,7 @@ snapshots: webflow-api@2.4.2: dependencies: - form-data: 4.0.1 + form-data: 4.0.2 formdata-node: 6.0.3 js-base64: 3.7.2 node-fetch: 2.7.0 From 4fc3d07adea9b08ebeb9fde318efd66bcb898a34 Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Fri, 7 Mar 2025 15:32:40 -0500 Subject: [PATCH 3/4] remove debug --- components/shopify/actions/bulk-import/bulk-import.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/components/shopify/actions/bulk-import/bulk-import.mjs b/components/shopify/actions/bulk-import/bulk-import.mjs index fa9c9dcd12f12..875cd76216c78 100644 --- a/components/shopify/actions/bulk-import/bulk-import.mjs +++ b/components/shopify/actions/bulk-import/bulk-import.mjs @@ -118,7 +118,6 @@ export default { method: "POST", headers: form.getHeaders(), data: form, - debug: true, }); // perform bulk import From e9c9504ea19ebbd8f8bf71f3af484a73e86d425d Mon Sep 17 00:00:00 2001 From: michelle0927 Date: Fri, 7 Mar 2025 15:39:58 -0500 Subject: [PATCH 4/4] Update components/shopify/actions/bulk-import/bulk-import.mjs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- components/shopify/actions/bulk-import/bulk-import.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/shopify/actions/bulk-import/bulk-import.mjs b/components/shopify/actions/bulk-import/bulk-import.mjs index 875cd76216c78..8110ef2dc061d 100644 --- a/components/shopify/actions/bulk-import/bulk-import.mjs +++ b/components/shopify/actions/bulk-import/bulk-import.mjs @@ -6,7 +6,7 @@ import FormData from "form-data"; export default { key: "shopify-bulk-import", name: "Bulk Import", - description: "Add tags. [See the documentation](https://shopify.dev/docs/api/admin-graphql/latest/mutations/bulkoperationrunmutation)", + description: "Execute bulk mutations by uploading a JSONL file containing mutation variables. [See the documentation](https://shopify.dev/docs/api/admin-graphql/latest/mutations/bulkoperationrunmutation)", version: "0.0.1", type: "action", props: {