@foxtware/mineral 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.creds.yml.sample +27 -6
- package/AGENTS.md +6 -1
- package/README.md +1 -1
- package/api/bleckmann/.gitkeep +0 -0
- package/api/bleckmann/bleckmann.constants.js +8 -0
- package/api/bleckmann/bleckmann.utils.js +32 -0
- package/api/bleckmann/bleckmannAsnGet.js +52 -0
- package/api/bleckmann/bleckmannAsnsGet.js +65 -0
- package/api/constants.js +2 -1
- package/api/github/github.constants.js +11 -0
- package/api/github/github.utils.js +65 -0
- package/api/github/githubGet.js +144 -0
- package/api/github/githubIssueCreate.js +71 -0
- package/api/github/githubIssueGet.js +65 -0
- package/api/github/githubIssueUpdate.js +71 -0
- package/api/github/githubIssuesGet.js +74 -0
- package/api/github/githubPullRequestCreate.js +74 -0
- package/api/github/githubPullRequestGet.js +65 -0
- package/api/github/githubPullRequestMerge.js +77 -0
- package/api/github/githubPullRequestUpdate.js +72 -0
- package/api/github/githubPullRequestsGet.js +74 -0
- package/api/github/githubRepoCreate.js +80 -0
- package/api/github/githubRepoDelete.js +60 -0
- package/api/github/githubRepoGet.js +61 -0
- package/api/github/githubRepoUpdate.js +68 -0
- package/api/github/githubReposGet.js +69 -0
- package/api/github/githubUserGet.js +64 -0
- package/api/linear/linear.utils.js +9 -14
- package/api/linear/linearIssuesGet.js +9 -9
- package/api/logiwa/logiwa.utils.js +27 -25
- package/api/logiwa/logiwaInventoriesGet.js +5 -3
- package/api/logiwa/logiwaOrderGet.js +4 -2
- package/api/logiwa/logiwaOrdersGet.js +5 -3
- package/api/logiwa/logiwaProductGet.js +4 -2
- package/api/logiwa/logiwaProductsGet.js +5 -3
- package/api/logiwa/logiwaReportGetAvailableToPromise.js +5 -3
- package/api/logiwa/logiwaReportGetInventoryCalculation.js +5 -3
- package/api/logiwa/logiwaReportGetInventorySnapshot.js +5 -3
- package/api/logiwa/logiwaReportGetTotalInventory.js +5 -3
- package/api/logiwa/logiwaWebhookStatusGet.js +4 -2
- package/api/logiwa/logiwaWebhookSubscribe.js +8 -6
- package/api/logiwa/logiwaWebhookUnsubscribe.js +4 -2
- package/api/logiwa/logiwaWebhooksGet.js +4 -2
- package/api/loop/loop.utils.js +9 -15
- package/api/loop/loopGet.js +20 -24
- package/api/loop/loopReturnGet.js +6 -6
- package/api/peoplevox/peoplevox.constants.js +1 -1
- package/api/peoplevox/peoplevox.sessions.js +0 -33
- package/api/peoplevox/peoplevox.utils.js +63 -19
- package/api/peoplevox/peoplevoxGetSingle.js +7 -5
- package/api/peoplevox/peoplevoxOrderEdit.js +7 -5
- package/api/peoplevox/peoplevoxReportGet.js +11 -9
- package/api/pipelineSteps.js +49 -0
- package/api/shopify/shopify.utils.js +18 -24
- package/api/shopify/shopifyBulkMutationDo.js +211 -0
- package/api/shopify/shopifyBulkOperationGet.js +86 -0
- package/api/shopify/shopifyBulkOperationRunMutation.js +83 -0
- package/api/shopify/shopifyCheckoutAndAccountsConfigurationUpdate.js +79 -0
- package/api/shopify/shopifyCollectionGet.js +6 -6
- package/api/shopify/shopifyCustomerGet.js +6 -6
- package/api/shopify/shopifyGet.js +18 -13
- package/api/shopify/shopifyGetSingle.js +9 -9
- package/api/shopify/shopifyMutationDo.js +6 -6
- package/api/shopify/shopifyOrdersGet.js +11 -11
- package/api/shopify/shopifyStagedUploadCreate.js +96 -0
- package/api/shopify/shopifyTagsAddBulk.js +90 -0
- package/api/slack/slack.utils.js +10 -19
- package/api/slack/slackMessagePost.js +11 -11
- package/api/starshipit/starshipit.constants.js +8 -0
- package/api/starshipit/starshipit.utils.js +71 -0
- package/api/starshipit/starshipitAddressCreate.js +77 -0
- package/api/starshipit/starshipitAddressDelete.js +55 -0
- package/api/starshipit/starshipitAddressUpdate.js +69 -0
- package/api/starshipit/starshipitAddressesGet.js +52 -0
- package/api/starshipit/starshipitGet.js +146 -0
- package/api/starshipit/starshipitOrderDelete.js +102 -0
- package/api/starshipit/starshipitOrderGet.js +74 -0
- package/api/starshipit/starshipitOrderUpdate.js +109 -0
- package/api/starshipit/starshipitOrdersListShipped.js +64 -0
- package/api/starshipit/starshipitProductAdd.js +100 -0
- package/api/starshipit/starshipitProductsDelete.js +57 -0
- package/api/starshipit/starshipitProductsGet.js +49 -0
- package/api/starshipit/starshipitTrackingGet.js +69 -0
- package/api/stripe/_example.js +7 -7
- package/api/stripe/stripe.utils.js +9 -14
- package/api/stripe/stripeCardTokenCreate.js +11 -11
- package/api/stripe/stripeChargeCapture.js +11 -11
- package/api/stripe/stripeChargeCreate.js +11 -11
- package/api/stripe/stripeChargeGet.js +5 -5
- package/api/stripe/stripeChargesGet.js +6 -6
- package/api/stripe/stripeRefundCreate.js +10 -10
- package/api/stripe/stripeRefundGet.js +5 -5
- package/api/stripe/stripeRefundsGet.js +6 -6
- package/api/stripe/stripeTokenGet.js +5 -5
- package/api/stylearcade/stylearcade.constants.js +5 -0
- package/api/stylearcade/stylearcade.utils.js +40 -0
- package/api/stylearcade/stylearcadeDataGet.js +62 -0
- package/api/stylearcade/stylearcadeGet.js +133 -0
- package/api/stylearcade/stylearcadeMetadataGet.js +47 -0
- package/api/threeclicks/threeclicks.constants.js +8 -0
- package/api/threeclicks/threeclicks.utils.js +119 -0
- package/api/threeclicks/threeclicksCollectionsGet.js +40 -0
- package/api/threeclicks/threeclicksGet.js +138 -0
- package/api/threeclicks/threeclicksKeycodeCreate.js +55 -0
- package/api/threeclicks/threeclicksKeycodeGet.js +47 -0
- package/api/threeclicks/threeclicksPurchaseOrderCreate.js +34 -0
- package/api/threeclicks/threeclicksPurchaseOrderCreateBulk.js +34 -0
- package/api/threeclicks/threeclicksPurchaseOrderGet.js +33 -0
- package/api/threeclicks/threeclicksPurchaseOrderQuantitiesGet.js +33 -0
- package/api/threeclicks/threeclicksPurchaseOrderQuantityCreate.js +34 -0
- package/api/threeclicks/threeclicksPurchaseOrderQuantityCreateBulk.js +34 -0
- package/api/threeclicks/threeclicksPurchaseOrderQuantityUpdate.js +46 -0
- package/api/threeclicks/threeclicksPurchaseOrderQuantityUpdateBulk.js +46 -0
- package/api/threeclicks/threeclicksPurchaseOrderUpdate.js +35 -0
- package/api/threeclicks/threeclicksPurchaseOrdersGet.js +30 -0
- package/api/threeclicks/threeclicksShipmentCreate.js +34 -0
- package/api/threeclicks/threeclicksShipmentGet.js +33 -0
- package/api/threeclicks/threeclicksShipmentOrderAdd.js +38 -0
- package/api/threeclicks/threeclicksShipmentOrderQuantityCreate.js +35 -0
- package/api/threeclicks/threeclicksShipmentQuantityUpdate.js +35 -0
- package/api/threeclicks/threeclicksShipmentStatusUpdate.js +45 -0
- package/api/threeclicks/threeclicksShipmentsGet.js +52 -0
- package/api/threeclicks/threeclicksSignatureCalculate.js +73 -0
- package/api/threeclicks/threeclicksStyleCodesGet.js +46 -0
- package/api/threeclicks/threeclicksStyleColourCreate.js +47 -0
- package/api/threeclicks/threeclicksStyleColourDelete.js +34 -0
- package/api/threeclicks/threeclicksStyleCreate.js +44 -0
- package/api/threeclicks/threeclicksStyleDelete.js +33 -0
- package/api/threeclicks/threeclicksStyleGet.js +43 -0
- package/api/threeclicks/threeclicksStylePriceUpdate.js +70 -0
- package/api/threeclicks/threeclicksStyleUpdate.js +47 -0
- package/api/threeclicks/threeclicksStylesGet.js +45 -0
- package/api/utils.js +85 -117
- package/api/validators.js +1 -1
- package/api/workable/workable.utils.js +8 -13
- package/api/workable/workableGet.js +16 -11
- package/api/workable/workableJobCandidateCreate.js +10 -10
- package/api/workable/workableJobGet.js +5 -5
- package/api/workable/workableJobMembersGet.js +5 -5
- package/api/workable/workableJobStagesGet.js +5 -5
- package/api/yotpo/yotpo.utils.js +17 -22
- package/api/yotpo/yotpoCampaignsGet.js +6 -6
- package/api/yotpo/yotpoCustomerActionRecord.js +7 -7
- package/api/yotpo/yotpoCustomerAnniversaryGet.js +7 -7
- package/api/yotpo/yotpoCustomerAnniversarySet.js +7 -7
- package/api/yotpo/yotpoCustomerBirthdaySet.js +7 -7
- package/api/yotpo/yotpoCustomerGet.js +6 -6
- package/api/yotpo/yotpoCustomerPointsAdjust.js +7 -7
- package/api/yotpo/yotpoCustomerUpsert.js +7 -7
- package/api/yotpo/yotpoCustomersRecentGet.js +6 -6
- package/api/yotpo/yotpoRedemptionCreate.js +7 -7
- package/api/yotpo/yotpoRedemptionOptionsGet.js +6 -6
- package/api/yotpo/yotpoVipTiersGet.js +5 -5
- package/api/youtube/youtube.constants.js +5 -0
- package/api/youtube/youtube.utils.js +77 -0
- package/api/youtube/youtubeChannelVideosGet.js +25 -70
- package/package.json +1 -1
|
@@ -48,40 +48,7 @@ const setSessionId = async (credsPayload, sessionId) => {
|
|
|
48
48
|
SESSION_IDS.set(CLIENT_ID, sessionId);
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
const withPeoplevoxAuth = async (fetchPayload, next) => {
|
|
52
|
-
const { context = {} } = fetchPayload;
|
|
53
|
-
const { credsPayload } = context;
|
|
54
|
-
|
|
55
|
-
const sessionIdResponse = await getSessionId(credsPayload);
|
|
56
|
-
|
|
57
|
-
const {
|
|
58
|
-
ok: sessionIdOk,
|
|
59
|
-
data: sessionId,
|
|
60
|
-
} = sessionIdResponse;
|
|
61
|
-
|
|
62
|
-
if (!sessionIdOk) {
|
|
63
|
-
return sessionIdResponse;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const response = await next({
|
|
67
|
-
...fetchPayload,
|
|
68
|
-
context: {
|
|
69
|
-
...context,
|
|
70
|
-
sessionId,
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
if (response.ok) {
|
|
75
|
-
await setSessionId(credsPayload, sessionId);
|
|
76
|
-
return response;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// TODO: Check if it was an auth error, and try another auth method if so
|
|
80
|
-
return response;
|
|
81
|
-
};
|
|
82
|
-
|
|
83
51
|
module.exports = {
|
|
84
52
|
getSessionId,
|
|
85
53
|
setSessionId,
|
|
86
|
-
withPeoplevoxAuth,
|
|
87
54
|
};
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
const csvtojson = require('csvtojson');
|
|
2
2
|
const xml2js = require('xml2js');
|
|
3
|
-
const {
|
|
4
|
-
const {
|
|
3
|
+
const { resolveCreds } = require('../pipelineSteps');
|
|
4
|
+
const {
|
|
5
|
+
FetchClient,
|
|
6
|
+
appendUrlToBase,
|
|
7
|
+
logDeep,
|
|
8
|
+
} = require('../utils');
|
|
9
|
+
const { getSessionId, setSessionId } = require('../peoplevox/peoplevox.sessions');
|
|
5
10
|
|
|
6
11
|
const xml2jsBuilder = new xml2js.Builder({
|
|
7
12
|
headless: true,
|
|
@@ -45,17 +50,17 @@ const buildSoapEnvelope = ({
|
|
|
45
50
|
return xml2jsBuilder.buildObject(envelopeObject);
|
|
46
51
|
};
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
const {
|
|
51
|
-
const {
|
|
52
|
-
const { CLIENT_ID } = await credsFromPayload(credsPayload);
|
|
53
|
+
const useSoapEnvelope = async (state) => {
|
|
54
|
+
const { requestPayload, context } = state;
|
|
55
|
+
const { creds, action, sessionId } = context;
|
|
56
|
+
const { CLIENT_ID } = creds;
|
|
53
57
|
|
|
54
58
|
if (!sessionId) {
|
|
55
59
|
throw new Error('PeopleVox sessionId is required');
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
const baseUrl = `https://ap.peoplevox.net/${ CLIENT_ID }/Resources/IntegrationServicev4.asmx`;
|
|
63
|
+
const { headers, body } = requestPayload;
|
|
59
64
|
|
|
60
65
|
const envelopeXml = buildSoapEnvelope({
|
|
61
66
|
action,
|
|
@@ -67,14 +72,16 @@ const peoplevoxRequestPreparer = async (requestPayload, context) => {
|
|
|
67
72
|
logDeep({ envelopeXml });
|
|
68
73
|
|
|
69
74
|
return {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
requestPayload: {
|
|
76
|
+
...requestPayload,
|
|
77
|
+
url: appendUrlToBase(baseUrl, requestPayload.url),
|
|
78
|
+
headers: {
|
|
79
|
+
...headers,
|
|
80
|
+
'Content-Type': 'text/xml; charset=utf-8',
|
|
81
|
+
'SOAPAction': `http://www.peoplevox.net/${ action }`,
|
|
82
|
+
},
|
|
83
|
+
body: envelopeXml,
|
|
76
84
|
},
|
|
77
|
-
body: envelopeXml,
|
|
78
85
|
};
|
|
79
86
|
};
|
|
80
87
|
|
|
@@ -167,17 +174,54 @@ const hoistDetail = (state) => {
|
|
|
167
174
|
};
|
|
168
175
|
|
|
169
176
|
const peoplevoxClient = new FetchClient({
|
|
170
|
-
|
|
171
|
-
|
|
177
|
+
pipeline: [
|
|
178
|
+
resolveCreds,
|
|
179
|
+
useSoapEnvelope,
|
|
180
|
+
'fetch',
|
|
172
181
|
stripEnvelope,
|
|
173
182
|
tryToParseDetailAsCsv,
|
|
174
183
|
unwrapSingleDetail,
|
|
175
184
|
hoistDetail,
|
|
176
|
-
]
|
|
185
|
+
],
|
|
177
186
|
});
|
|
178
187
|
|
|
179
|
-
peoplevoxClient.
|
|
188
|
+
const fetchWithoutAuth = peoplevoxClient.fetch.bind(peoplevoxClient);
|
|
189
|
+
|
|
190
|
+
peoplevoxClient.fetch = async ({
|
|
191
|
+
requestPayload,
|
|
192
|
+
context = {},
|
|
193
|
+
inspect = false,
|
|
194
|
+
}) => {
|
|
195
|
+
const { credsPayload } = context;
|
|
196
|
+
|
|
197
|
+
const sessionIdResponse = await getSessionId(credsPayload);
|
|
198
|
+
|
|
199
|
+
const {
|
|
200
|
+
ok: sessionIdOk,
|
|
201
|
+
data: sessionId,
|
|
202
|
+
} = sessionIdResponse;
|
|
203
|
+
|
|
204
|
+
if (!sessionIdOk) {
|
|
205
|
+
return sessionIdResponse;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const response = await fetchWithoutAuth({
|
|
209
|
+
requestPayload,
|
|
210
|
+
context: {
|
|
211
|
+
...context,
|
|
212
|
+
sessionId,
|
|
213
|
+
},
|
|
214
|
+
inspect,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
if (response.ok) {
|
|
218
|
+
await setSessionId(credsPayload, sessionId);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// TODO: Check if it was an auth error, and try another auth method if so
|
|
222
|
+
return response;
|
|
223
|
+
};
|
|
180
224
|
|
|
181
225
|
module.exports = {
|
|
182
226
|
peoplevoxClient,
|
|
183
|
-
};
|
|
227
|
+
};
|
|
@@ -32,11 +32,13 @@ const peoplevoxGetSingle = async (
|
|
|
32
32
|
const resolvedSearchClause = searchClause || `${ idName }.Equals("${ id }")`;
|
|
33
33
|
|
|
34
34
|
const response = await peoplevoxClient.fetch({
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
requestPayload: {
|
|
36
|
+
method: 'post',
|
|
37
|
+
body: {
|
|
38
|
+
getRequest: {
|
|
39
|
+
TemplateName: templateName,
|
|
40
|
+
SearchClause: resolvedSearchClause,
|
|
41
|
+
},
|
|
40
42
|
},
|
|
41
43
|
},
|
|
42
44
|
context: {
|
|
@@ -37,11 +37,13 @@ const peoplevoxOrderEdit = async (
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
return peoplevoxClient.fetch({
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
requestPayload: {
|
|
41
|
+
method: 'post',
|
|
42
|
+
body: {
|
|
43
|
+
saveRequest: {
|
|
44
|
+
TemplateName: 'Sales orders',
|
|
45
|
+
CsvData: csvData,
|
|
46
|
+
},
|
|
45
47
|
},
|
|
46
48
|
},
|
|
47
49
|
context: {
|
|
@@ -25,15 +25,17 @@ const peoplevoxReportGet = async (
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const reportGetResponse = await peoplevoxClient.fetch({
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
requestPayload: {
|
|
29
|
+
method: 'post',
|
|
30
|
+
body: {
|
|
31
|
+
getReportRequest: {
|
|
32
|
+
TemplateName: reportName,
|
|
33
|
+
...(searchClause ? { SearchClause: searchClause } : {}),
|
|
34
|
+
...(perPage ? { ItemsPerPage: perPage } : {}),
|
|
35
|
+
...(filter ? { FilterClause: filter } : {}),
|
|
36
|
+
...(orderBy ? { OrderBy: orderBy } : {}),
|
|
37
|
+
...(columns ? { Columns: columns.join(',') } : {}),
|
|
38
|
+
},
|
|
37
39
|
},
|
|
38
40
|
},
|
|
39
41
|
context: {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const { appendUrlToBase, credsFromPayload } = require('./utils');
|
|
2
|
+
|
|
3
|
+
const resolveCreds = async (state) => {
|
|
4
|
+
const { context } = state;
|
|
5
|
+
const { creds, credsPayload } = context;
|
|
6
|
+
|
|
7
|
+
if (creds || !credsPayload) {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const resolvedCreds = await credsFromPayload(credsPayload);
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
context: {
|
|
15
|
+
...context,
|
|
16
|
+
creds: resolvedCreds,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const useBaseUrl = (baseUrl) => async (state) => {
|
|
22
|
+
const { requestPayload, context } = state;
|
|
23
|
+
const resolvedBaseUrl = baseUrl ?? context.baseUrl;
|
|
24
|
+
|
|
25
|
+
if (!resolvedBaseUrl) {
|
|
26
|
+
return {
|
|
27
|
+
breakChain: true,
|
|
28
|
+
response: {
|
|
29
|
+
ok: false,
|
|
30
|
+
error: {
|
|
31
|
+
code: 'NO_BASE_URL',
|
|
32
|
+
message: 'No base URL provided',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
requestPayload: {
|
|
40
|
+
...requestPayload,
|
|
41
|
+
url: appendUrlToBase(resolvedBaseUrl, requestPayload.url),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
module.exports = {
|
|
47
|
+
resolveCreds,
|
|
48
|
+
useBaseUrl,
|
|
49
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { DEFAULT_API_VERSION } = require('../shopify/shopify.constants');
|
|
2
|
+
const { resolveCreds } = require('../pipelineSteps');
|
|
2
3
|
const {
|
|
3
4
|
FetchClient,
|
|
4
|
-
Chain,
|
|
5
5
|
appendUrlToBase,
|
|
6
6
|
fetchClientCommonSteps,
|
|
7
7
|
pathAsArray,
|
|
@@ -49,11 +49,11 @@ const handleMutationUserErrors = async (state) => {
|
|
|
49
49
|
};
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
const
|
|
52
|
+
const useUrlAndAuthHeaders = async (state) => {
|
|
53
53
|
const { requestPayload, context } = state;
|
|
54
54
|
const {
|
|
55
|
-
creds,
|
|
56
55
|
apiVersion = DEFAULT_API_VERSION,
|
|
56
|
+
creds,
|
|
57
57
|
} = context;
|
|
58
58
|
const {
|
|
59
59
|
STORE_HANDLE,
|
|
@@ -61,15 +61,13 @@ const addUrlAndAuthHeaders = async (state) => {
|
|
|
61
61
|
} = creds;
|
|
62
62
|
|
|
63
63
|
const baseUrl = `https://${ STORE_HANDLE }.myshopify.com/admin/api/${ apiVersion }/graphql.json`;
|
|
64
|
-
const baseHeaders = {
|
|
65
|
-
'X-Shopify-Access-Token': API_KEY,
|
|
66
|
-
};
|
|
67
64
|
|
|
68
65
|
return {
|
|
69
66
|
requestPayload: {
|
|
67
|
+
...requestPayload,
|
|
70
68
|
url: appendUrlToBase(baseUrl, requestPayload.url),
|
|
71
69
|
headers: {
|
|
72
|
-
|
|
70
|
+
'X-Shopify-Access-Token': API_KEY,
|
|
73
71
|
...requestPayload.headers,
|
|
74
72
|
},
|
|
75
73
|
},
|
|
@@ -99,25 +97,21 @@ const movePageInfoToMeta = async (state) => {
|
|
|
99
97
|
};
|
|
100
98
|
};
|
|
101
99
|
|
|
102
|
-
const shopifyClientRequestPreparer = new Chain([
|
|
103
|
-
addUrlAndAuthHeaders,
|
|
104
|
-
]);
|
|
105
|
-
|
|
106
|
-
const shopifyClientResponseInterpreter = new Chain([
|
|
107
|
-
movePageInfoToMeta,
|
|
108
|
-
fetchClientCommonSteps.stripEdgesAndNodes,
|
|
109
|
-
fetchClientCommonSteps.collapseDataWithOneValue,
|
|
110
|
-
fetchClientCommonSteps.exitEarlyOnNotOk,
|
|
111
|
-
fetchClientCommonSteps.exitEarlyOnGraphqlErrors,
|
|
112
|
-
fetchClientCommonSteps.digToPath,
|
|
113
|
-
handleMutationUserErrors,
|
|
114
|
-
]);
|
|
115
|
-
|
|
116
100
|
const shopifyClient = new FetchClient({
|
|
117
|
-
|
|
118
|
-
|
|
101
|
+
pipeline: [
|
|
102
|
+
resolveCreds,
|
|
103
|
+
useUrlAndAuthHeaders,
|
|
104
|
+
'fetch',
|
|
105
|
+
movePageInfoToMeta,
|
|
106
|
+
fetchClientCommonSteps.stripEdgesAndNodes,
|
|
107
|
+
fetchClientCommonSteps.collapseDataWithOneValue,
|
|
108
|
+
fetchClientCommonSteps.exitEarlyOnNotOk,
|
|
109
|
+
fetchClientCommonSteps.exitEarlyOnGraphqlErrors,
|
|
110
|
+
fetchClientCommonSteps.digToPath,
|
|
111
|
+
handleMutationUserErrors,
|
|
112
|
+
],
|
|
119
113
|
});
|
|
120
114
|
|
|
121
115
|
module.exports = {
|
|
122
116
|
shopifyClient,
|
|
123
|
-
};
|
|
117
|
+
};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
const { randomUUID } = require('crypto');
|
|
2
|
+
const { createReadStream } = require('fs');
|
|
3
|
+
const fs = require('fs').promises;
|
|
4
|
+
|
|
5
|
+
const { HOSTED, TEMP_DIR } = require('../constants');
|
|
6
|
+
const { credsValidator } = require('../validators');
|
|
7
|
+
const {
|
|
8
|
+
ArgsWarden,
|
|
9
|
+
customFetch,
|
|
10
|
+
gidToId,
|
|
11
|
+
objectToFormData,
|
|
12
|
+
objHasAny,
|
|
13
|
+
objectArrayToJsonl,
|
|
14
|
+
jsonlToObjectArray,
|
|
15
|
+
wait,
|
|
16
|
+
valueProvided,
|
|
17
|
+
} = require('../utils');
|
|
18
|
+
const { shopifyStagedUploadCreate } = require('./shopifyStagedUploadCreate');
|
|
19
|
+
const { shopifyBulkOperationRunMutation } = require('./shopifyBulkOperationRunMutation');
|
|
20
|
+
const { shopifyBulkOperationGet } = require('./shopifyBulkOperationGet');
|
|
21
|
+
|
|
22
|
+
const bulkOpAttrs = `
|
|
23
|
+
id
|
|
24
|
+
status
|
|
25
|
+
type
|
|
26
|
+
objectCount
|
|
27
|
+
url
|
|
28
|
+
errorCode
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const createOrResumeBulkOpPayloadValidator = (payload) => {
|
|
32
|
+
const { mutation, input, bulkOperationId } = payload;
|
|
33
|
+
|
|
34
|
+
if (valueProvided(bulkOperationId)) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return valueProvided(mutation) && objHasAny(input, ['data', 'filepath']);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const argsWarden = new ArgsWarden([
|
|
42
|
+
['credsPayload', credsValidator],
|
|
43
|
+
['createOrResumeBulkOpPayload', createOrResumeBulkOpPayloadValidator],
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
const shopifyBulkMutationDo = async (
|
|
47
|
+
credsPayload,
|
|
48
|
+
createOrResumeBulkOpPayload,
|
|
49
|
+
{
|
|
50
|
+
apiVersion,
|
|
51
|
+
clientIdentifier,
|
|
52
|
+
waitForResult = true,
|
|
53
|
+
} = {},
|
|
54
|
+
) => {
|
|
55
|
+
|
|
56
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
57
|
+
credsPayload,
|
|
58
|
+
createOrResumeBulkOpPayload,
|
|
59
|
+
});
|
|
60
|
+
if (rejectResponse) {
|
|
61
|
+
return rejectResponse;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const {
|
|
65
|
+
mutation,
|
|
66
|
+
input,
|
|
67
|
+
bulkOperationId,
|
|
68
|
+
} = createOrResumeBulkOpPayload;
|
|
69
|
+
|
|
70
|
+
let bulkOperation;
|
|
71
|
+
|
|
72
|
+
if (!bulkOperationId) {
|
|
73
|
+
|
|
74
|
+
if (HOSTED) {
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
error: 'This function is only available locally',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let {
|
|
82
|
+
data,
|
|
83
|
+
filepath,
|
|
84
|
+
} = input;
|
|
85
|
+
|
|
86
|
+
if (!filepath) {
|
|
87
|
+
await fs.mkdir(TEMP_DIR, { recursive: true });
|
|
88
|
+
filepath = `${ TEMP_DIR }/shopifyBulkMutationDo_${ randomUUID() }.jsonl`;
|
|
89
|
+
await fs.writeFile(filepath, objectArrayToJsonl(data));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const stagedUploadResponse = await shopifyStagedUploadCreate(
|
|
93
|
+
credsPayload,
|
|
94
|
+
{
|
|
95
|
+
resource: 'BULK_MUTATION_VARIABLES',
|
|
96
|
+
filename: filepath.split('/').pop(),
|
|
97
|
+
mimeType: 'text/jsonl',
|
|
98
|
+
httpMethod: 'POST',
|
|
99
|
+
},
|
|
100
|
+
{ apiVersion },
|
|
101
|
+
);
|
|
102
|
+
if (!stagedUploadResponse.ok) {
|
|
103
|
+
return stagedUploadResponse;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const { url, parameters } = stagedUploadResponse.data.stagedTargets[0];
|
|
107
|
+
|
|
108
|
+
const formData = objectToFormData(
|
|
109
|
+
Object.fromEntries(parameters.map(({ name, value }) => [name, value])),
|
|
110
|
+
);
|
|
111
|
+
formData.append('file', createReadStream(filepath));
|
|
112
|
+
|
|
113
|
+
const uploadResponse = await customFetch(url, {
|
|
114
|
+
method: 'post',
|
|
115
|
+
body: formData,
|
|
116
|
+
});
|
|
117
|
+
if (!uploadResponse.ok) {
|
|
118
|
+
return uploadResponse;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const stagedUploadPath = uploadResponse.data?.PostResponse?.Key;
|
|
122
|
+
|
|
123
|
+
const mutationRunResponse = await shopifyBulkOperationRunMutation(
|
|
124
|
+
credsPayload,
|
|
125
|
+
mutation,
|
|
126
|
+
stagedUploadPath,
|
|
127
|
+
{
|
|
128
|
+
apiVersion,
|
|
129
|
+
clientIdentifier,
|
|
130
|
+
returnAttrs: bulkOpAttrs,
|
|
131
|
+
},
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
if (!waitForResult) {
|
|
135
|
+
return mutationRunResponse;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const { ok: mutationRunOk, data: mutationRunData } = mutationRunResponse;
|
|
139
|
+
if (!mutationRunOk) {
|
|
140
|
+
return mutationRunResponse;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
bulkOperation = mutationRunData.bulkOperation;
|
|
144
|
+
bulkOperationId = gidToId(bulkOperation.id);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
while (['CREATED', 'RUNNING'].includes(bulkOperation?.status)) {
|
|
148
|
+
|
|
149
|
+
if (bulkOperation) {
|
|
150
|
+
await wait(5000);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const operationResponse = await shopifyBulkOperationGet(
|
|
154
|
+
credsPayload,
|
|
155
|
+
bulkOperationId,
|
|
156
|
+
{
|
|
157
|
+
apiVersion,
|
|
158
|
+
attrs: bulkOpAttrs,
|
|
159
|
+
},
|
|
160
|
+
);
|
|
161
|
+
if (!operationResponse.ok) {
|
|
162
|
+
return operationResponse;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
bulkOperation = operationResponse.data;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (bulkOperation.status !== 'COMPLETED') {
|
|
169
|
+
return {
|
|
170
|
+
ok: false,
|
|
171
|
+
error: {
|
|
172
|
+
code: 'BULK_OPERATION_FAILED',
|
|
173
|
+
message: `Bulk operation failed with status ${ bulkOperation.status }`,
|
|
174
|
+
details: bulkOperation,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const resultsResponse = await customFetch(bulkOperation.url);
|
|
180
|
+
if (!resultsResponse.ok) {
|
|
181
|
+
return resultsResponse;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const results = jsonlToObjectArray(resultsResponse.data);
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
ok: true,
|
|
188
|
+
data: results,
|
|
189
|
+
meta: {
|
|
190
|
+
bulkOperation,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const funcApiConfig = {
|
|
196
|
+
argsWarden,
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
module.exports = {
|
|
200
|
+
shopifyBulkMutationDo,
|
|
201
|
+
funcApiConfig,
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/*
|
|
205
|
+
curl -X POST "http://localhost:8000/shopifyBulkMutationDo" \
|
|
206
|
+
-H "Content-Type: application/json" \
|
|
207
|
+
-d '{
|
|
208
|
+
"credsPayload": { "credsPath": "shopify.au" },
|
|
209
|
+
"arg": "1234"
|
|
210
|
+
}'
|
|
211
|
+
*/
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// https://shopify.dev/docs/api/admin-graphql/latest/queries/bulkOperation
|
|
2
|
+
|
|
3
|
+
const { credsValidator } = require('../validators');
|
|
4
|
+
const { ArgsWarden, actionSingleOrMultiple } = require('../utils');
|
|
5
|
+
const { shopifyGetSingle } = require('./shopifyGetSingle');
|
|
6
|
+
|
|
7
|
+
const defaultAttrs = `
|
|
8
|
+
id
|
|
9
|
+
status
|
|
10
|
+
type
|
|
11
|
+
objectCount
|
|
12
|
+
url
|
|
13
|
+
errorCode
|
|
14
|
+
`.trim();
|
|
15
|
+
|
|
16
|
+
const argsWarden = new ArgsWarden([
|
|
17
|
+
['credsPayload', credsValidator],
|
|
18
|
+
['bulkOperationId'],
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
const shopifyBulkOperationGetSingle = async (
|
|
22
|
+
credsPayload,
|
|
23
|
+
bulkOperationId,
|
|
24
|
+
{
|
|
25
|
+
apiVersion,
|
|
26
|
+
attrs = defaultAttrs,
|
|
27
|
+
} = {},
|
|
28
|
+
) => {
|
|
29
|
+
return shopifyGetSingle(
|
|
30
|
+
credsPayload,
|
|
31
|
+
'bulkOperation',
|
|
32
|
+
bulkOperationId,
|
|
33
|
+
{
|
|
34
|
+
apiVersion,
|
|
35
|
+
attrs,
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const shopifyBulkOperationGet = async (
|
|
41
|
+
credsPayload,
|
|
42
|
+
bulkOperationId,
|
|
43
|
+
{
|
|
44
|
+
queueRunOptions,
|
|
45
|
+
apiVersion,
|
|
46
|
+
attrs = defaultAttrs,
|
|
47
|
+
} = {},
|
|
48
|
+
) => {
|
|
49
|
+
|
|
50
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
51
|
+
credsPayload,
|
|
52
|
+
bulkOperationId,
|
|
53
|
+
});
|
|
54
|
+
if (rejectResponse) {
|
|
55
|
+
return rejectResponse;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return actionSingleOrMultiple(
|
|
59
|
+
bulkOperationId,
|
|
60
|
+
shopifyBulkOperationGetSingle,
|
|
61
|
+
(bulkOperationIdItem) => ({
|
|
62
|
+
args: [credsPayload, bulkOperationIdItem, { apiVersion, attrs }],
|
|
63
|
+
}),
|
|
64
|
+
{
|
|
65
|
+
...(queueRunOptions ? { queueRunOptions } : {}),
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const funcApiConfig = {
|
|
71
|
+
argsWarden,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
module.exports = {
|
|
75
|
+
shopifyBulkOperationGet,
|
|
76
|
+
funcApiConfig,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/*
|
|
80
|
+
curl -X POST "http://localhost:8000/shopifyBulkOperationGet" \
|
|
81
|
+
-H "Content-Type: application/json" \
|
|
82
|
+
-d '{
|
|
83
|
+
"credsPayload": { "credsPath": "shopify.au" },
|
|
84
|
+
"bulkOperationId": "3525975375944"
|
|
85
|
+
}'
|
|
86
|
+
*/
|