@foxtware/mineral 0.1.16 → 0.1.17

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.
@@ -5,8 +5,8 @@ const { credsValidator } = require('../validators');
5
5
  const { etsyClient } = require('./etsy.utils');
6
6
 
7
7
  const updatePayloadWithListingIdValidator = (updatePayloadWithListingId) => {
8
- return valueProvided(updatePayloadWithListingId?.listingId)
9
- && valueProvided(updatePayloadWithListingId?.updatePayload);
8
+ const { listingId, ...updatePayload } = updatePayloadWithListingId;
9
+ return valueProvided(listingId) && Object.keys(updatePayload).length > 0;
10
10
  };
11
11
 
12
12
  const argsWarden = new ArgsWarden([
@@ -14,7 +14,7 @@ const argsWarden = new ArgsWarden([
14
14
  ['updatePayloadWithListingId', (updatePayloadWithListingId) => everyIfArray(updatePayloadWithListingIdValidator, updatePayloadWithListingId)],
15
15
  ]);
16
16
 
17
- const etsyListingupdatePayloadWithListingIdSingle = async (
17
+ const etsyListingInventoryUpdateSingle = async (
18
18
  credsPayload,
19
19
  updatePayloadWithListingId,
20
20
  {
@@ -24,9 +24,9 @@ const etsyListingupdatePayloadWithListingIdSingle = async (
24
24
  } = {},
25
25
  ) => {
26
26
 
27
- const {
28
- listingId,
29
- ...updatePayload
27
+ const {
28
+ listingId,
29
+ ...updatePayload
30
30
  } = updatePayloadWithListingId;
31
31
 
32
32
  return fetchClient.fetch({
@@ -44,7 +44,7 @@ const etsyListingupdatePayloadWithListingIdSingle = async (
44
44
  });
45
45
  };
46
46
 
47
- const etsyListingupdatePayloadWithListingId = async (
47
+ const etsyListingInventoryUpdate = async (
48
48
  credsPayload,
49
49
  updatePayloadWithListingId,
50
50
  {
@@ -65,7 +65,7 @@ const etsyListingupdatePayloadWithListingId = async (
65
65
 
66
66
  return actionSingleOrMultiple(
67
67
  updatePayloadWithListingId,
68
- etsyListingupdatePayloadWithListingIdSingle,
68
+ etsyListingInventoryUpdateSingle,
69
69
  (updatePayloadWithListingIdItem) => ({
70
70
  args: [credsPayload, updatePayloadWithListingIdItem, { params, inspect, fetchClient }],
71
71
  }),
@@ -80,12 +80,12 @@ const funcApiConfig = {
80
80
  };
81
81
 
82
82
  module.exports = {
83
- etsyListingupdatePayloadWithListingId,
83
+ etsyListingInventoryUpdate,
84
84
  funcApiConfig,
85
85
  };
86
86
 
87
87
  /*
88
- curl -X POST "http://localhost:8000/etsyListingupdatePayloadWithListingId" \
88
+ curl -X POST "http://localhost:8000/etsyListingInventoryUpdate" \
89
89
  -H "Content-Type: application/json" \
90
90
  -d '{
91
91
  "credsPayload": {
@@ -93,7 +93,7 @@ curl -X POST "http://localhost:8000/etsyListingupdatePayloadWithListingId" \
93
93
  },
94
94
  "updatePayloadWithListingId": {
95
95
  "listingId": "1234567890",
96
- "updatePayload": {}
96
+ "products": []
97
97
  }
98
98
  }'
99
99
  */
@@ -0,0 +1,211 @@
1
+ // https://shopify.dev/docs/api/admin-graphql/latest/mutations/metafieldDefinitionCreate
2
+ // https://shopify.dev/docs/api/admin-graphql/latest/queries/metafieldDefinition
3
+
4
+ const { credsValidator } = require('../validators');
5
+ const { ArgsWarden, credsFromPayload, objHasAny } = require('../utils');
6
+ const { shopifyClient } = require('./shopify.utils');
7
+ const { shopifyMutationDo } = require('./shopifyMutationDo');
8
+
9
+ const sourceMetafieldDefinitionAttrs = `
10
+ name
11
+ namespace
12
+ key
13
+ description
14
+ ownerType
15
+ pinnedPosition
16
+ type {
17
+ name
18
+ }
19
+ validations {
20
+ name
21
+ value
22
+ }
23
+ capabilities {
24
+ adminFilterable {
25
+ enabled
26
+ }
27
+ smartCollectionCondition {
28
+ enabled
29
+ }
30
+ uniqueValues {
31
+ enabled
32
+ }
33
+ }
34
+ `.trim();
35
+
36
+ const defaultReturnCreatedDefinitionAttrs = 'id name namespace key ownerType type { name }';
37
+
38
+ const metafieldDefinitionIdentifierValidator = (metafieldDefinitionIdentifier) => {
39
+ return objHasAny(metafieldDefinitionIdentifier, [
40
+ 'ownerType',
41
+ 'namespace',
42
+ 'key',
43
+ ]);
44
+ };
45
+
46
+ const argsWarden = new ArgsWarden([
47
+ ['fromStoreCredsPayload', credsValidator],
48
+ ['toStoreCredsPayload', credsValidator],
49
+ ['metafieldDefinitionIdentifier', metafieldDefinitionIdentifierValidator],
50
+ ]);
51
+
52
+ const metafieldDefinitionInputFromDefinition = (sourceDefinition) => {
53
+ const {
54
+ name,
55
+ namespace,
56
+ key,
57
+ description,
58
+ ownerType,
59
+ type,
60
+ validations,
61
+ capabilities,
62
+ pinnedPosition,
63
+ } = sourceDefinition;
64
+
65
+ const definitionInput = {
66
+ name,
67
+ namespace,
68
+ key,
69
+ ownerType,
70
+ type: type?.name,
71
+ ...(description && { description }),
72
+ ...(pinnedPosition != null && { pin: true }),
73
+ };
74
+
75
+ if (Array.isArray(validations) && validations.length) {
76
+ definitionInput.validations = validations.map(({ name: validationName, value }) => ({
77
+ name: validationName,
78
+ value,
79
+ }));
80
+ }
81
+
82
+ if (capabilities) {
83
+ definitionInput.capabilities = {
84
+ ...(capabilities.adminFilterable && {
85
+ adminFilterable: { enabled: capabilities.adminFilterable.enabled },
86
+ }),
87
+ ...(capabilities.smartCollectionCondition && {
88
+ smartCollectionCondition: { enabled: capabilities.smartCollectionCondition.enabled },
89
+ }),
90
+ ...(capabilities.uniqueValues && {
91
+ uniqueValues: { enabled: capabilities.uniqueValues.enabled },
92
+ }),
93
+ };
94
+ }
95
+
96
+ return definitionInput;
97
+ };
98
+
99
+ const fetchSourceMetafieldDefinition = async (
100
+ fromStoreCredsPayload,
101
+ metafieldDefinitionIdentifier,
102
+ {
103
+ apiVersion,
104
+ } = {},
105
+ ) => {
106
+ const creds = await credsFromPayload(fromStoreCredsPayload);
107
+
108
+ return shopifyClient.fetch({
109
+ method: 'post',
110
+ body: {
111
+ query: `
112
+ query GetMetafieldDefinition($identifier: MetafieldDefinitionIdentifierInput!) {
113
+ metafieldDefinition(identifier: $identifier) {
114
+ ${ sourceMetafieldDefinitionAttrs }
115
+ }
116
+ }
117
+ `,
118
+ variables: {
119
+ identifier: metafieldDefinitionIdentifier,
120
+ },
121
+ },
122
+ context: {
123
+ creds,
124
+ apiVersion,
125
+ resultPath: 'data.metafieldDefinition',
126
+ },
127
+ });
128
+ };
129
+
130
+ const shopifyMetafieldDefinitionPropagate = async (
131
+ fromStoreCredsPayload,
132
+ toStoreCredsPayload,
133
+ metafieldDefinitionIdentifier,
134
+ {
135
+ apiVersion,
136
+ returnCreatedDefinitionAttrs = defaultReturnCreatedDefinitionAttrs,
137
+ } = {},
138
+ ) => {
139
+
140
+ const rejectResponse = await argsWarden.responseIfRejectingArgs({
141
+ fromStoreCredsPayload,
142
+ toStoreCredsPayload,
143
+ metafieldDefinitionIdentifier,
144
+ });
145
+ if (rejectResponse) {
146
+ return rejectResponse;
147
+ }
148
+
149
+ const sourceResponse = await fetchSourceMetafieldDefinition(
150
+ fromStoreCredsPayload,
151
+ metafieldDefinitionIdentifier,
152
+ { apiVersion },
153
+ );
154
+
155
+ if (!sourceResponse.ok) {
156
+ return sourceResponse;
157
+ }
158
+
159
+ if (!sourceResponse.data) {
160
+ return {
161
+ ok: false,
162
+ error: {
163
+ code: 'NOT_FOUND',
164
+ message: 'Metafield definition not found on source store.',
165
+ details: metafieldDefinitionIdentifier,
166
+ },
167
+ };
168
+ }
169
+
170
+ const definitionInput = metafieldDefinitionInputFromDefinition(sourceResponse.data);
171
+
172
+ return shopifyMutationDo(
173
+ toStoreCredsPayload,
174
+ 'metafieldDefinitionCreate',
175
+ {
176
+ mutationVariables: {
177
+ definition: {
178
+ type: 'MetafieldDefinitionInput!',
179
+ value: definitionInput,
180
+ },
181
+ },
182
+ returnSchema: `
183
+ createdDefinition { ${ returnCreatedDefinitionAttrs } }
184
+ `.trim(),
185
+ apiVersion,
186
+ },
187
+ );
188
+ };
189
+
190
+ const funcApiConfig = {
191
+ argsWarden,
192
+ };
193
+
194
+ module.exports = {
195
+ shopifyMetafieldDefinitionPropagate,
196
+ funcApiConfig,
197
+ };
198
+
199
+ /*
200
+ curl -X POST "http://localhost:8000/shopifyMetafieldDefinitionPropagate" \
201
+ -H "Content-Type: application/json" \
202
+ -d '{
203
+ "fromStoreCredsPayload": { "credsPath": "shopify.au" },
204
+ "toStoreCredsPayload": { "credsPath": "shopify.us" },
205
+ "metafieldDefinitionIdentifier": {
206
+ "ownerType": "PRODUCT",
207
+ "namespace": "custom",
208
+ "key": "outfit_builder_image"
209
+ }
210
+ }'
211
+ */
@@ -141,7 +141,7 @@ const deployFunction = async ({
141
141
  console.log(deployCommand);
142
142
 
143
143
  try {
144
- await execCommand(deployCommand);
144
+ await execCommand(deployCommand, { interactive: true });
145
145
  } catch (error) {
146
146
  console.error(`Error deploying function ${ functionName }:`, error);
147
147
  return;
@@ -188,7 +188,7 @@ const deployFunction = async ({
188
188
  ].join(' ');
189
189
 
190
190
  console.log(schedulerCommand);
191
- await execCommand(schedulerCommand);
191
+ await execCommand(schedulerCommand, { interactive: true });
192
192
  } catch (error) {
193
193
  console.error(`Error handling scheduler job ${ jobName }:`, error);
194
194
  }
@@ -1,11 +1,28 @@
1
1
  const { spawn } = require('child_process');
2
2
 
3
- const execCommand = (command) => new Promise((resolve, reject) => {
3
+ const execCommand = (command, { interactive = false } = {}) => new Promise((resolve, reject) => {
4
4
  const childProcess = spawn(command, [], {
5
- stdio: 'pipe',
5
+ stdio: interactive ? 'inherit' : 'pipe',
6
6
  shell: true,
7
7
  });
8
8
 
9
+ if (interactive) {
10
+ childProcess.on('close', (code) => {
11
+ if (code === 0) {
12
+ resolve({ stdout: '', stderr: '', command });
13
+ return;
14
+ }
15
+
16
+ reject({ stdout: '', stderr: '', command, code });
17
+ });
18
+
19
+ childProcess.on('error', (error) => {
20
+ reject({ error, command });
21
+ });
22
+
23
+ return;
24
+ }
25
+
9
26
  let stdout = '';
10
27
  let stderr = '';
11
28
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foxtware/mineral",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "bin": {
5
5
  "mineral": "bin/mineral.js"
6
6
  },