@keystrokehq/shopify 0.0.11 → 0.0.16-integration-id-canonicalization.0
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/README.md +14 -153
- package/dist/{schemas.d.mts → common-C2s35du9.d.mts} +3 -2
- package/dist/{schemas.mjs → common-JZyHdK6p.mjs} +3 -3
- package/dist/credential-sets/index.d.mts +2 -0
- package/dist/credential-sets/index.mjs +4 -0
- package/dist/index.d.mts +4 -1
- package/dist/index.mjs +6 -1
- package/dist/operations/index.d.mts +2 -0
- package/dist/operations/index.mjs +3 -0
- package/dist/schemas/index.d.mts +2 -0
- package/dist/schemas/index.mjs +3 -0
- package/dist/shopify-app.credential-set-DuAYUhzY.d.mts +65 -0
- package/dist/shopify-app.credential-set-M3vKwTji.mjs +17 -0
- package/dist/{integration-vSl3XHTG.mjs → shopify.credential-set-CaxST3GP.mjs} +6 -141
- package/dist/update-shopify-product.operation-ByYhZggW.mjs +1972 -0
- package/dist/update-shopify-product.operation-Db_kLuJa.d.mts +2817 -0
- package/package.json +11 -67
- package/dist/_official/index.d.mts +0 -38
- package/dist/_official/index.mjs +0 -3
- package/dist/_runtime/index.d.mts +0 -56
- package/dist/_runtime/index.mjs +0 -150
- package/dist/articles.d.mts +0 -174
- package/dist/articles.mjs +0 -252
- package/dist/blogs.d.mts +0 -113
- package/dist/blogs.mjs +0 -174
- package/dist/client.d.mts +0 -22
- package/dist/client.mjs +0 -90
- package/dist/collections.d.mts +0 -140
- package/dist/collections.mjs +0 -209
- package/dist/connection.d.mts +0 -2
- package/dist/connection.mjs +0 -3
- package/dist/customers.d.mts +0 -161
- package/dist/customers.mjs +0 -225
- package/dist/events.d.mts +0 -181
- package/dist/events.mjs +0 -67
- package/dist/factory-BKmxl2-8.mjs +0 -7
- package/dist/fulfillments.d.mts +0 -99
- package/dist/fulfillments.mjs +0 -167
- package/dist/integration-HrSKAMfF.d.mts +0 -70
- package/dist/inventory.d.mts +0 -103
- package/dist/inventory.mjs +0 -182
- package/dist/locations.d.mts +0 -47
- package/dist/locations.mjs +0 -81
- package/dist/messaging.d.mts +0 -1
- package/dist/messaging.mjs +0 -1
- package/dist/operation-helpers-CKEDIx0o.mjs +0 -21
- package/dist/orders.d.mts +0 -229
- package/dist/orders.mjs +0 -271
- package/dist/products.d.mts +0 -155
- package/dist/products.mjs +0 -171
- package/dist/shop.d.mts +0 -20
- package/dist/shop.mjs +0 -31
|
@@ -0,0 +1,1972 @@
|
|
|
1
|
+
import { S as shopifyShopSchema, b as shopifyProductSchema, c as shopifyGlobalIdSchema, d as shopifyInventoryItemSchema, f as shopifyInventoryLevelSchema, i as shopifyConnectionNodesSchema, l as shopifyGraphqlErrorSchema, m as shopifyLocationSchema, n as shopifyBlogSchema, o as shopifyCustomerSchema, p as shopifyJobSchema, r as shopifyCollectionSchema, s as shopifyFulfillmentSchema, t as shopifyArticleSchema, v as shopifyOrderSchema, w as shopifyUserErrorSchema } from "./common-JZyHdK6p.mjs";
|
|
2
|
+
import { t as shopifyCredentialSet } from "./shopify.credential-set-CaxST3GP.mjs";
|
|
3
|
+
import { Operation } from "@keystrokehq/core";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { CredentialRevokedError } from "@keystrokehq/core/errors";
|
|
6
|
+
import { createAdminApiClient, createAdminRestApiClient } from "@shopify/admin-api-client";
|
|
7
|
+
|
|
8
|
+
//#region src/schemas/collections.ts
|
|
9
|
+
const collectionSelection = `
|
|
10
|
+
id
|
|
11
|
+
title
|
|
12
|
+
handle
|
|
13
|
+
descriptionHtml
|
|
14
|
+
updatedAt
|
|
15
|
+
image {
|
|
16
|
+
url
|
|
17
|
+
altText
|
|
18
|
+
}
|
|
19
|
+
seo {
|
|
20
|
+
title
|
|
21
|
+
description
|
|
22
|
+
}
|
|
23
|
+
`;
|
|
24
|
+
const collectionMutationInputSchema = z.object({
|
|
25
|
+
title: z.string().min(1).optional(),
|
|
26
|
+
handle: z.string().min(1).optional(),
|
|
27
|
+
descriptionHtml: z.string().optional(),
|
|
28
|
+
seo: z.object({
|
|
29
|
+
title: z.string().optional(),
|
|
30
|
+
description: z.string().optional()
|
|
31
|
+
}).optional()
|
|
32
|
+
});
|
|
33
|
+
const collectionMutationResponseSchema = z.object({
|
|
34
|
+
collection: shopifyCollectionSchema.nullable(),
|
|
35
|
+
userErrors: z.array(shopifyUserErrorSchema)
|
|
36
|
+
});
|
|
37
|
+
const listCollectionsResponseSchema = z.object({ collections: shopifyConnectionNodesSchema(shopifyCollectionSchema) });
|
|
38
|
+
const getCollectionResponseSchema = z.object({ collection: shopifyCollectionSchema.nullable() });
|
|
39
|
+
const deleteCollectionResponseSchema = z.object({
|
|
40
|
+
deletedCollectionId: shopifyGlobalIdSchema.nullable(),
|
|
41
|
+
userErrors: z.array(shopifyUserErrorSchema)
|
|
42
|
+
});
|
|
43
|
+
const removeProductsResponseSchema = z.object({
|
|
44
|
+
job: shopifyJobSchema.nullable(),
|
|
45
|
+
userErrors: z.array(shopifyUserErrorSchema)
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/utils/client.ts
|
|
50
|
+
const DEFAULT_SHOPIFY_API_VERSION = "2025-01";
|
|
51
|
+
function normalizeShopifyError(error, methodPath) {
|
|
52
|
+
if (error instanceof CredentialRevokedError) return error;
|
|
53
|
+
if (error instanceof Error) {
|
|
54
|
+
const maybeStatus = error;
|
|
55
|
+
const status = maybeStatus.status ?? maybeStatus.response?.status;
|
|
56
|
+
if (status === 401 || status === 403) return new CredentialRevokedError("shopify", `Shopify authentication failed while calling \`${methodPath}\`. The stored credentials for shopify may be revoked or expired.`);
|
|
57
|
+
if (status === 429) return new Error(`Shopify API throttled while calling \`${methodPath}\`: ${error.message}`, { cause: error });
|
|
58
|
+
return new Error(`Shopify API call failed while calling \`${methodPath}\`: ${error.message}`, { cause: error });
|
|
59
|
+
}
|
|
60
|
+
return /* @__PURE__ */ new Error(`Shopify API call failed while calling \`${methodPath}\`.`);
|
|
61
|
+
}
|
|
62
|
+
function createShopifyCredentialError(methodPath) {
|
|
63
|
+
return new CredentialRevokedError("shopify", `Shopify authentication failed while calling \`${methodPath}\`. The stored credentials for shopify may be revoked or expired.`);
|
|
64
|
+
}
|
|
65
|
+
function assertGraphqlSuccess(response, methodPath) {
|
|
66
|
+
const status = response.errors?.networkStatusCode;
|
|
67
|
+
if (status === 401 || status === 403) throw createShopifyCredentialError(methodPath);
|
|
68
|
+
if (status === 429) throw new Error(`Shopify API throttled while calling \`${methodPath}\`: ${response.errors?.message ?? "rate limited"}`);
|
|
69
|
+
if (response.errors?.graphQLErrors?.length) {
|
|
70
|
+
const messages = response.errors.graphQLErrors.map((error) => shopifyGraphqlErrorSchema.parse(error).message).join("; ");
|
|
71
|
+
throw new Error(`Shopify GraphQL errors while calling \`${methodPath}\`: ${messages}`);
|
|
72
|
+
}
|
|
73
|
+
if (response.errors?.message) throw new Error(`Shopify API call failed while calling \`${methodPath}\`: ${response.errors.message}`);
|
|
74
|
+
if (response.data === void 0) throw new Error(`Shopify API call returned no data while calling \`${methodPath}\`.`);
|
|
75
|
+
}
|
|
76
|
+
async function parseRestResponse(response, schema, methodPath) {
|
|
77
|
+
if (response.status === 401 || response.status === 403) throw createShopifyCredentialError(methodPath);
|
|
78
|
+
if (response.status === 429) throw new Error(`Shopify API throttled while calling \`${methodPath}\`.`);
|
|
79
|
+
const payload = response.status === 204 ? null : await response.json();
|
|
80
|
+
if (!response.ok) throw new Error(`Shopify REST API call failed while calling \`${methodPath}\`: HTTP ${response.status}`);
|
|
81
|
+
return schema.parse(payload);
|
|
82
|
+
}
|
|
83
|
+
function createShopifyClient(credentials) {
|
|
84
|
+
const graphqlClient = createAdminApiClient({
|
|
85
|
+
storeDomain: credentials.SHOPIFY_STORE_DOMAIN,
|
|
86
|
+
accessToken: credentials.SHOPIFY_ACCESS_TOKEN,
|
|
87
|
+
apiVersion: DEFAULT_SHOPIFY_API_VERSION
|
|
88
|
+
});
|
|
89
|
+
const restClient = createAdminRestApiClient({
|
|
90
|
+
storeDomain: credentials.SHOPIFY_STORE_DOMAIN,
|
|
91
|
+
accessToken: credentials.SHOPIFY_ACCESS_TOKEN,
|
|
92
|
+
apiVersion: DEFAULT_SHOPIFY_API_VERSION
|
|
93
|
+
});
|
|
94
|
+
async function rawGraphql(query, variables) {
|
|
95
|
+
try {
|
|
96
|
+
return await graphqlClient.request(query, { variables });
|
|
97
|
+
} catch (error) {
|
|
98
|
+
throw normalizeShopifyError(error, "graphql");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function graphql(query, schema, options) {
|
|
102
|
+
const response = await rawGraphql(query, options?.variables);
|
|
103
|
+
assertGraphqlSuccess(response, "graphql");
|
|
104
|
+
return schema.parse(response.data);
|
|
105
|
+
}
|
|
106
|
+
async function rest(method, path, schema, options) {
|
|
107
|
+
const methodPath = `${method} ${path}`;
|
|
108
|
+
try {
|
|
109
|
+
switch (method) {
|
|
110
|
+
case "GET": return await parseRestResponse(await restClient.get(path, options), schema, methodPath);
|
|
111
|
+
case "POST": return await parseRestResponse(await restClient.post(path, {
|
|
112
|
+
...options,
|
|
113
|
+
data: options?.data ?? {}
|
|
114
|
+
}), schema, methodPath);
|
|
115
|
+
case "PUT": return await parseRestResponse(await restClient.put(path, {
|
|
116
|
+
...options,
|
|
117
|
+
data: options?.data ?? {}
|
|
118
|
+
}), schema, methodPath);
|
|
119
|
+
case "DELETE": return await parseRestResponse(await restClient.delete(path, options), schema, methodPath);
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
throw normalizeShopifyError(error, methodPath);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
rawGraphql,
|
|
127
|
+
graphql,
|
|
128
|
+
rest
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region src/utils/graphql-helpers.ts
|
|
134
|
+
const shopifyPageInputSchema = z.object({
|
|
135
|
+
first: z.number().int().min(1).max(100).optional().default(25),
|
|
136
|
+
after: z.string().optional(),
|
|
137
|
+
query: z.string().optional()
|
|
138
|
+
});
|
|
139
|
+
const shopifyProductIdsInputSchema = z.array(shopifyGlobalIdSchema).min(1).max(250);
|
|
140
|
+
function assertNoUserErrors(userErrors) {
|
|
141
|
+
if (userErrors.length === 0) return;
|
|
142
|
+
const message = userErrors.map((error) => error.field && error.field.length > 0 ? `${error.field.join(".")}: ${error.message}` : error.message).join("; ");
|
|
143
|
+
throw new Error(`Shopify mutation returned user errors: ${message}`);
|
|
144
|
+
}
|
|
145
|
+
function omitUndefined(input) {
|
|
146
|
+
return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== void 0));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
//#endregion
|
|
150
|
+
//#region src/operations/add-products-to-shopify-collection.operation.ts
|
|
151
|
+
const addProductsToCollectionOperation = new Operation({
|
|
152
|
+
credentialSets: [shopifyCredentialSet],
|
|
153
|
+
id: "shopify.add-products-to-shopify-collection",
|
|
154
|
+
name: "Add Products To Shopify Collection",
|
|
155
|
+
description: "Add products to a manual Shopify collection.",
|
|
156
|
+
needsApproval: true,
|
|
157
|
+
input: z.object({
|
|
158
|
+
id: shopifyGlobalIdSchema,
|
|
159
|
+
productIds: shopifyProductIdsInputSchema
|
|
160
|
+
}),
|
|
161
|
+
output: shopifyCollectionSchema,
|
|
162
|
+
run: async (input, context) => {
|
|
163
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
164
|
+
mutation AddProductsToCollection($id: ID!, $productIds: [ID!]!) {
|
|
165
|
+
collectionAddProducts(id: $id, productIds: $productIds) {
|
|
166
|
+
collection {
|
|
167
|
+
${collectionSelection}
|
|
168
|
+
}
|
|
169
|
+
userErrors {
|
|
170
|
+
field
|
|
171
|
+
message
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
`, z.object({ collectionAddProducts: collectionMutationResponseSchema }), { variables: {
|
|
176
|
+
id: input.id,
|
|
177
|
+
productIds: input.productIds
|
|
178
|
+
} });
|
|
179
|
+
assertNoUserErrors(response.collectionAddProducts.userErrors);
|
|
180
|
+
if (!response.collectionAddProducts.collection) throw new Error(`Shopify did not return the updated collection: ${input.id}`);
|
|
181
|
+
return response.collectionAddProducts.collection;
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/schemas/inventory.ts
|
|
187
|
+
const inventoryItemSelection = `
|
|
188
|
+
id
|
|
189
|
+
sku
|
|
190
|
+
tracked
|
|
191
|
+
`;
|
|
192
|
+
const inventoryLevelSelection = `
|
|
193
|
+
id
|
|
194
|
+
quantities(names: ["available", "committed", "incoming", "on_hand", "reserved"]) {
|
|
195
|
+
name
|
|
196
|
+
quantity
|
|
197
|
+
}
|
|
198
|
+
item {
|
|
199
|
+
${inventoryItemSelection}
|
|
200
|
+
}
|
|
201
|
+
location {
|
|
202
|
+
id
|
|
203
|
+
name
|
|
204
|
+
isActive
|
|
205
|
+
fulfillsOnlineOrders
|
|
206
|
+
}
|
|
207
|
+
`;
|
|
208
|
+
const listInventoryItemsResponseSchema = z.object({ inventoryItems: shopifyConnectionNodesSchema(shopifyInventoryItemSchema) });
|
|
209
|
+
const getInventoryItemResponseSchema = z.object({ inventoryItem: shopifyInventoryItemSchema.nullable() });
|
|
210
|
+
const inventoryLevelsResponseSchema = z.object({ inventoryItem: z.object({ inventoryLevels: shopifyConnectionNodesSchema(shopifyInventoryLevelSchema) }).nullable() });
|
|
211
|
+
const inventoryAdjustmentResponseSchema = z.object({
|
|
212
|
+
inventoryAdjustmentGroup: z.object({
|
|
213
|
+
createdAt: z.iso.datetime().optional(),
|
|
214
|
+
reason: z.string(),
|
|
215
|
+
referenceDocumentUri: z.string().nullable().optional(),
|
|
216
|
+
changes: z.array(z.object({
|
|
217
|
+
name: z.string(),
|
|
218
|
+
delta: z.number()
|
|
219
|
+
}))
|
|
220
|
+
}).nullable(),
|
|
221
|
+
userErrors: z.array(shopifyUserErrorSchema)
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
//#endregion
|
|
225
|
+
//#region src/operations/adjust-shopify-inventory-quantities.operation.ts
|
|
226
|
+
const adjustInventoryQuantitiesOperation = new Operation({
|
|
227
|
+
credentialSets: [shopifyCredentialSet],
|
|
228
|
+
id: "shopify.adjust-shopify-inventory-quantities",
|
|
229
|
+
name: "Adjust Shopify Inventory Quantities",
|
|
230
|
+
description: "Adjust inventory quantities at specific Shopify locations.",
|
|
231
|
+
needsApproval: true,
|
|
232
|
+
input: z.object({
|
|
233
|
+
name: z.string().min(1).default("available"),
|
|
234
|
+
reason: z.string().min(1),
|
|
235
|
+
referenceDocumentUri: z.string().optional(),
|
|
236
|
+
changes: z.array(z.object({
|
|
237
|
+
inventoryItemId: shopifyGlobalIdSchema,
|
|
238
|
+
locationId: shopifyGlobalIdSchema,
|
|
239
|
+
delta: z.number().int()
|
|
240
|
+
})).min(1)
|
|
241
|
+
}),
|
|
242
|
+
output: z.object({
|
|
243
|
+
createdAt: z.iso.datetime().optional(),
|
|
244
|
+
reason: z.string(),
|
|
245
|
+
referenceDocumentUri: z.string().nullable().optional(),
|
|
246
|
+
changes: z.array(z.object({
|
|
247
|
+
name: z.string(),
|
|
248
|
+
delta: z.number()
|
|
249
|
+
}))
|
|
250
|
+
}),
|
|
251
|
+
run: async (input, context) => {
|
|
252
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
253
|
+
mutation AdjustInventoryQuantities($input: InventoryAdjustQuantitiesInput!) {
|
|
254
|
+
inventoryAdjustQuantities(input: $input) {
|
|
255
|
+
inventoryAdjustmentGroup {
|
|
256
|
+
createdAt
|
|
257
|
+
reason
|
|
258
|
+
referenceDocumentUri
|
|
259
|
+
changes {
|
|
260
|
+
name
|
|
261
|
+
delta
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
userErrors {
|
|
265
|
+
field
|
|
266
|
+
message
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
`, z.object({ inventoryAdjustQuantities: inventoryAdjustmentResponseSchema }), { variables: { input: {
|
|
271
|
+
name: input.name,
|
|
272
|
+
reason: input.reason,
|
|
273
|
+
referenceDocumentUri: input.referenceDocumentUri,
|
|
274
|
+
changes: input.changes
|
|
275
|
+
} } });
|
|
276
|
+
assertNoUserErrors(response.inventoryAdjustQuantities.userErrors);
|
|
277
|
+
if (!response.inventoryAdjustQuantities.inventoryAdjustmentGroup) throw new Error("Shopify did not return the inventory adjustment group.");
|
|
278
|
+
return response.inventoryAdjustQuantities.inventoryAdjustmentGroup;
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
//#endregion
|
|
283
|
+
//#region src/schemas/orders.ts
|
|
284
|
+
const orderSelection$1 = `
|
|
285
|
+
id
|
|
286
|
+
name
|
|
287
|
+
createdAt
|
|
288
|
+
updatedAt
|
|
289
|
+
cancelledAt
|
|
290
|
+
email
|
|
291
|
+
note
|
|
292
|
+
tags
|
|
293
|
+
displayFinancialStatus
|
|
294
|
+
displayFulfillmentStatus
|
|
295
|
+
currentTotalPriceSet {
|
|
296
|
+
shopMoney {
|
|
297
|
+
amount
|
|
298
|
+
currencyCode
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
customer {
|
|
302
|
+
id
|
|
303
|
+
displayName
|
|
304
|
+
firstName
|
|
305
|
+
lastName
|
|
306
|
+
email
|
|
307
|
+
phone
|
|
308
|
+
createdAt
|
|
309
|
+
updatedAt
|
|
310
|
+
}
|
|
311
|
+
`;
|
|
312
|
+
const orderLineItemVariantSchema = z.object({
|
|
313
|
+
variantId: shopifyGlobalIdSchema,
|
|
314
|
+
quantity: z.number().int().min(1)
|
|
315
|
+
});
|
|
316
|
+
const orderLineItemCustomSchema = z.object({
|
|
317
|
+
title: z.string().min(1),
|
|
318
|
+
quantity: z.number().int().min(1),
|
|
319
|
+
price: z.number().positive()
|
|
320
|
+
});
|
|
321
|
+
const orderCreateLineItemSchema = z.union([orderLineItemVariantSchema, orderLineItemCustomSchema]);
|
|
322
|
+
const orderAddressSchema = z.object({
|
|
323
|
+
address1: z.string().min(1),
|
|
324
|
+
address2: z.string().optional(),
|
|
325
|
+
city: z.string().min(1),
|
|
326
|
+
province: z.string().optional(),
|
|
327
|
+
country: z.string().min(1),
|
|
328
|
+
zip: z.string().optional(),
|
|
329
|
+
firstName: z.string().optional(),
|
|
330
|
+
lastName: z.string().optional(),
|
|
331
|
+
phone: z.string().optional()
|
|
332
|
+
});
|
|
333
|
+
const orderMutationResponseSchema = z.object({
|
|
334
|
+
order: shopifyOrderSchema.nullable(),
|
|
335
|
+
userErrors: z.array(shopifyUserErrorSchema)
|
|
336
|
+
});
|
|
337
|
+
const orderCreateUserErrorSchema = shopifyUserErrorSchema.extend({ code: z.string().optional() });
|
|
338
|
+
const orderCancelUserErrorSchema = shopifyUserErrorSchema.extend({ code: z.string().optional() });
|
|
339
|
+
const listOrdersResponseSchema = z.object({ orders: shopifyConnectionNodesSchema(shopifyOrderSchema) });
|
|
340
|
+
const getOrderResponseSchema = z.object({ order: shopifyOrderSchema.nullable() });
|
|
341
|
+
const createOrderResponseSchema = z.object({
|
|
342
|
+
order: shopifyOrderSchema.nullable(),
|
|
343
|
+
userErrors: z.array(orderCreateUserErrorSchema)
|
|
344
|
+
});
|
|
345
|
+
const cancelOrderResponseSchema = z.object({
|
|
346
|
+
job: shopifyJobSchema.nullable(),
|
|
347
|
+
orderCancelUserErrors: z.array(orderCancelUserErrorSchema)
|
|
348
|
+
});
|
|
349
|
+
const orderCreateInputSchema = z.object({
|
|
350
|
+
currency: z.string().length(3),
|
|
351
|
+
email: z.email().optional(),
|
|
352
|
+
note: z.string().optional(),
|
|
353
|
+
tags: z.array(z.string()).optional(),
|
|
354
|
+
customerId: shopifyGlobalIdSchema.optional(),
|
|
355
|
+
lineItems: z.array(orderCreateLineItemSchema).min(1)
|
|
356
|
+
});
|
|
357
|
+
const orderUpdateInputSchema = z.object({
|
|
358
|
+
id: shopifyGlobalIdSchema,
|
|
359
|
+
email: z.email().optional(),
|
|
360
|
+
note: z.string().optional(),
|
|
361
|
+
tags: z.array(z.string()).optional(),
|
|
362
|
+
shippingAddress: orderAddressSchema.optional()
|
|
363
|
+
});
|
|
364
|
+
const orderCancelReasonSchema = z.enum([
|
|
365
|
+
"CUSTOMER",
|
|
366
|
+
"DECLINED",
|
|
367
|
+
"FRAUD",
|
|
368
|
+
"INVENTORY",
|
|
369
|
+
"OTHER",
|
|
370
|
+
"STAFF"
|
|
371
|
+
]);
|
|
372
|
+
function buildOrderCreateLineItems(lineItems, currency) {
|
|
373
|
+
return lineItems.map((lineItem) => {
|
|
374
|
+
if ("variantId" in lineItem) return {
|
|
375
|
+
variantId: lineItem.variantId,
|
|
376
|
+
quantity: lineItem.quantity
|
|
377
|
+
};
|
|
378
|
+
return {
|
|
379
|
+
title: lineItem.title,
|
|
380
|
+
quantity: lineItem.quantity,
|
|
381
|
+
priceSet: { shopMoney: {
|
|
382
|
+
amount: lineItem.price,
|
|
383
|
+
currencyCode: currency
|
|
384
|
+
} }
|
|
385
|
+
};
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
//#endregion
|
|
390
|
+
//#region src/operations/cancel-shopify-order.operation.ts
|
|
391
|
+
const cancelOrderOperation = new Operation({
|
|
392
|
+
credentialSets: [shopifyCredentialSet],
|
|
393
|
+
id: "shopify.cancel-shopify-order",
|
|
394
|
+
name: "Cancel Shopify Order",
|
|
395
|
+
description: "Cancel a Shopify order and return the asynchronous cancellation job.",
|
|
396
|
+
needsApproval: true,
|
|
397
|
+
input: z.object({
|
|
398
|
+
orderId: shopifyGlobalIdSchema,
|
|
399
|
+
reason: orderCancelReasonSchema,
|
|
400
|
+
restock: z.boolean(),
|
|
401
|
+
notifyCustomer: z.boolean().optional(),
|
|
402
|
+
staffNote: z.string().max(255).optional(),
|
|
403
|
+
refundMethod: z.object({ originalPaymentMethodsRefund: z.boolean().optional() }).optional()
|
|
404
|
+
}),
|
|
405
|
+
output: shopifyJobSchema,
|
|
406
|
+
run: async (input, context) => {
|
|
407
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
408
|
+
mutation CancelOrder(
|
|
409
|
+
$orderId: ID!
|
|
410
|
+
$reason: OrderCancelReason!
|
|
411
|
+
$restock: Boolean!
|
|
412
|
+
$notifyCustomer: Boolean
|
|
413
|
+
$staffNote: String
|
|
414
|
+
$refundMethod: OrderCancelRefundMethodInput
|
|
415
|
+
) {
|
|
416
|
+
orderCancel(
|
|
417
|
+
orderId: $orderId
|
|
418
|
+
reason: $reason
|
|
419
|
+
restock: $restock
|
|
420
|
+
notifyCustomer: $notifyCustomer
|
|
421
|
+
staffNote: $staffNote
|
|
422
|
+
refundMethod: $refundMethod
|
|
423
|
+
) {
|
|
424
|
+
job {
|
|
425
|
+
id
|
|
426
|
+
done
|
|
427
|
+
}
|
|
428
|
+
orderCancelUserErrors {
|
|
429
|
+
field
|
|
430
|
+
message
|
|
431
|
+
code
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
`, z.object({ orderCancel: cancelOrderResponseSchema }), { variables: omitUndefined(input) });
|
|
436
|
+
assertNoUserErrors(response.orderCancel.orderCancelUserErrors);
|
|
437
|
+
if (!response.orderCancel.job) throw new Error(`Shopify did not return a cancellation job for order: ${input.orderId}`);
|
|
438
|
+
return response.orderCancel.job;
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
//#endregion
|
|
443
|
+
//#region src/schemas/articles.ts
|
|
444
|
+
const blogSelection$1 = `
|
|
445
|
+
id
|
|
446
|
+
title
|
|
447
|
+
handle
|
|
448
|
+
createdAt
|
|
449
|
+
updatedAt
|
|
450
|
+
commentPolicy
|
|
451
|
+
templateSuffix
|
|
452
|
+
`;
|
|
453
|
+
const articleSelection = `
|
|
454
|
+
id
|
|
455
|
+
title
|
|
456
|
+
handle
|
|
457
|
+
blog {
|
|
458
|
+
${blogSelection$1}
|
|
459
|
+
}
|
|
460
|
+
author {
|
|
461
|
+
name
|
|
462
|
+
}
|
|
463
|
+
body
|
|
464
|
+
summary
|
|
465
|
+
tags
|
|
466
|
+
image {
|
|
467
|
+
url
|
|
468
|
+
altText
|
|
469
|
+
}
|
|
470
|
+
publishedAt
|
|
471
|
+
updatedAt
|
|
472
|
+
`;
|
|
473
|
+
const articleMutationInputSchema = z.object({
|
|
474
|
+
blogId: shopifyGlobalIdSchema.optional(),
|
|
475
|
+
title: z.string().min(1).optional(),
|
|
476
|
+
handle: z.string().min(1).optional(),
|
|
477
|
+
body: z.string().optional(),
|
|
478
|
+
summary: z.string().optional(),
|
|
479
|
+
authorName: z.string().optional(),
|
|
480
|
+
isPublished: z.boolean().optional(),
|
|
481
|
+
publishDate: z.iso.datetime().optional(),
|
|
482
|
+
tags: z.array(z.string()).optional()
|
|
483
|
+
});
|
|
484
|
+
const articleResponseSchema = z.object({
|
|
485
|
+
id: shopifyGlobalIdSchema,
|
|
486
|
+
title: z.string(),
|
|
487
|
+
handle: z.string(),
|
|
488
|
+
blog: z.object({
|
|
489
|
+
id: shopifyGlobalIdSchema,
|
|
490
|
+
title: z.string(),
|
|
491
|
+
handle: z.string(),
|
|
492
|
+
createdAt: z.iso.datetime().optional(),
|
|
493
|
+
updatedAt: z.iso.datetime().optional(),
|
|
494
|
+
commentPolicy: z.string().nullable().optional(),
|
|
495
|
+
templateSuffix: z.string().nullable().optional()
|
|
496
|
+
}).nullable().optional(),
|
|
497
|
+
author: z.object({ name: z.string().nullable().optional() }).nullable().optional(),
|
|
498
|
+
body: z.string().nullable().optional(),
|
|
499
|
+
summary: z.string().nullable().optional(),
|
|
500
|
+
tags: z.array(z.string()).optional(),
|
|
501
|
+
image: z.object({
|
|
502
|
+
url: z.url(),
|
|
503
|
+
altText: z.string().nullable().optional()
|
|
504
|
+
}).nullable().optional(),
|
|
505
|
+
publishedAt: z.iso.datetime().nullable().optional(),
|
|
506
|
+
updatedAt: z.iso.datetime().optional()
|
|
507
|
+
});
|
|
508
|
+
const articleMutationPayloadSchema = z.object({
|
|
509
|
+
article: articleResponseSchema.nullable(),
|
|
510
|
+
userErrors: z.array(shopifyUserErrorSchema.extend({ code: z.string().optional() }))
|
|
511
|
+
});
|
|
512
|
+
const listArticlesResponseSchema = z.object({ articles: shopifyConnectionNodesSchema(articleResponseSchema) });
|
|
513
|
+
const getArticleResponseSchema = z.object({ article: articleResponseSchema.nullable() });
|
|
514
|
+
const deleteArticleResponseSchema = z.object({
|
|
515
|
+
deletedArticleId: shopifyGlobalIdSchema.nullable(),
|
|
516
|
+
userErrors: z.array(shopifyUserErrorSchema.extend({ code: z.string().optional() }))
|
|
517
|
+
});
|
|
518
|
+
function normalizeArticle(article) {
|
|
519
|
+
return {
|
|
520
|
+
id: article.id,
|
|
521
|
+
title: article.title,
|
|
522
|
+
handle: article.handle,
|
|
523
|
+
blog: article.blog ?? null,
|
|
524
|
+
author: article.author?.name ?? null,
|
|
525
|
+
body: article.body ?? null,
|
|
526
|
+
summary: article.summary ?? null,
|
|
527
|
+
tags: article.tags,
|
|
528
|
+
image: article.image ?? null,
|
|
529
|
+
publishedAt: article.publishedAt ?? null,
|
|
530
|
+
updatedAt: article.updatedAt
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
function buildArticleInput(input) {
|
|
534
|
+
return omitUndefined({
|
|
535
|
+
blogId: input.blogId,
|
|
536
|
+
title: input.title,
|
|
537
|
+
handle: input.handle,
|
|
538
|
+
body: input.body,
|
|
539
|
+
summary: input.summary,
|
|
540
|
+
author: input.authorName ? { name: input.authorName } : void 0,
|
|
541
|
+
isPublished: input.isPublished,
|
|
542
|
+
publishDate: input.publishDate,
|
|
543
|
+
tags: input.tags
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
//#endregion
|
|
548
|
+
//#region src/operations/create-shopify-article.operation.ts
|
|
549
|
+
const createArticleOperation = new Operation({
|
|
550
|
+
credentialSets: [shopifyCredentialSet],
|
|
551
|
+
id: "shopify.create-shopify-article",
|
|
552
|
+
name: "Create Shopify Article",
|
|
553
|
+
description: "Create an article in the connected Shopify store.",
|
|
554
|
+
needsApproval: true,
|
|
555
|
+
input: articleMutationInputSchema.extend({
|
|
556
|
+
blogId: shopifyGlobalIdSchema,
|
|
557
|
+
title: z.string().min(1)
|
|
558
|
+
}),
|
|
559
|
+
output: shopifyArticleSchema,
|
|
560
|
+
run: async (input, context) => {
|
|
561
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
562
|
+
mutation CreateArticle($article: ArticleCreateInput!) {
|
|
563
|
+
articleCreate(article: $article) {
|
|
564
|
+
article {
|
|
565
|
+
${articleSelection}
|
|
566
|
+
}
|
|
567
|
+
userErrors {
|
|
568
|
+
code
|
|
569
|
+
field
|
|
570
|
+
message
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
`, z.object({ articleCreate: articleMutationPayloadSchema }), { variables: { article: buildArticleInput(input) } });
|
|
575
|
+
assertNoUserErrors(response.articleCreate.userErrors);
|
|
576
|
+
if (!response.articleCreate.article) throw new Error("Shopify did not return the created article.");
|
|
577
|
+
return normalizeArticle(response.articleCreate.article);
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
//#endregion
|
|
582
|
+
//#region src/schemas/blogs.ts
|
|
583
|
+
const blogSelection = `
|
|
584
|
+
id
|
|
585
|
+
title
|
|
586
|
+
handle
|
|
587
|
+
createdAt
|
|
588
|
+
updatedAt
|
|
589
|
+
commentPolicy
|
|
590
|
+
templateSuffix
|
|
591
|
+
`;
|
|
592
|
+
const blogCommentPolicySchema = z.enum([
|
|
593
|
+
"DISABLED",
|
|
594
|
+
"HIDDEN",
|
|
595
|
+
"MODERATED",
|
|
596
|
+
"OPEN"
|
|
597
|
+
]);
|
|
598
|
+
const blogMutationInputSchema = z.object({
|
|
599
|
+
title: z.string().min(1).optional(),
|
|
600
|
+
handle: z.string().min(1).optional(),
|
|
601
|
+
templateSuffix: z.string().optional(),
|
|
602
|
+
commentPolicy: blogCommentPolicySchema.optional()
|
|
603
|
+
});
|
|
604
|
+
const blogMutationResponseSchema = z.object({
|
|
605
|
+
blog: shopifyBlogSchema.nullable(),
|
|
606
|
+
userErrors: z.array(shopifyUserErrorSchema.extend({ code: z.string().optional() }))
|
|
607
|
+
});
|
|
608
|
+
const listBlogsResponseSchema = z.object({ blogs: shopifyConnectionNodesSchema(shopifyBlogSchema) });
|
|
609
|
+
const getBlogResponseSchema = z.object({ blog: shopifyBlogSchema.nullable() });
|
|
610
|
+
const deleteBlogResponseSchema = z.object({
|
|
611
|
+
deletedBlogId: shopifyGlobalIdSchema.nullable(),
|
|
612
|
+
userErrors: z.array(shopifyUserErrorSchema.extend({ code: z.string().optional() }))
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
//#endregion
|
|
616
|
+
//#region src/operations/create-shopify-blog.operation.ts
|
|
617
|
+
const createBlogOperation = new Operation({
|
|
618
|
+
credentialSets: [shopifyCredentialSet],
|
|
619
|
+
id: "shopify.create-shopify-blog",
|
|
620
|
+
name: "Create Shopify Blog",
|
|
621
|
+
description: "Create a blog in the connected Shopify store.",
|
|
622
|
+
needsApproval: true,
|
|
623
|
+
input: blogMutationInputSchema.extend({ title: z.string().min(1) }),
|
|
624
|
+
output: shopifyBlogSchema,
|
|
625
|
+
run: async (input, context) => {
|
|
626
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
627
|
+
mutation CreateBlog($blog: BlogCreateInput!) {
|
|
628
|
+
blogCreate(blog: $blog) {
|
|
629
|
+
blog {
|
|
630
|
+
${blogSelection}
|
|
631
|
+
}
|
|
632
|
+
userErrors {
|
|
633
|
+
code
|
|
634
|
+
field
|
|
635
|
+
message
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
`, z.object({ blogCreate: blogMutationResponseSchema }), { variables: { blog: omitUndefined(input) } });
|
|
640
|
+
assertNoUserErrors(response.blogCreate.userErrors);
|
|
641
|
+
if (!response.blogCreate.blog) throw new Error("Shopify did not return the created blog.");
|
|
642
|
+
return response.blogCreate.blog;
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
//#endregion
|
|
647
|
+
//#region src/operations/create-shopify-collection.operation.ts
|
|
648
|
+
const createCollectionOperation = new Operation({
|
|
649
|
+
credentialSets: [shopifyCredentialSet],
|
|
650
|
+
id: "shopify.create-shopify-collection",
|
|
651
|
+
name: "Create Shopify Collection",
|
|
652
|
+
description: "Create a collection in the connected Shopify store.",
|
|
653
|
+
needsApproval: true,
|
|
654
|
+
input: collectionMutationInputSchema.extend({ title: z.string().min(1) }),
|
|
655
|
+
output: shopifyCollectionSchema,
|
|
656
|
+
run: async (input, context) => {
|
|
657
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
658
|
+
mutation CreateCollection($input: CollectionInput!) {
|
|
659
|
+
collectionCreate(input: $input) {
|
|
660
|
+
collection {
|
|
661
|
+
${collectionSelection}
|
|
662
|
+
}
|
|
663
|
+
userErrors {
|
|
664
|
+
field
|
|
665
|
+
message
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
`, z.object({ collectionCreate: collectionMutationResponseSchema }), { variables: { input: omitUndefined(input) } });
|
|
670
|
+
assertNoUserErrors(response.collectionCreate.userErrors);
|
|
671
|
+
if (!response.collectionCreate.collection) throw new Error("Shopify did not return the created collection.");
|
|
672
|
+
return response.collectionCreate.collection;
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
//#endregion
|
|
677
|
+
//#region src/schemas/customers.ts
|
|
678
|
+
const customerSelection = `
|
|
679
|
+
id
|
|
680
|
+
displayName
|
|
681
|
+
firstName
|
|
682
|
+
lastName
|
|
683
|
+
email
|
|
684
|
+
phone
|
|
685
|
+
createdAt
|
|
686
|
+
updatedAt
|
|
687
|
+
`;
|
|
688
|
+
const orderSelection = `
|
|
689
|
+
id
|
|
690
|
+
name
|
|
691
|
+
createdAt
|
|
692
|
+
updatedAt
|
|
693
|
+
cancelledAt
|
|
694
|
+
email
|
|
695
|
+
note
|
|
696
|
+
tags
|
|
697
|
+
displayFinancialStatus
|
|
698
|
+
displayFulfillmentStatus
|
|
699
|
+
currentTotalPriceSet {
|
|
700
|
+
shopMoney {
|
|
701
|
+
amount
|
|
702
|
+
currencyCode
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
customer {
|
|
706
|
+
id
|
|
707
|
+
displayName
|
|
708
|
+
firstName
|
|
709
|
+
lastName
|
|
710
|
+
email
|
|
711
|
+
phone
|
|
712
|
+
createdAt
|
|
713
|
+
updatedAt
|
|
714
|
+
}
|
|
715
|
+
`;
|
|
716
|
+
const customerMutationInputSchema = z.object({
|
|
717
|
+
email: z.email().optional(),
|
|
718
|
+
firstName: z.string().optional(),
|
|
719
|
+
lastName: z.string().optional(),
|
|
720
|
+
phone: z.string().optional(),
|
|
721
|
+
note: z.string().optional(),
|
|
722
|
+
tags: z.array(z.string()).optional()
|
|
723
|
+
});
|
|
724
|
+
const customerMutationResponseSchema = z.object({
|
|
725
|
+
customer: shopifyCustomerSchema.nullable(),
|
|
726
|
+
userErrors: z.array(shopifyUserErrorSchema)
|
|
727
|
+
});
|
|
728
|
+
const listCustomersResponseSchema = z.object({ customers: shopifyConnectionNodesSchema(shopifyCustomerSchema) });
|
|
729
|
+
const getCustomerResponseSchema = z.object({ customer: shopifyCustomerSchema.nullable() });
|
|
730
|
+
const customerDeleteResponseSchema = z.object({
|
|
731
|
+
deletedCustomerId: shopifyGlobalIdSchema.nullable(),
|
|
732
|
+
userErrors: z.array(shopifyUserErrorSchema)
|
|
733
|
+
});
|
|
734
|
+
const customerOrdersResponseSchema = z.object({ customer: z.object({ orders: shopifyConnectionNodesSchema(shopifyOrderSchema) }).nullable() });
|
|
735
|
+
|
|
736
|
+
//#endregion
|
|
737
|
+
//#region src/operations/create-shopify-customer.operation.ts
|
|
738
|
+
const createCustomerOperation = new Operation({
|
|
739
|
+
credentialSets: [shopifyCredentialSet],
|
|
740
|
+
id: "shopify.create-shopify-customer",
|
|
741
|
+
name: "Create Shopify Customer",
|
|
742
|
+
description: "Create a customer in the connected Shopify store.",
|
|
743
|
+
needsApproval: true,
|
|
744
|
+
input: customerMutationInputSchema.refine((input) => input.email !== void 0 || input.phone !== void 0 || input.firstName !== void 0, { message: "At least one identifying customer field must be provided." }),
|
|
745
|
+
output: shopifyCustomerSchema,
|
|
746
|
+
run: async (input, context) => {
|
|
747
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
748
|
+
mutation CreateCustomer($input: CustomerInput!) {
|
|
749
|
+
customerCreate(input: $input) {
|
|
750
|
+
customer {
|
|
751
|
+
${customerSelection}
|
|
752
|
+
}
|
|
753
|
+
userErrors {
|
|
754
|
+
field
|
|
755
|
+
message
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
`, z.object({ customerCreate: customerMutationResponseSchema }), { variables: { input: omitUndefined(input) } });
|
|
760
|
+
assertNoUserErrors(response.customerCreate.userErrors);
|
|
761
|
+
if (!response.customerCreate.customer) throw new Error("Shopify did not return the created customer.");
|
|
762
|
+
return response.customerCreate.customer;
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
//#endregion
|
|
767
|
+
//#region src/schemas/fulfillments.ts
|
|
768
|
+
const fulfillmentSelection = `
|
|
769
|
+
id
|
|
770
|
+
status
|
|
771
|
+
trackingInfo {
|
|
772
|
+
number
|
|
773
|
+
url
|
|
774
|
+
}
|
|
775
|
+
`;
|
|
776
|
+
const fulfillmentOrderLineItemSchema = z.object({
|
|
777
|
+
id: shopifyGlobalIdSchema,
|
|
778
|
+
remainingQuantity: z.number().int(),
|
|
779
|
+
lineItem: z.object({
|
|
780
|
+
id: shopifyGlobalIdSchema,
|
|
781
|
+
name: z.string(),
|
|
782
|
+
quantity: z.number().int()
|
|
783
|
+
}).nullable().optional()
|
|
784
|
+
});
|
|
785
|
+
const fulfillmentOrderSchema = z.object({
|
|
786
|
+
id: shopifyGlobalIdSchema,
|
|
787
|
+
status: z.string(),
|
|
788
|
+
assignedLocation: z.object({ location: shopifyLocationSchema.nullable().optional() }).nullable().optional(),
|
|
789
|
+
lineItems: shopifyConnectionNodesSchema(fulfillmentOrderLineItemSchema)
|
|
790
|
+
});
|
|
791
|
+
const fulfillmentOrderConnectionSchema = z.object({ order: z.object({ fulfillmentOrders: shopifyConnectionNodesSchema(fulfillmentOrderSchema) }).nullable() });
|
|
792
|
+
const fulfillmentResponseSchema = z.object({ fulfillment: shopifyFulfillmentSchema.nullable() });
|
|
793
|
+
const fulfillmentCreatePayloadSchema = z.object({
|
|
794
|
+
fulfillment: shopifyFulfillmentSchema.nullable(),
|
|
795
|
+
userErrors: z.array(shopifyUserErrorSchema)
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
//#endregion
|
|
799
|
+
//#region src/operations/create-shopify-fulfillment.operation.ts
|
|
800
|
+
const createFulfillmentOperation = new Operation({
|
|
801
|
+
credentialSets: [shopifyCredentialSet],
|
|
802
|
+
id: "shopify.create-shopify-fulfillment",
|
|
803
|
+
name: "Create Shopify Fulfillment",
|
|
804
|
+
description: "Create a fulfillment from one or more Shopify fulfillment orders.",
|
|
805
|
+
needsApproval: true,
|
|
806
|
+
input: z.object({
|
|
807
|
+
lineItemsByFulfillmentOrder: z.array(z.object({
|
|
808
|
+
fulfillmentOrderId: shopifyGlobalIdSchema,
|
|
809
|
+
fulfillmentOrderLineItems: z.array(z.object({
|
|
810
|
+
id: shopifyGlobalIdSchema,
|
|
811
|
+
quantity: z.number().int().min(1)
|
|
812
|
+
})).optional()
|
|
813
|
+
})).min(1),
|
|
814
|
+
notifyCustomer: z.boolean().optional(),
|
|
815
|
+
message: z.string().optional(),
|
|
816
|
+
trackingInfo: z.object({
|
|
817
|
+
company: z.string().optional(),
|
|
818
|
+
number: z.string().optional(),
|
|
819
|
+
url: z.url().optional()
|
|
820
|
+
}).optional()
|
|
821
|
+
}),
|
|
822
|
+
output: shopifyFulfillmentSchema,
|
|
823
|
+
run: async (input, context) => {
|
|
824
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
825
|
+
mutation CreateFulfillment($fulfillment: FulfillmentInput!, $message: String) {
|
|
826
|
+
fulfillmentCreate(fulfillment: $fulfillment, message: $message) {
|
|
827
|
+
fulfillment {
|
|
828
|
+
${fulfillmentSelection}
|
|
829
|
+
}
|
|
830
|
+
userErrors {
|
|
831
|
+
field
|
|
832
|
+
message
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
`, z.object({ fulfillmentCreate: fulfillmentCreatePayloadSchema }), { variables: {
|
|
837
|
+
fulfillment: {
|
|
838
|
+
lineItemsByFulfillmentOrder: input.lineItemsByFulfillmentOrder,
|
|
839
|
+
notifyCustomer: input.notifyCustomer,
|
|
840
|
+
trackingInfo: input.trackingInfo
|
|
841
|
+
},
|
|
842
|
+
...input.message ? { message: input.message } : {}
|
|
843
|
+
} });
|
|
844
|
+
assertNoUserErrors(response.fulfillmentCreate.userErrors);
|
|
845
|
+
if (!response.fulfillmentCreate.fulfillment) throw new Error("Shopify did not return the created fulfillment.");
|
|
846
|
+
return response.fulfillmentCreate.fulfillment;
|
|
847
|
+
}
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
//#endregion
|
|
851
|
+
//#region src/operations/create-shopify-order.operation.ts
|
|
852
|
+
const createOrderOperation = new Operation({
|
|
853
|
+
credentialSets: [shopifyCredentialSet],
|
|
854
|
+
id: "shopify.create-shopify-order",
|
|
855
|
+
name: "Create Shopify Order",
|
|
856
|
+
description: "Create an order in the connected Shopify store.",
|
|
857
|
+
needsApproval: true,
|
|
858
|
+
input: orderCreateInputSchema,
|
|
859
|
+
output: shopifyOrderSchema,
|
|
860
|
+
run: async (input, context) => {
|
|
861
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
862
|
+
mutation CreateOrder($order: OrderCreateOrderInput!) {
|
|
863
|
+
orderCreate(order: $order) {
|
|
864
|
+
order {
|
|
865
|
+
${orderSelection$1}
|
|
866
|
+
}
|
|
867
|
+
userErrors {
|
|
868
|
+
field
|
|
869
|
+
message
|
|
870
|
+
code
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
`, z.object({ orderCreate: createOrderResponseSchema }), { variables: { order: {
|
|
875
|
+
...omitUndefined({
|
|
876
|
+
currency: input.currency,
|
|
877
|
+
email: input.email,
|
|
878
|
+
note: input.note,
|
|
879
|
+
tags: input.tags,
|
|
880
|
+
customerId: input.customerId
|
|
881
|
+
}),
|
|
882
|
+
lineItems: buildOrderCreateLineItems(input.lineItems, input.currency)
|
|
883
|
+
} } });
|
|
884
|
+
assertNoUserErrors(response.orderCreate.userErrors);
|
|
885
|
+
if (!response.orderCreate.order) throw new Error("Shopify did not return the created order.");
|
|
886
|
+
return response.orderCreate.order;
|
|
887
|
+
}
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
//#endregion
|
|
891
|
+
//#region src/schemas/products.ts
|
|
892
|
+
const productSelection = `
|
|
893
|
+
id
|
|
894
|
+
title
|
|
895
|
+
handle
|
|
896
|
+
status
|
|
897
|
+
productType
|
|
898
|
+
vendor
|
|
899
|
+
descriptionHtml
|
|
900
|
+
onlineStoreUrl
|
|
901
|
+
createdAt
|
|
902
|
+
updatedAt
|
|
903
|
+
tags
|
|
904
|
+
featuredImage {
|
|
905
|
+
url
|
|
906
|
+
altText
|
|
907
|
+
}
|
|
908
|
+
seo {
|
|
909
|
+
title
|
|
910
|
+
description
|
|
911
|
+
}
|
|
912
|
+
`;
|
|
913
|
+
const productMutationInputSchema = z.object({
|
|
914
|
+
title: z.string().min(1).optional(),
|
|
915
|
+
handle: z.string().min(1).optional(),
|
|
916
|
+
descriptionHtml: z.string().optional(),
|
|
917
|
+
vendor: z.string().optional(),
|
|
918
|
+
productType: z.string().optional(),
|
|
919
|
+
tags: z.array(z.string()).optional()
|
|
920
|
+
});
|
|
921
|
+
const listProductsResponseSchema = z.object({ products: shopifyConnectionNodesSchema(shopifyProductSchema) });
|
|
922
|
+
const getProductResponseSchema = z.object({ product: shopifyProductSchema.nullable() });
|
|
923
|
+
const productMutationResponseSchema = z.object({
|
|
924
|
+
product: shopifyProductSchema.nullable(),
|
|
925
|
+
userErrors: z.array(shopifyUserErrorSchema)
|
|
926
|
+
});
|
|
927
|
+
const deleteProductResponseSchema = z.object({
|
|
928
|
+
deletedProductId: shopifyGlobalIdSchema.nullable(),
|
|
929
|
+
userErrors: z.array(shopifyUserErrorSchema)
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
//#endregion
|
|
933
|
+
//#region src/operations/create-shopify-product.operation.ts
|
|
934
|
+
const createProductOperation = new Operation({
|
|
935
|
+
credentialSets: [shopifyCredentialSet],
|
|
936
|
+
id: "shopify.create-shopify-product",
|
|
937
|
+
name: "Create Shopify Product",
|
|
938
|
+
description: "Create a product in the connected Shopify store.",
|
|
939
|
+
needsApproval: true,
|
|
940
|
+
input: productMutationInputSchema.extend({ title: z.string().min(1) }),
|
|
941
|
+
output: shopifyProductSchema,
|
|
942
|
+
run: async (input, context) => {
|
|
943
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
944
|
+
mutation CreateProduct($product: ProductCreateInput!) {
|
|
945
|
+
productCreate(product: $product) {
|
|
946
|
+
product {
|
|
947
|
+
${productSelection}
|
|
948
|
+
}
|
|
949
|
+
userErrors {
|
|
950
|
+
field
|
|
951
|
+
message
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
`, z.object({ productCreate: productMutationResponseSchema }), { variables: { product: omitUndefined(input) } });
|
|
956
|
+
assertNoUserErrors(response.productCreate.userErrors);
|
|
957
|
+
if (!response.productCreate.product) throw new Error("Shopify did not return the created product.");
|
|
958
|
+
return response.productCreate.product;
|
|
959
|
+
}
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
//#endregion
|
|
963
|
+
//#region src/operations/delete-shopify-article.operation.ts
|
|
964
|
+
const deleteArticleOperation = new Operation({
|
|
965
|
+
credentialSets: [shopifyCredentialSet],
|
|
966
|
+
id: "shopify.delete-shopify-article",
|
|
967
|
+
name: "Delete Shopify Article",
|
|
968
|
+
description: "Delete a Shopify article by its global ID.",
|
|
969
|
+
needsApproval: true,
|
|
970
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
971
|
+
output: z.object({ deletedArticleId: shopifyGlobalIdSchema }),
|
|
972
|
+
run: async (input, context) => {
|
|
973
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
974
|
+
mutation DeleteArticle($id: ID!) {
|
|
975
|
+
articleDelete(id: $id) {
|
|
976
|
+
deletedArticleId
|
|
977
|
+
userErrors {
|
|
978
|
+
code
|
|
979
|
+
field
|
|
980
|
+
message
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
`, z.object({ articleDelete: deleteArticleResponseSchema }), { variables: { id: input.id } });
|
|
985
|
+
assertNoUserErrors(response.articleDelete.userErrors);
|
|
986
|
+
if (!response.articleDelete.deletedArticleId) throw new Error(`Shopify did not confirm article deletion: ${input.id}`);
|
|
987
|
+
return { deletedArticleId: response.articleDelete.deletedArticleId };
|
|
988
|
+
}
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
//#endregion
|
|
992
|
+
//#region src/operations/delete-shopify-blog.operation.ts
|
|
993
|
+
const deleteBlogOperation = new Operation({
|
|
994
|
+
credentialSets: [shopifyCredentialSet],
|
|
995
|
+
id: "shopify.delete-shopify-blog",
|
|
996
|
+
name: "Delete Shopify Blog",
|
|
997
|
+
description: "Delete a Shopify blog by its global ID.",
|
|
998
|
+
needsApproval: true,
|
|
999
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1000
|
+
output: z.object({ deletedBlogId: shopifyGlobalIdSchema }),
|
|
1001
|
+
run: async (input, context) => {
|
|
1002
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1003
|
+
mutation DeleteBlog($id: ID!) {
|
|
1004
|
+
blogDelete(id: $id) {
|
|
1005
|
+
deletedBlogId
|
|
1006
|
+
userErrors {
|
|
1007
|
+
code
|
|
1008
|
+
field
|
|
1009
|
+
message
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
`, z.object({ blogDelete: deleteBlogResponseSchema }), { variables: { id: input.id } });
|
|
1014
|
+
assertNoUserErrors(response.blogDelete.userErrors);
|
|
1015
|
+
if (!response.blogDelete.deletedBlogId) throw new Error(`Shopify did not confirm blog deletion: ${input.id}`);
|
|
1016
|
+
return { deletedBlogId: response.blogDelete.deletedBlogId };
|
|
1017
|
+
}
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
//#endregion
|
|
1021
|
+
//#region src/operations/delete-shopify-collection.operation.ts
|
|
1022
|
+
const deleteCollectionOperation = new Operation({
|
|
1023
|
+
credentialSets: [shopifyCredentialSet],
|
|
1024
|
+
id: "shopify.delete-shopify-collection",
|
|
1025
|
+
name: "Delete Shopify Collection",
|
|
1026
|
+
description: "Delete a Shopify collection by its global ID.",
|
|
1027
|
+
needsApproval: true,
|
|
1028
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1029
|
+
output: z.object({ deletedCollectionId: shopifyGlobalIdSchema }),
|
|
1030
|
+
run: async (input, context) => {
|
|
1031
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1032
|
+
mutation DeleteCollection($input: CollectionDeleteInput!) {
|
|
1033
|
+
collectionDelete(input: $input) {
|
|
1034
|
+
deletedCollectionId
|
|
1035
|
+
userErrors {
|
|
1036
|
+
field
|
|
1037
|
+
message
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
`, z.object({ collectionDelete: deleteCollectionResponseSchema }), { variables: { input: { id: input.id } } });
|
|
1042
|
+
assertNoUserErrors(response.collectionDelete.userErrors);
|
|
1043
|
+
if (!response.collectionDelete.deletedCollectionId) throw new Error(`Shopify did not confirm collection deletion: ${input.id}`);
|
|
1044
|
+
return { deletedCollectionId: response.collectionDelete.deletedCollectionId };
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
//#endregion
|
|
1049
|
+
//#region src/operations/delete-shopify-customer.operation.ts
|
|
1050
|
+
const deleteCustomerOperation = new Operation({
|
|
1051
|
+
credentialSets: [shopifyCredentialSet],
|
|
1052
|
+
id: "shopify.delete-shopify-customer",
|
|
1053
|
+
name: "Delete Shopify Customer",
|
|
1054
|
+
description: "Delete a Shopify customer who has no placed orders.",
|
|
1055
|
+
needsApproval: true,
|
|
1056
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1057
|
+
output: z.object({ deletedCustomerId: shopifyGlobalIdSchema }),
|
|
1058
|
+
run: async (input, context) => {
|
|
1059
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1060
|
+
mutation DeleteCustomer($id: ID!) {
|
|
1061
|
+
customerDelete(input: { id: $id }) {
|
|
1062
|
+
deletedCustomerId
|
|
1063
|
+
userErrors {
|
|
1064
|
+
field
|
|
1065
|
+
message
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
`, z.object({ customerDelete: customerDeleteResponseSchema }), { variables: { id: input.id } });
|
|
1070
|
+
assertNoUserErrors(response.customerDelete.userErrors);
|
|
1071
|
+
if (!response.customerDelete.deletedCustomerId) throw new Error(`Shopify did not confirm customer deletion: ${input.id}`);
|
|
1072
|
+
return { deletedCustomerId: response.customerDelete.deletedCustomerId };
|
|
1073
|
+
}
|
|
1074
|
+
});
|
|
1075
|
+
|
|
1076
|
+
//#endregion
|
|
1077
|
+
//#region src/operations/delete-shopify-product.operation.ts
|
|
1078
|
+
const deleteProductOperation = new Operation({
|
|
1079
|
+
credentialSets: [shopifyCredentialSet],
|
|
1080
|
+
id: "shopify.delete-shopify-product",
|
|
1081
|
+
name: "Delete Shopify Product",
|
|
1082
|
+
description: "Delete a Shopify product by its global ID.",
|
|
1083
|
+
needsApproval: true,
|
|
1084
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1085
|
+
output: z.object({ deletedProductId: shopifyGlobalIdSchema }),
|
|
1086
|
+
run: async (input, context) => {
|
|
1087
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1088
|
+
mutation DeleteProduct($input: ProductDeleteInput!) {
|
|
1089
|
+
productDelete(input: $input) {
|
|
1090
|
+
deletedProductId
|
|
1091
|
+
userErrors {
|
|
1092
|
+
field
|
|
1093
|
+
message
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
`, z.object({ productDelete: deleteProductResponseSchema }), { variables: { input: { id: input.id } } });
|
|
1098
|
+
assertNoUserErrors(response.productDelete.userErrors);
|
|
1099
|
+
if (!response.productDelete.deletedProductId) throw new Error(`Shopify did not confirm product deletion: ${input.id}`);
|
|
1100
|
+
return { deletedProductId: response.productDelete.deletedProductId };
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
//#endregion
|
|
1105
|
+
//#region src/operations/get-shopify-article.operation.ts
|
|
1106
|
+
const getArticleOperation = new Operation({
|
|
1107
|
+
credentialSets: [shopifyCredentialSet],
|
|
1108
|
+
id: "shopify.get-shopify-article",
|
|
1109
|
+
name: "Get Shopify Article",
|
|
1110
|
+
description: "Retrieve a single Shopify article by its global ID.",
|
|
1111
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1112
|
+
output: shopifyArticleSchema,
|
|
1113
|
+
run: async (input, context) => {
|
|
1114
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1115
|
+
query GetArticle($id: ID!) {
|
|
1116
|
+
article(id: $id) {
|
|
1117
|
+
${articleSelection}
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
`, getArticleResponseSchema, { variables: { id: input.id } });
|
|
1121
|
+
if (!response.article) throw new Error(`Shopify article not found: ${input.id}`);
|
|
1122
|
+
return normalizeArticle(response.article);
|
|
1123
|
+
}
|
|
1124
|
+
});
|
|
1125
|
+
|
|
1126
|
+
//#endregion
|
|
1127
|
+
//#region src/operations/get-shopify-blog.operation.ts
|
|
1128
|
+
const getBlogOperation = new Operation({
|
|
1129
|
+
credentialSets: [shopifyCredentialSet],
|
|
1130
|
+
id: "shopify.get-shopify-blog",
|
|
1131
|
+
name: "Get Shopify Blog",
|
|
1132
|
+
description: "Retrieve a single Shopify blog by its global ID.",
|
|
1133
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1134
|
+
output: shopifyBlogSchema,
|
|
1135
|
+
run: async (input, context) => {
|
|
1136
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1137
|
+
query GetBlog($id: ID!) {
|
|
1138
|
+
blog(id: $id) {
|
|
1139
|
+
${blogSelection}
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
`, getBlogResponseSchema, { variables: { id: input.id } });
|
|
1143
|
+
if (!response.blog) throw new Error(`Shopify blog not found: ${input.id}`);
|
|
1144
|
+
return response.blog;
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1147
|
+
|
|
1148
|
+
//#endregion
|
|
1149
|
+
//#region src/operations/get-shopify-collection.operation.ts
|
|
1150
|
+
const getCollectionOperation = new Operation({
|
|
1151
|
+
credentialSets: [shopifyCredentialSet],
|
|
1152
|
+
id: "shopify.get-shopify-collection",
|
|
1153
|
+
name: "Get Shopify Collection",
|
|
1154
|
+
description: "Retrieve a single Shopify collection by its global ID.",
|
|
1155
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1156
|
+
output: shopifyCollectionSchema,
|
|
1157
|
+
run: async (input, context) => {
|
|
1158
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1159
|
+
query GetCollection($id: ID!) {
|
|
1160
|
+
collection(id: $id) {
|
|
1161
|
+
${collectionSelection}
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
`, getCollectionResponseSchema, { variables: { id: input.id } });
|
|
1165
|
+
if (!response.collection) throw new Error(`Shopify collection not found: ${input.id}`);
|
|
1166
|
+
return response.collection;
|
|
1167
|
+
}
|
|
1168
|
+
});
|
|
1169
|
+
|
|
1170
|
+
//#endregion
|
|
1171
|
+
//#region src/operations/get-shopify-customer.operation.ts
|
|
1172
|
+
const getCustomerOperation = new Operation({
|
|
1173
|
+
credentialSets: [shopifyCredentialSet],
|
|
1174
|
+
id: "shopify.get-shopify-customer",
|
|
1175
|
+
name: "Get Shopify Customer",
|
|
1176
|
+
description: "Retrieve a single Shopify customer by its global ID.",
|
|
1177
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1178
|
+
output: shopifyCustomerSchema,
|
|
1179
|
+
run: async (input, context) => {
|
|
1180
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1181
|
+
query GetCustomer($id: ID!) {
|
|
1182
|
+
customer(id: $id) {
|
|
1183
|
+
${customerSelection}
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
`, getCustomerResponseSchema, { variables: { id: input.id } });
|
|
1187
|
+
if (!response.customer) throw new Error(`Shopify customer not found: ${input.id}`);
|
|
1188
|
+
return response.customer;
|
|
1189
|
+
}
|
|
1190
|
+
});
|
|
1191
|
+
|
|
1192
|
+
//#endregion
|
|
1193
|
+
//#region src/operations/get-shopify-customer-orders.operation.ts
|
|
1194
|
+
const getCustomerOrdersOperation = new Operation({
|
|
1195
|
+
credentialSets: [shopifyCredentialSet],
|
|
1196
|
+
id: "shopify.get-shopify-customer-orders",
|
|
1197
|
+
name: "Get Shopify Customer Orders",
|
|
1198
|
+
description: "Retrieve orders for a specific Shopify customer.",
|
|
1199
|
+
input: z.object({
|
|
1200
|
+
id: shopifyGlobalIdSchema,
|
|
1201
|
+
first: z.number().int().min(1).max(100).optional().default(25),
|
|
1202
|
+
after: z.string().optional()
|
|
1203
|
+
}),
|
|
1204
|
+
output: shopifyConnectionNodesSchema(shopifyOrderSchema),
|
|
1205
|
+
run: async (input, context) => {
|
|
1206
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1207
|
+
query GetCustomerOrders($id: ID!, $first: Int!, $after: String) {
|
|
1208
|
+
customer(id: $id) {
|
|
1209
|
+
orders(first: $first, after: $after) {
|
|
1210
|
+
nodes {
|
|
1211
|
+
${orderSelection}
|
|
1212
|
+
}
|
|
1213
|
+
pageInfo {
|
|
1214
|
+
hasNextPage
|
|
1215
|
+
hasPreviousPage
|
|
1216
|
+
startCursor
|
|
1217
|
+
endCursor
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
`, customerOrdersResponseSchema, { variables: {
|
|
1223
|
+
id: input.id,
|
|
1224
|
+
first: input.first,
|
|
1225
|
+
...input.after ? { after: input.after } : {}
|
|
1226
|
+
} });
|
|
1227
|
+
if (!response.customer) throw new Error(`Shopify customer not found for orders lookup: ${input.id}`);
|
|
1228
|
+
return response.customer.orders;
|
|
1229
|
+
}
|
|
1230
|
+
});
|
|
1231
|
+
|
|
1232
|
+
//#endregion
|
|
1233
|
+
//#region src/operations/get-shopify-fulfillment.operation.ts
|
|
1234
|
+
const getFulfillmentOperation = new Operation({
|
|
1235
|
+
credentialSets: [shopifyCredentialSet],
|
|
1236
|
+
id: "shopify.get-shopify-fulfillment",
|
|
1237
|
+
name: "Get Shopify Fulfillment",
|
|
1238
|
+
description: "Retrieve a single Shopify fulfillment by its global ID.",
|
|
1239
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1240
|
+
output: shopifyFulfillmentSchema,
|
|
1241
|
+
run: async (input, context) => {
|
|
1242
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1243
|
+
query GetFulfillment($id: ID!) {
|
|
1244
|
+
fulfillment(id: $id) {
|
|
1245
|
+
${fulfillmentSelection}
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
`, fulfillmentResponseSchema, { variables: { id: input.id } });
|
|
1249
|
+
if (!response.fulfillment) throw new Error(`Shopify fulfillment not found: ${input.id}`);
|
|
1250
|
+
return response.fulfillment;
|
|
1251
|
+
}
|
|
1252
|
+
});
|
|
1253
|
+
|
|
1254
|
+
//#endregion
|
|
1255
|
+
//#region src/operations/get-shopify-inventory-item.operation.ts
|
|
1256
|
+
const getInventoryItemOperation = new Operation({
|
|
1257
|
+
credentialSets: [shopifyCredentialSet],
|
|
1258
|
+
id: "shopify.get-shopify-inventory-item",
|
|
1259
|
+
name: "Get Shopify Inventory Item",
|
|
1260
|
+
description: "Retrieve a single Shopify inventory item by its global ID.",
|
|
1261
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1262
|
+
output: shopifyInventoryItemSchema,
|
|
1263
|
+
run: async (input, context) => {
|
|
1264
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1265
|
+
query GetInventoryItem($id: ID!) {
|
|
1266
|
+
inventoryItem(id: $id) {
|
|
1267
|
+
${inventoryItemSelection}
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
`, getInventoryItemResponseSchema, { variables: { id: input.id } });
|
|
1271
|
+
if (!response.inventoryItem) throw new Error(`Shopify inventory item not found: ${input.id}`);
|
|
1272
|
+
return response.inventoryItem;
|
|
1273
|
+
}
|
|
1274
|
+
});
|
|
1275
|
+
|
|
1276
|
+
//#endregion
|
|
1277
|
+
//#region src/operations/get-shopify-inventory-levels-for-item.operation.ts
|
|
1278
|
+
const getInventoryLevelsForItemOperation = new Operation({
|
|
1279
|
+
credentialSets: [shopifyCredentialSet],
|
|
1280
|
+
id: "shopify.get-shopify-inventory-levels-for-item",
|
|
1281
|
+
name: "Get Shopify Inventory Levels For Item",
|
|
1282
|
+
description: "Retrieve inventory levels for a specific Shopify inventory item.",
|
|
1283
|
+
input: z.object({
|
|
1284
|
+
inventoryItemId: shopifyGlobalIdSchema,
|
|
1285
|
+
first: z.number().int().min(1).max(100).optional().default(25),
|
|
1286
|
+
after: z.string().optional()
|
|
1287
|
+
}),
|
|
1288
|
+
output: shopifyConnectionNodesSchema(shopifyInventoryLevelSchema),
|
|
1289
|
+
run: async (input, context) => {
|
|
1290
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1291
|
+
query GetInventoryLevelsForItem($id: ID!, $first: Int!, $after: String) {
|
|
1292
|
+
inventoryItem(id: $id) {
|
|
1293
|
+
inventoryLevels(first: $first, after: $after) {
|
|
1294
|
+
nodes {
|
|
1295
|
+
${inventoryLevelSelection}
|
|
1296
|
+
}
|
|
1297
|
+
pageInfo {
|
|
1298
|
+
hasNextPage
|
|
1299
|
+
hasPreviousPage
|
|
1300
|
+
startCursor
|
|
1301
|
+
endCursor
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
`, inventoryLevelsResponseSchema, { variables: {
|
|
1307
|
+
id: input.inventoryItemId,
|
|
1308
|
+
first: input.first,
|
|
1309
|
+
...input.after ? { after: input.after } : {}
|
|
1310
|
+
} });
|
|
1311
|
+
if (!response.inventoryItem) throw new Error(`Shopify inventory item not found for inventory levels lookup: ${input.inventoryItemId}`);
|
|
1312
|
+
return response.inventoryItem.inventoryLevels;
|
|
1313
|
+
}
|
|
1314
|
+
});
|
|
1315
|
+
|
|
1316
|
+
//#endregion
|
|
1317
|
+
//#region src/schemas/locations.ts
|
|
1318
|
+
const locationSelection = `
|
|
1319
|
+
id
|
|
1320
|
+
name
|
|
1321
|
+
isActive
|
|
1322
|
+
fulfillsOnlineOrders
|
|
1323
|
+
`;
|
|
1324
|
+
const listLocationsResponseSchema = z.object({ locations: shopifyConnectionNodesSchema(shopifyLocationSchema) });
|
|
1325
|
+
const getLocationResponseSchema = z.object({ location: shopifyLocationSchema.nullable() });
|
|
1326
|
+
|
|
1327
|
+
//#endregion
|
|
1328
|
+
//#region src/operations/get-shopify-location.operation.ts
|
|
1329
|
+
const getLocationOperation = new Operation({
|
|
1330
|
+
credentialSets: [shopifyCredentialSet],
|
|
1331
|
+
id: "shopify.get-shopify-location",
|
|
1332
|
+
name: "Get Shopify Location",
|
|
1333
|
+
description: "Retrieve a single Shopify location by its global ID.",
|
|
1334
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1335
|
+
output: shopifyLocationSchema,
|
|
1336
|
+
run: async (input, context) => {
|
|
1337
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1338
|
+
query GetLocation($id: ID!) {
|
|
1339
|
+
location(id: $id) {
|
|
1340
|
+
${locationSelection}
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
`, getLocationResponseSchema, { variables: { id: input.id } });
|
|
1344
|
+
if (!response.location) throw new Error(`Shopify location not found: ${input.id}`);
|
|
1345
|
+
return response.location;
|
|
1346
|
+
}
|
|
1347
|
+
});
|
|
1348
|
+
|
|
1349
|
+
//#endregion
|
|
1350
|
+
//#region src/operations/get-shopify-order.operation.ts
|
|
1351
|
+
const getOrderOperation = new Operation({
|
|
1352
|
+
credentialSets: [shopifyCredentialSet],
|
|
1353
|
+
id: "shopify.get-shopify-order",
|
|
1354
|
+
name: "Get Shopify Order",
|
|
1355
|
+
description: "Retrieve a single Shopify order by its global ID.",
|
|
1356
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1357
|
+
output: shopifyOrderSchema,
|
|
1358
|
+
run: async (input, context) => {
|
|
1359
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1360
|
+
query GetOrder($id: ID!) {
|
|
1361
|
+
order(id: $id) {
|
|
1362
|
+
${orderSelection$1}
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
`, getOrderResponseSchema, { variables: { id: input.id } });
|
|
1366
|
+
if (!response.order) throw new Error(`Shopify order not found: ${input.id}`);
|
|
1367
|
+
return response.order;
|
|
1368
|
+
}
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1371
|
+
//#endregion
|
|
1372
|
+
//#region src/operations/get-shopify-product.operation.ts
|
|
1373
|
+
const getProductOperation = new Operation({
|
|
1374
|
+
credentialSets: [shopifyCredentialSet],
|
|
1375
|
+
id: "shopify.get-shopify-product",
|
|
1376
|
+
name: "Get Shopify Product",
|
|
1377
|
+
description: "Retrieve a single Shopify product by its global ID.",
|
|
1378
|
+
input: z.object({ id: shopifyGlobalIdSchema }),
|
|
1379
|
+
output: shopifyProductSchema,
|
|
1380
|
+
run: async (input, context) => {
|
|
1381
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1382
|
+
query GetProduct($id: ID!) {
|
|
1383
|
+
product(id: $id) {
|
|
1384
|
+
${productSelection}
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
`, getProductResponseSchema, { variables: { id: input.id } });
|
|
1388
|
+
if (!response.product) throw new Error(`Shopify product not found: ${input.id}`);
|
|
1389
|
+
return response.product;
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
|
|
1393
|
+
//#endregion
|
|
1394
|
+
//#region src/schemas/shop.ts
|
|
1395
|
+
const getShopResponseSchema = z.object({ shop: shopifyShopSchema });
|
|
1396
|
+
const getShopQuery = `
|
|
1397
|
+
query GetShop {
|
|
1398
|
+
shop {
|
|
1399
|
+
id
|
|
1400
|
+
name
|
|
1401
|
+
myshopifyDomain
|
|
1402
|
+
contactEmail
|
|
1403
|
+
currencyCode
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
`;
|
|
1407
|
+
|
|
1408
|
+
//#endregion
|
|
1409
|
+
//#region src/operations/get-shopify-shop.operation.ts
|
|
1410
|
+
const getShopOperation = new Operation({
|
|
1411
|
+
credentialSets: [shopifyCredentialSet],
|
|
1412
|
+
id: "shopify.get-shopify-shop",
|
|
1413
|
+
name: "Get Shopify Shop",
|
|
1414
|
+
description: "Retrieve high-level details about the connected Shopify store.",
|
|
1415
|
+
input: z.object({}),
|
|
1416
|
+
output: shopifyShopSchema,
|
|
1417
|
+
run: async (_input, context) => {
|
|
1418
|
+
return (await createShopifyClient(context.credentials.shopify).graphql(getShopQuery, getShopResponseSchema)).shop;
|
|
1419
|
+
}
|
|
1420
|
+
});
|
|
1421
|
+
|
|
1422
|
+
//#endregion
|
|
1423
|
+
//#region src/operations/list-shopify-articles.operation.ts
|
|
1424
|
+
const listArticlesOperation = new Operation({
|
|
1425
|
+
credentialSets: [shopifyCredentialSet],
|
|
1426
|
+
id: "shopify.list-shopify-articles",
|
|
1427
|
+
name: "List Shopify Articles",
|
|
1428
|
+
description: "List blog articles from the connected Shopify store.",
|
|
1429
|
+
input: shopifyPageInputSchema,
|
|
1430
|
+
output: shopifyConnectionNodesSchema(shopifyArticleSchema),
|
|
1431
|
+
run: async (input, context) => {
|
|
1432
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1433
|
+
query ListArticles($first: Int!, $after: String, $query: String) {
|
|
1434
|
+
articles(first: $first, after: $after, query: $query) {
|
|
1435
|
+
nodes {
|
|
1436
|
+
${articleSelection}
|
|
1437
|
+
}
|
|
1438
|
+
pageInfo {
|
|
1439
|
+
hasNextPage
|
|
1440
|
+
hasPreviousPage
|
|
1441
|
+
startCursor
|
|
1442
|
+
endCursor
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
`, listArticlesResponseSchema, { variables: {
|
|
1447
|
+
first: input.first,
|
|
1448
|
+
...input.after ? { after: input.after } : {},
|
|
1449
|
+
...input.query ? { query: input.query } : {}
|
|
1450
|
+
} });
|
|
1451
|
+
return {
|
|
1452
|
+
nodes: response.articles.nodes.map(normalizeArticle),
|
|
1453
|
+
pageInfo: response.articles.pageInfo
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1456
|
+
});
|
|
1457
|
+
|
|
1458
|
+
//#endregion
|
|
1459
|
+
//#region src/operations/list-shopify-blogs.operation.ts
|
|
1460
|
+
const listBlogsOperation = new Operation({
|
|
1461
|
+
credentialSets: [shopifyCredentialSet],
|
|
1462
|
+
id: "shopify.list-shopify-blogs",
|
|
1463
|
+
name: "List Shopify Blogs",
|
|
1464
|
+
description: "List blogs from the connected Shopify store.",
|
|
1465
|
+
input: shopifyPageInputSchema,
|
|
1466
|
+
output: shopifyConnectionNodesSchema(shopifyBlogSchema),
|
|
1467
|
+
run: async (input, context) => {
|
|
1468
|
+
return (await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1469
|
+
query ListBlogs($first: Int!, $after: String, $query: String) {
|
|
1470
|
+
blogs(first: $first, after: $after, query: $query) {
|
|
1471
|
+
nodes {
|
|
1472
|
+
${blogSelection}
|
|
1473
|
+
}
|
|
1474
|
+
pageInfo {
|
|
1475
|
+
hasNextPage
|
|
1476
|
+
hasPreviousPage
|
|
1477
|
+
startCursor
|
|
1478
|
+
endCursor
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
`, listBlogsResponseSchema, { variables: {
|
|
1483
|
+
first: input.first,
|
|
1484
|
+
...input.after ? { after: input.after } : {},
|
|
1485
|
+
...input.query ? { query: input.query } : {}
|
|
1486
|
+
} })).blogs;
|
|
1487
|
+
}
|
|
1488
|
+
});
|
|
1489
|
+
|
|
1490
|
+
//#endregion
|
|
1491
|
+
//#region src/operations/list-shopify-collections.operation.ts
|
|
1492
|
+
const listCollectionsOperation = new Operation({
|
|
1493
|
+
credentialSets: [shopifyCredentialSet],
|
|
1494
|
+
id: "shopify.list-shopify-collections",
|
|
1495
|
+
name: "List Shopify Collections",
|
|
1496
|
+
description: "List collections from the connected Shopify store.",
|
|
1497
|
+
input: shopifyPageInputSchema,
|
|
1498
|
+
output: shopifyConnectionNodesSchema(shopifyCollectionSchema),
|
|
1499
|
+
run: async (input, context) => {
|
|
1500
|
+
return (await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1501
|
+
query ListCollections($first: Int!, $after: String, $query: String) {
|
|
1502
|
+
collections(first: $first, after: $after, query: $query) {
|
|
1503
|
+
nodes {
|
|
1504
|
+
${collectionSelection}
|
|
1505
|
+
}
|
|
1506
|
+
pageInfo {
|
|
1507
|
+
hasNextPage
|
|
1508
|
+
hasPreviousPage
|
|
1509
|
+
startCursor
|
|
1510
|
+
endCursor
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
`, listCollectionsResponseSchema, { variables: {
|
|
1515
|
+
first: input.first,
|
|
1516
|
+
...input.after ? { after: input.after } : {},
|
|
1517
|
+
...input.query ? { query: input.query } : {}
|
|
1518
|
+
} })).collections;
|
|
1519
|
+
}
|
|
1520
|
+
});
|
|
1521
|
+
|
|
1522
|
+
//#endregion
|
|
1523
|
+
//#region src/operations/list-shopify-customers.operation.ts
|
|
1524
|
+
const listCustomersOperation = new Operation({
|
|
1525
|
+
credentialSets: [shopifyCredentialSet],
|
|
1526
|
+
id: "shopify.list-shopify-customers",
|
|
1527
|
+
name: "List Shopify Customers",
|
|
1528
|
+
description: "List customers from the connected Shopify store.",
|
|
1529
|
+
input: shopifyPageInputSchema,
|
|
1530
|
+
output: shopifyConnectionNodesSchema(shopifyCustomerSchema),
|
|
1531
|
+
run: async (input, context) => {
|
|
1532
|
+
return (await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1533
|
+
query ListCustomers($first: Int!, $after: String, $query: String) {
|
|
1534
|
+
customers(first: $first, after: $after, query: $query) {
|
|
1535
|
+
nodes {
|
|
1536
|
+
${customerSelection}
|
|
1537
|
+
}
|
|
1538
|
+
pageInfo {
|
|
1539
|
+
hasNextPage
|
|
1540
|
+
hasPreviousPage
|
|
1541
|
+
startCursor
|
|
1542
|
+
endCursor
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
`, listCustomersResponseSchema, { variables: {
|
|
1547
|
+
first: input.first,
|
|
1548
|
+
...input.after ? { after: input.after } : {},
|
|
1549
|
+
...input.query ? { query: input.query } : {}
|
|
1550
|
+
} })).customers;
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
|
|
1554
|
+
//#endregion
|
|
1555
|
+
//#region src/operations/list-shopify-fulfillment-orders-for-order.operation.ts
|
|
1556
|
+
const listFulfillmentOrdersForOrderOperation = new Operation({
|
|
1557
|
+
credentialSets: [shopifyCredentialSet],
|
|
1558
|
+
id: "shopify.list-shopify-fulfillment-orders-for-order",
|
|
1559
|
+
name: "List Shopify Fulfillment Orders For Order",
|
|
1560
|
+
description: "List fulfillment orders for a Shopify order so they can be fulfilled.",
|
|
1561
|
+
input: z.object({
|
|
1562
|
+
orderId: shopifyGlobalIdSchema,
|
|
1563
|
+
first: z.number().int().min(1).max(100).optional().default(25),
|
|
1564
|
+
after: z.string().optional()
|
|
1565
|
+
}),
|
|
1566
|
+
output: shopifyConnectionNodesSchema(fulfillmentOrderSchema),
|
|
1567
|
+
run: async (input, context) => {
|
|
1568
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1569
|
+
query ListFulfillmentOrdersForOrder($id: ID!, $first: Int!, $after: String) {
|
|
1570
|
+
order(id: $id) {
|
|
1571
|
+
fulfillmentOrders(first: $first, after: $after) {
|
|
1572
|
+
nodes {
|
|
1573
|
+
id
|
|
1574
|
+
status
|
|
1575
|
+
assignedLocation {
|
|
1576
|
+
location {
|
|
1577
|
+
id
|
|
1578
|
+
name
|
|
1579
|
+
isActive
|
|
1580
|
+
fulfillsOnlineOrders
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
lineItems(first: 50) {
|
|
1584
|
+
nodes {
|
|
1585
|
+
id
|
|
1586
|
+
remainingQuantity
|
|
1587
|
+
lineItem {
|
|
1588
|
+
id
|
|
1589
|
+
name
|
|
1590
|
+
quantity
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
pageInfo {
|
|
1594
|
+
hasNextPage
|
|
1595
|
+
hasPreviousPage
|
|
1596
|
+
startCursor
|
|
1597
|
+
endCursor
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
pageInfo {
|
|
1602
|
+
hasNextPage
|
|
1603
|
+
hasPreviousPage
|
|
1604
|
+
startCursor
|
|
1605
|
+
endCursor
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
`, fulfillmentOrderConnectionSchema, { variables: {
|
|
1611
|
+
id: input.orderId,
|
|
1612
|
+
first: input.first,
|
|
1613
|
+
...input.after ? { after: input.after } : {}
|
|
1614
|
+
} });
|
|
1615
|
+
if (!response.order) throw new Error(`Shopify order not found for fulfillment orders lookup: ${input.orderId}`);
|
|
1616
|
+
return response.order.fulfillmentOrders;
|
|
1617
|
+
}
|
|
1618
|
+
});
|
|
1619
|
+
|
|
1620
|
+
//#endregion
|
|
1621
|
+
//#region src/operations/list-shopify-inventory-items.operation.ts
|
|
1622
|
+
const listInventoryItemsOperation = new Operation({
|
|
1623
|
+
credentialSets: [shopifyCredentialSet],
|
|
1624
|
+
id: "shopify.list-shopify-inventory-items",
|
|
1625
|
+
name: "List Shopify Inventory Items",
|
|
1626
|
+
description: "List inventory items from the connected Shopify store.",
|
|
1627
|
+
input: shopifyPageInputSchema,
|
|
1628
|
+
output: shopifyConnectionNodesSchema(shopifyInventoryItemSchema),
|
|
1629
|
+
run: async (input, context) => {
|
|
1630
|
+
return (await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1631
|
+
query ListInventoryItems($first: Int!, $after: String, $query: String) {
|
|
1632
|
+
inventoryItems(first: $first, after: $after, query: $query) {
|
|
1633
|
+
nodes {
|
|
1634
|
+
${inventoryItemSelection}
|
|
1635
|
+
}
|
|
1636
|
+
pageInfo {
|
|
1637
|
+
hasNextPage
|
|
1638
|
+
hasPreviousPage
|
|
1639
|
+
startCursor
|
|
1640
|
+
endCursor
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
`, listInventoryItemsResponseSchema, { variables: {
|
|
1645
|
+
first: input.first,
|
|
1646
|
+
...input.after ? { after: input.after } : {},
|
|
1647
|
+
...input.query ? { query: input.query } : {}
|
|
1648
|
+
} })).inventoryItems;
|
|
1649
|
+
}
|
|
1650
|
+
});
|
|
1651
|
+
|
|
1652
|
+
//#endregion
|
|
1653
|
+
//#region src/operations/list-shopify-locations.operation.ts
|
|
1654
|
+
const listLocationsOperation = new Operation({
|
|
1655
|
+
credentialSets: [shopifyCredentialSet],
|
|
1656
|
+
id: "shopify.list-shopify-locations",
|
|
1657
|
+
name: "List Shopify Locations",
|
|
1658
|
+
description: "List locations from the connected Shopify store.",
|
|
1659
|
+
input: shopifyPageInputSchema.extend({
|
|
1660
|
+
includeInactive: z.boolean().optional(),
|
|
1661
|
+
includeLegacy: z.boolean().optional()
|
|
1662
|
+
}),
|
|
1663
|
+
output: shopifyConnectionNodesSchema(shopifyLocationSchema),
|
|
1664
|
+
run: async (input, context) => {
|
|
1665
|
+
return (await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1666
|
+
query ListLocations(
|
|
1667
|
+
$first: Int!
|
|
1668
|
+
$after: String
|
|
1669
|
+
$query: String
|
|
1670
|
+
$includeInactive: Boolean
|
|
1671
|
+
$includeLegacy: Boolean
|
|
1672
|
+
) {
|
|
1673
|
+
locations(
|
|
1674
|
+
first: $first
|
|
1675
|
+
after: $after
|
|
1676
|
+
query: $query
|
|
1677
|
+
includeInactive: $includeInactive
|
|
1678
|
+
includeLegacy: $includeLegacy
|
|
1679
|
+
) {
|
|
1680
|
+
nodes {
|
|
1681
|
+
${locationSelection}
|
|
1682
|
+
}
|
|
1683
|
+
pageInfo {
|
|
1684
|
+
hasNextPage
|
|
1685
|
+
hasPreviousPage
|
|
1686
|
+
startCursor
|
|
1687
|
+
endCursor
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
`, listLocationsResponseSchema, { variables: {
|
|
1692
|
+
first: input.first,
|
|
1693
|
+
...input.after ? { after: input.after } : {},
|
|
1694
|
+
...input.query ? { query: input.query } : {},
|
|
1695
|
+
...input.includeInactive !== void 0 ? { includeInactive: input.includeInactive } : {},
|
|
1696
|
+
...input.includeLegacy !== void 0 ? { includeLegacy: input.includeLegacy } : {}
|
|
1697
|
+
} })).locations;
|
|
1698
|
+
}
|
|
1699
|
+
});
|
|
1700
|
+
|
|
1701
|
+
//#endregion
|
|
1702
|
+
//#region src/operations/list-shopify-orders.operation.ts
|
|
1703
|
+
const listOrdersOperation = new Operation({
|
|
1704
|
+
credentialSets: [shopifyCredentialSet],
|
|
1705
|
+
id: "shopify.list-shopify-orders",
|
|
1706
|
+
name: "List Shopify Orders",
|
|
1707
|
+
description: "List orders from the connected Shopify store.",
|
|
1708
|
+
input: shopifyPageInputSchema,
|
|
1709
|
+
output: shopifyConnectionNodesSchema(shopifyOrderSchema),
|
|
1710
|
+
run: async (input, context) => {
|
|
1711
|
+
return (await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1712
|
+
query ListOrders($first: Int!, $after: String, $query: String) {
|
|
1713
|
+
orders(first: $first, after: $after, query: $query) {
|
|
1714
|
+
nodes {
|
|
1715
|
+
${orderSelection$1}
|
|
1716
|
+
}
|
|
1717
|
+
pageInfo {
|
|
1718
|
+
hasNextPage
|
|
1719
|
+
hasPreviousPage
|
|
1720
|
+
startCursor
|
|
1721
|
+
endCursor
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
`, listOrdersResponseSchema, { variables: {
|
|
1726
|
+
first: input.first,
|
|
1727
|
+
...input.after ? { after: input.after } : {},
|
|
1728
|
+
...input.query ? { query: input.query } : {}
|
|
1729
|
+
} })).orders;
|
|
1730
|
+
}
|
|
1731
|
+
});
|
|
1732
|
+
|
|
1733
|
+
//#endregion
|
|
1734
|
+
//#region src/operations/list-shopify-products.operation.ts
|
|
1735
|
+
const listProductsOperation = new Operation({
|
|
1736
|
+
credentialSets: [shopifyCredentialSet],
|
|
1737
|
+
id: "shopify.list-shopify-products",
|
|
1738
|
+
name: "List Shopify Products",
|
|
1739
|
+
description: "List products from the connected Shopify store.",
|
|
1740
|
+
input: shopifyPageInputSchema,
|
|
1741
|
+
output: shopifyConnectionNodesSchema(shopifyProductSchema),
|
|
1742
|
+
run: async (input, context) => {
|
|
1743
|
+
return (await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1744
|
+
query ListProducts($first: Int!, $after: String, $query: String) {
|
|
1745
|
+
products(first: $first, after: $after, query: $query) {
|
|
1746
|
+
nodes {
|
|
1747
|
+
${productSelection}
|
|
1748
|
+
}
|
|
1749
|
+
pageInfo {
|
|
1750
|
+
hasNextPage
|
|
1751
|
+
hasPreviousPage
|
|
1752
|
+
startCursor
|
|
1753
|
+
endCursor
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
`, listProductsResponseSchema, { variables: {
|
|
1758
|
+
first: input.first,
|
|
1759
|
+
...input.after ? { after: input.after } : {},
|
|
1760
|
+
...input.query ? { query: input.query } : {}
|
|
1761
|
+
} })).products;
|
|
1762
|
+
}
|
|
1763
|
+
});
|
|
1764
|
+
|
|
1765
|
+
//#endregion
|
|
1766
|
+
//#region src/operations/remove-products-from-shopify-collection.operation.ts
|
|
1767
|
+
const removeProductsFromCollectionOperation = new Operation({
|
|
1768
|
+
credentialSets: [shopifyCredentialSet],
|
|
1769
|
+
id: "shopify.remove-products-from-shopify-collection",
|
|
1770
|
+
name: "Remove Products From Shopify Collection",
|
|
1771
|
+
description: "Remove products from a manual Shopify collection.",
|
|
1772
|
+
needsApproval: true,
|
|
1773
|
+
input: z.object({
|
|
1774
|
+
id: shopifyGlobalIdSchema,
|
|
1775
|
+
productIds: shopifyProductIdsInputSchema
|
|
1776
|
+
}),
|
|
1777
|
+
output: shopifyJobSchema,
|
|
1778
|
+
run: async (input, context) => {
|
|
1779
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1780
|
+
mutation RemoveProductsFromCollection($id: ID!, $productIds: [ID!]!) {
|
|
1781
|
+
collectionRemoveProducts(id: $id, productIds: $productIds) {
|
|
1782
|
+
job {
|
|
1783
|
+
id
|
|
1784
|
+
done
|
|
1785
|
+
}
|
|
1786
|
+
userErrors {
|
|
1787
|
+
field
|
|
1788
|
+
message
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
`, z.object({ collectionRemoveProducts: removeProductsResponseSchema }), { variables: {
|
|
1793
|
+
id: input.id,
|
|
1794
|
+
productIds: input.productIds
|
|
1795
|
+
} });
|
|
1796
|
+
assertNoUserErrors(response.collectionRemoveProducts.userErrors);
|
|
1797
|
+
if (!response.collectionRemoveProducts.job) throw new Error(`Shopify did not return a removal job for collection: ${input.id}`);
|
|
1798
|
+
return response.collectionRemoveProducts.job;
|
|
1799
|
+
}
|
|
1800
|
+
});
|
|
1801
|
+
|
|
1802
|
+
//#endregion
|
|
1803
|
+
//#region src/operations/update-shopify-article.operation.ts
|
|
1804
|
+
const updateArticleOperation = new Operation({
|
|
1805
|
+
credentialSets: [shopifyCredentialSet],
|
|
1806
|
+
id: "shopify.update-shopify-article",
|
|
1807
|
+
name: "Update Shopify Article",
|
|
1808
|
+
description: "Update a Shopify article by its global ID.",
|
|
1809
|
+
needsApproval: true,
|
|
1810
|
+
input: articleMutationInputSchema.extend({
|
|
1811
|
+
id: shopifyGlobalIdSchema,
|
|
1812
|
+
redirectNewHandle: z.boolean().optional()
|
|
1813
|
+
}),
|
|
1814
|
+
output: shopifyArticleSchema,
|
|
1815
|
+
run: async (input, context) => {
|
|
1816
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1817
|
+
mutation UpdateArticle($id: ID!, $article: ArticleUpdateInput!) {
|
|
1818
|
+
articleUpdate(id: $id, article: $article) {
|
|
1819
|
+
article {
|
|
1820
|
+
${articleSelection}
|
|
1821
|
+
}
|
|
1822
|
+
userErrors {
|
|
1823
|
+
code
|
|
1824
|
+
field
|
|
1825
|
+
message
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
`, z.object({ articleUpdate: articleMutationPayloadSchema }), { variables: {
|
|
1830
|
+
id: input.id,
|
|
1831
|
+
article: omitUndefined({
|
|
1832
|
+
...buildArticleInput(input),
|
|
1833
|
+
redirectNewHandle: input.redirectNewHandle
|
|
1834
|
+
})
|
|
1835
|
+
} });
|
|
1836
|
+
assertNoUserErrors(response.articleUpdate.userErrors);
|
|
1837
|
+
if (!response.articleUpdate.article) throw new Error(`Shopify did not return the updated article: ${input.id}`);
|
|
1838
|
+
return normalizeArticle(response.articleUpdate.article);
|
|
1839
|
+
}
|
|
1840
|
+
});
|
|
1841
|
+
|
|
1842
|
+
//#endregion
|
|
1843
|
+
//#region src/operations/update-shopify-blog.operation.ts
|
|
1844
|
+
const updateBlogOperation = new Operation({
|
|
1845
|
+
credentialSets: [shopifyCredentialSet],
|
|
1846
|
+
id: "shopify.update-shopify-blog",
|
|
1847
|
+
name: "Update Shopify Blog",
|
|
1848
|
+
description: "Update a Shopify blog by its global ID.",
|
|
1849
|
+
needsApproval: true,
|
|
1850
|
+
input: blogMutationInputSchema.extend({ id: shopifyGlobalIdSchema }),
|
|
1851
|
+
output: shopifyBlogSchema,
|
|
1852
|
+
run: async (input, context) => {
|
|
1853
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1854
|
+
mutation UpdateBlog($id: ID!, $blog: BlogUpdateInput!) {
|
|
1855
|
+
blogUpdate(id: $id, blog: $blog) {
|
|
1856
|
+
blog {
|
|
1857
|
+
${blogSelection}
|
|
1858
|
+
}
|
|
1859
|
+
userErrors {
|
|
1860
|
+
code
|
|
1861
|
+
field
|
|
1862
|
+
message
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
`, z.object({ blogUpdate: blogMutationResponseSchema }), { variables: {
|
|
1867
|
+
id: input.id,
|
|
1868
|
+
blog: omitUndefined({
|
|
1869
|
+
title: input.title,
|
|
1870
|
+
handle: input.handle,
|
|
1871
|
+
templateSuffix: input.templateSuffix,
|
|
1872
|
+
commentPolicy: input.commentPolicy
|
|
1873
|
+
})
|
|
1874
|
+
} });
|
|
1875
|
+
assertNoUserErrors(response.blogUpdate.userErrors);
|
|
1876
|
+
if (!response.blogUpdate.blog) throw new Error(`Shopify did not return the updated blog: ${input.id}`);
|
|
1877
|
+
return response.blogUpdate.blog;
|
|
1878
|
+
}
|
|
1879
|
+
});
|
|
1880
|
+
|
|
1881
|
+
//#endregion
|
|
1882
|
+
//#region src/operations/update-shopify-customer.operation.ts
|
|
1883
|
+
const updateCustomerOperation = new Operation({
|
|
1884
|
+
credentialSets: [shopifyCredentialSet],
|
|
1885
|
+
id: "shopify.update-shopify-customer",
|
|
1886
|
+
name: "Update Shopify Customer",
|
|
1887
|
+
description: "Update a Shopify customer by its global ID.",
|
|
1888
|
+
needsApproval: true,
|
|
1889
|
+
input: customerMutationInputSchema.extend({ id: shopifyGlobalIdSchema }),
|
|
1890
|
+
output: shopifyCustomerSchema,
|
|
1891
|
+
run: async (input, context) => {
|
|
1892
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1893
|
+
mutation UpdateCustomer($input: CustomerInput!) {
|
|
1894
|
+
customerUpdate(input: $input) {
|
|
1895
|
+
customer {
|
|
1896
|
+
${customerSelection}
|
|
1897
|
+
}
|
|
1898
|
+
userErrors {
|
|
1899
|
+
field
|
|
1900
|
+
message
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
`, z.object({ customerUpdate: customerMutationResponseSchema }), { variables: { input: omitUndefined(input) } });
|
|
1905
|
+
assertNoUserErrors(response.customerUpdate.userErrors);
|
|
1906
|
+
if (!response.customerUpdate.customer) throw new Error(`Shopify did not return the updated customer: ${input.id}`);
|
|
1907
|
+
return response.customerUpdate.customer;
|
|
1908
|
+
}
|
|
1909
|
+
});
|
|
1910
|
+
|
|
1911
|
+
//#endregion
|
|
1912
|
+
//#region src/operations/update-shopify-order.operation.ts
|
|
1913
|
+
const updateOrderOperation = new Operation({
|
|
1914
|
+
credentialSets: [shopifyCredentialSet],
|
|
1915
|
+
id: "shopify.update-shopify-order",
|
|
1916
|
+
name: "Update Shopify Order",
|
|
1917
|
+
description: "Update simple order attributes such as note, tags, email, or shipping address.",
|
|
1918
|
+
needsApproval: true,
|
|
1919
|
+
input: orderUpdateInputSchema,
|
|
1920
|
+
output: shopifyOrderSchema,
|
|
1921
|
+
run: async (input, context) => {
|
|
1922
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1923
|
+
mutation UpdateOrder($input: OrderInput!) {
|
|
1924
|
+
orderUpdate(input: $input) {
|
|
1925
|
+
order {
|
|
1926
|
+
${orderSelection$1}
|
|
1927
|
+
}
|
|
1928
|
+
userErrors {
|
|
1929
|
+
field
|
|
1930
|
+
message
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
`, z.object({ orderUpdate: orderMutationResponseSchema }), { variables: { input: omitUndefined(input) } });
|
|
1935
|
+
assertNoUserErrors(response.orderUpdate.userErrors);
|
|
1936
|
+
if (!response.orderUpdate.order) throw new Error(`Shopify did not return the updated order: ${input.id}`);
|
|
1937
|
+
return response.orderUpdate.order;
|
|
1938
|
+
}
|
|
1939
|
+
});
|
|
1940
|
+
|
|
1941
|
+
//#endregion
|
|
1942
|
+
//#region src/operations/update-shopify-product.operation.ts
|
|
1943
|
+
const updateProductOperation = new Operation({
|
|
1944
|
+
credentialSets: [shopifyCredentialSet],
|
|
1945
|
+
id: "shopify.update-shopify-product",
|
|
1946
|
+
name: "Update Shopify Product",
|
|
1947
|
+
description: "Update a Shopify product by its global ID.",
|
|
1948
|
+
needsApproval: true,
|
|
1949
|
+
input: productMutationInputSchema.extend({ id: shopifyGlobalIdSchema }),
|
|
1950
|
+
output: shopifyProductSchema,
|
|
1951
|
+
run: async (input, context) => {
|
|
1952
|
+
const response = await createShopifyClient(context.credentials.shopify).graphql(`
|
|
1953
|
+
mutation UpdateProduct($product: ProductUpdateInput!) {
|
|
1954
|
+
productUpdate(product: $product) {
|
|
1955
|
+
product {
|
|
1956
|
+
${productSelection}
|
|
1957
|
+
}
|
|
1958
|
+
userErrors {
|
|
1959
|
+
field
|
|
1960
|
+
message
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
`, z.object({ productUpdate: productMutationResponseSchema }), { variables: { product: omitUndefined(input) } });
|
|
1965
|
+
assertNoUserErrors(response.productUpdate.userErrors);
|
|
1966
|
+
if (!response.productUpdate.product) throw new Error(`Shopify did not return the updated product: ${input.id}`);
|
|
1967
|
+
return response.productUpdate.product;
|
|
1968
|
+
}
|
|
1969
|
+
});
|
|
1970
|
+
|
|
1971
|
+
//#endregion
|
|
1972
|
+
export { deleteCollectionOperation as A, cancelOrderOperation as B, getCustomerOrdersOperation as C, getArticleOperation as D, getBlogOperation as E, createFulfillmentOperation as F, addProductsToCollectionOperation as H, createCustomerOperation as I, createCollectionOperation as L, deleteArticleOperation as M, createProductOperation as N, deleteProductOperation as O, createOrderOperation as P, createBlogOperation as R, getFulfillmentOperation as S, getCollectionOperation as T, adjustInventoryQuantitiesOperation as V, getProductOperation as _, updateArticleOperation as a, getInventoryLevelsForItemOperation as b, listOrdersOperation as c, listFulfillmentOrdersForOrderOperation as d, listCustomersOperation as f, getShopOperation as g, listArticlesOperation as h, updateBlogOperation as i, deleteBlogOperation as j, deleteCustomerOperation as k, listLocationsOperation as l, listBlogsOperation as m, updateOrderOperation as n, removeProductsFromCollectionOperation as o, listCollectionsOperation as p, updateCustomerOperation as r, listProductsOperation as s, updateProductOperation as t, listInventoryItemsOperation as u, getOrderOperation as v, getCustomerOperation as w, getInventoryItemOperation as x, getLocationOperation as y, createArticleOperation as z };
|