ecomcoder-cli 1.3.11 → 1.3.13

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.
Files changed (105) hide show
  1. package/README.md +16 -0
  2. package/dist/commands/asset/delete.d.ts.map +1 -1
  3. package/dist/commands/asset/delete.js +14 -0
  4. package/dist/commands/asset/delete.js.map +1 -1
  5. package/dist/commands/asset/import.d.ts.map +1 -1
  6. package/dist/commands/asset/import.js +14 -0
  7. package/dist/commands/asset/import.js.map +1 -1
  8. package/dist/commands/asset/upload.d.ts.map +1 -1
  9. package/dist/commands/asset/upload.js +14 -0
  10. package/dist/commands/asset/upload.js.map +1 -1
  11. package/dist/commands/create-dummy-products.d.ts.map +1 -1
  12. package/dist/commands/create-dummy-products.js +14 -0
  13. package/dist/commands/create-dummy-products.js.map +1 -1
  14. package/dist/commands/create-metafield.d.ts.map +1 -1
  15. package/dist/commands/create-metafield.js +14 -0
  16. package/dist/commands/create-metafield.js.map +1 -1
  17. package/dist/commands/discount/create-basic.d.ts.map +1 -1
  18. package/dist/commands/discount/create-basic.js +14 -0
  19. package/dist/commands/discount/create-basic.js.map +1 -1
  20. package/dist/commands/discount/create-bxgy.d.ts.map +1 -1
  21. package/dist/commands/discount/create-bxgy.js +14 -0
  22. package/dist/commands/discount/create-bxgy.js.map +1 -1
  23. package/dist/commands/discount/create-shipping.d.ts.map +1 -1
  24. package/dist/commands/discount/create-shipping.js +14 -0
  25. package/dist/commands/discount/create-shipping.js.map +1 -1
  26. package/dist/commands/discount/delete.d.ts.map +1 -1
  27. package/dist/commands/discount/delete.js +14 -0
  28. package/dist/commands/discount/delete.js.map +1 -1
  29. package/dist/commands/product/add-options.d.ts.map +1 -1
  30. package/dist/commands/product/add-options.js +14 -0
  31. package/dist/commands/product/add-options.js.map +1 -1
  32. package/dist/commands/product/add-tags.d.ts +9 -0
  33. package/dist/commands/product/add-tags.d.ts.map +1 -0
  34. package/dist/commands/product/add-tags.js +93 -0
  35. package/dist/commands/product/add-tags.js.map +1 -0
  36. package/dist/commands/product/create-variants.d.ts.map +1 -1
  37. package/dist/commands/product/create-variants.js +14 -0
  38. package/dist/commands/product/create-variants.js.map +1 -1
  39. package/dist/commands/product/create.d.ts.map +1 -1
  40. package/dist/commands/product/create.js +92 -4
  41. package/dist/commands/product/create.js.map +1 -1
  42. package/dist/commands/product/delete-variants.d.ts.map +1 -1
  43. package/dist/commands/product/delete-variants.js +14 -0
  44. package/dist/commands/product/delete-variants.js.map +1 -1
  45. package/dist/commands/product/index.d.ts.map +1 -1
  46. package/dist/commands/product/index.js +32 -0
  47. package/dist/commands/product/index.js.map +1 -1
  48. package/dist/commands/product/queries.d.ts +23 -0
  49. package/dist/commands/product/queries.d.ts.map +1 -1
  50. package/dist/commands/product/queries.js +80 -0
  51. package/dist/commands/product/queries.js.map +1 -1
  52. package/dist/commands/product/remove-tags.d.ts +9 -0
  53. package/dist/commands/product/remove-tags.d.ts.map +1 -0
  54. package/dist/commands/product/remove-tags.js +108 -0
  55. package/dist/commands/product/remove-tags.js.map +1 -0
  56. package/dist/commands/product/service.d.ts +81 -2
  57. package/dist/commands/product/service.d.ts.map +1 -1
  58. package/dist/commands/product/service.js +291 -13
  59. package/dist/commands/product/service.js.map +1 -1
  60. package/dist/commands/product/set-metafield.d.ts.map +1 -1
  61. package/dist/commands/product/set-metafield.js +14 -0
  62. package/dist/commands/product/set-metafield.js.map +1 -1
  63. package/dist/commands/product/set-tags.d.ts +9 -0
  64. package/dist/commands/product/set-tags.d.ts.map +1 -0
  65. package/dist/commands/product/set-tags.js +107 -0
  66. package/dist/commands/product/set-tags.js.map +1 -0
  67. package/dist/commands/product/types.d.ts +58 -0
  68. package/dist/commands/product/types.d.ts.map +1 -1
  69. package/dist/commands/product/update-description.d.ts.map +1 -1
  70. package/dist/commands/product/update-description.js +14 -0
  71. package/dist/commands/product/update-description.js.map +1 -1
  72. package/dist/commands/product/update-images.d.ts +8 -0
  73. package/dist/commands/product/update-images.d.ts.map +1 -0
  74. package/dist/commands/product/update-images.js +191 -0
  75. package/dist/commands/product/update-images.js.map +1 -0
  76. package/dist/commands/product/update-options.d.ts.map +1 -1
  77. package/dist/commands/product/update-options.js +14 -0
  78. package/dist/commands/product/update-options.js.map +1 -1
  79. package/dist/commands/product/update-price.d.ts.map +1 -1
  80. package/dist/commands/product/update-price.js +14 -0
  81. package/dist/commands/product/update-price.js.map +1 -1
  82. package/dist/commands/product/update-status.d.ts.map +1 -1
  83. package/dist/commands/product/update-status.js +14 -0
  84. package/dist/commands/product/update-status.js.map +1 -1
  85. package/dist/commands/product/update-template.d.ts.map +1 -1
  86. package/dist/commands/product/update-template.js +14 -0
  87. package/dist/commands/product/update-template.js.map +1 -1
  88. package/dist/commands/product/update-title.d.ts.map +1 -1
  89. package/dist/commands/product/update-title.js +14 -0
  90. package/dist/commands/product/update-title.js.map +1 -1
  91. package/dist/commands/set-product-rating.d.ts.map +1 -1
  92. package/dist/commands/set-product-rating.js +14 -0
  93. package/dist/commands/set-product-rating.js.map +1 -1
  94. package/dist/commands/shop/set-metafield.d.ts.map +1 -1
  95. package/dist/commands/shop/set-metafield.js +14 -0
  96. package/dist/commands/shop/set-metafield.js.map +1 -1
  97. package/dist/lib/approval.d.ts +28 -0
  98. package/dist/lib/approval.d.ts.map +1 -0
  99. package/dist/lib/approval.js +38 -0
  100. package/dist/lib/approval.js.map +1 -0
  101. package/dist/lib/image-library.d.ts +65 -0
  102. package/dist/lib/image-library.d.ts.map +1 -0
  103. package/dist/lib/image-library.js +143 -0
  104. package/dist/lib/image-library.js.map +1 -0
  105. package/package.json +1 -1
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Remove Product Tags Command
3
+ *
4
+ * Following Command Pattern - thin orchestration layer
5
+ * Delegates business logic to ProductService
6
+ * DESTRUCTIVE - Requires approval flow
7
+ */
8
+ import { getCredentials, getSessionId } from '../../lib/api-client.js';
9
+ import { parseArgs, hasHelpFlag } from '../../lib/args-parser.js';
10
+ import { ProductService } from './service.js';
11
+ import { requestApproval } from '../../lib/approval.js';
12
+ function showHelp() {
13
+ console.log(`
14
+ Remove Product Tags
15
+
16
+ USAGE:
17
+ ecomcoder product remove-tags --id=<id> --tags=<tag1,tag2,tag3>
18
+
19
+ REQUIRED OPTIONS:
20
+ --id <id> Product ID (numeric or GID)
21
+ --tags <tags> Comma-separated tags to remove
22
+
23
+ EXAMPLES:
24
+ # Remove single tag
25
+ ecomcoder product remove-tags --id=123 --tags="discontinued"
26
+
27
+ # Remove multiple tags
28
+ ecomcoder product remove-tags --id=123 --tags="old-collection,winter-2023"
29
+
30
+ # Using GID
31
+ ecomcoder product remove-tags --id="gid://shopify/Product/123" --tags="clearance"
32
+
33
+ NOTES:
34
+ - Destructive operation (removes tags from product)
35
+ - Requires approval before execution
36
+ - Silently ignores tags that don't exist on product
37
+ - Removed tags can be re-added using add-tags command
38
+ - Tags are case-sensitive
39
+ `);
40
+ process.exit(0);
41
+ }
42
+ export async function run(argv = process.argv.slice(2)) {
43
+ if (hasHelpFlag(argv)) {
44
+ showHelp();
45
+ }
46
+ const args = parseArgs(argv);
47
+ // Validate required arguments
48
+ if (!args.id) {
49
+ console.error(JSON.stringify({
50
+ success: false,
51
+ error: 'Missing required argument: --id'
52
+ }));
53
+ process.exit(1);
54
+ }
55
+ if (!args.tags) {
56
+ console.error(JSON.stringify({
57
+ success: false,
58
+ error: 'Missing required argument: --tags'
59
+ }));
60
+ process.exit(1);
61
+ }
62
+ try {
63
+ // Parse tags from comma-separated string
64
+ const tags = args.tags.split(',').map((tag) => tag.trim()).filter(Boolean);
65
+ if (tags.length === 0) {
66
+ console.error(JSON.stringify({
67
+ success: false,
68
+ error: 'No valid tags provided'
69
+ }));
70
+ process.exit(1);
71
+ }
72
+ // Get credentials
73
+ const sessionId = getSessionId(args.sessionId);
74
+ const credentials = await getCredentials(sessionId, args.backendUrl, args.jwt);
75
+ // Request approval before executing
76
+ const tagCount = tags.length;
77
+ const approved = await requestApproval({
78
+ command: `ecomcoder product remove-tags --id=${args.id} --tags=${args.tags}`,
79
+ message: `This will remove ${tagCount} tag(s) from your product on the live Shopify store. Removed tags can be re-added later.`,
80
+ riskLevel: 'moderate'
81
+ });
82
+ if (!approved) {
83
+ console.log(JSON.stringify({
84
+ success: false,
85
+ error: 'Operation cancelled by user'
86
+ }));
87
+ process.exit(1);
88
+ }
89
+ // Execute remove via service
90
+ const result = await ProductService.removeTags(credentials, {
91
+ id: args.id,
92
+ tags
93
+ });
94
+ // Output result
95
+ console.log(JSON.stringify(result, null, 2));
96
+ if (!result.success) {
97
+ process.exit(1);
98
+ }
99
+ }
100
+ catch (error) {
101
+ console.error(JSON.stringify({
102
+ success: false,
103
+ error: error.message || 'Unknown error occurred'
104
+ }));
105
+ process.exit(1);
106
+ }
107
+ }
108
+ //# sourceMappingURL=remove-tags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove-tags.js","sourceRoot":"","sources":["../../../src/commands/product/remove-tags.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@
5
5
  * Follows Dependency Injection - accepts dependencies as parameters
6
6
  */
7
7
  import type { ShopifyCredentials } from '../../lib/types.js';
8
- import type { ShopifyProduct, FormattedProduct, UpdateDescriptionInput, UpdateTitleInput, UpdateStatusInput, UpdatePriceInput, UpdateTemplateInput, SetMetafieldInput, GetMetafieldInput, DeleteVariantsInput, CreateVariantsInput, CreateProductInput, AddOptionsInput, UpdateOptionInput, CommandResult } from './types.js';
8
+ import type { ShopifyProduct, FormattedProduct, UpdateDescriptionInput, UpdateTitleInput, UpdateStatusInput, UpdatePriceInput, UpdateTemplateInput, UpdateImagesInput, SetMetafieldInput, GetMetafieldInput, DeleteVariantsInput, CreateVariantsInput, CreateProductInput, AddOptionsInput, UpdateOptionInput, AddTagsInput, RemoveTagsInput, SetTagsInput, CommandResult } from './types.js';
9
9
  /**
10
10
  * Product Service
11
11
  *
@@ -22,9 +22,16 @@ export declare class ProductService {
22
22
  /**
23
23
  * Create a new product from scratch
24
24
  *
25
+ * @param credentials Shopify credentials
26
+ * @param input Product creation input
27
+ * @param media Optional media/images to add (null = no images, undefined/array = add images)
25
28
  * @returns Formatted result with created product data
26
29
  */
27
- static createProduct(credentials: ShopifyCredentials, input: CreateProductInput): Promise<CommandResult<{
30
+ static createProduct(credentials: ShopifyCredentials, input: CreateProductInput, media?: Array<{
31
+ originalSource: string;
32
+ alt?: string;
33
+ mediaContentType: string;
34
+ }> | null): Promise<CommandResult<{
28
35
  product: FormattedProduct;
29
36
  }>>;
30
37
  /**
@@ -51,6 +58,24 @@ export declare class ProductService {
51
58
  static updateStatus(credentials: ShopifyCredentials, input: UpdateStatusInput): Promise<CommandResult<{
52
59
  product: FormattedProduct;
53
60
  }>>;
61
+ /**
62
+ * Update product images
63
+ * Adds new images to the product using smart, context-aware image selection
64
+ *
65
+ * Strategy:
66
+ * 1. If --images provided: Use custom URLs
67
+ * 2. If --search provided: Search Pexels with custom query
68
+ * 3. If --random provided: Generate random placeholders
69
+ * 4. Default: Use product title to search for relevant images
70
+ *
71
+ * Note: Shopify productUpdate with media parameter ADDS images, doesn't replace existing ones
72
+ *
73
+ * @returns Formatted result with updated product and media
74
+ */
75
+ static updateImages(credentials: ShopifyCredentials, input: UpdateImagesInput): Promise<CommandResult<{
76
+ product: any;
77
+ imagesAdded: number;
78
+ }>>;
54
79
  /**
55
80
  * Set product metafield value
56
81
  *
@@ -150,5 +175,59 @@ export declare class ProductService {
150
175
  static updateOption(credentials: ShopifyCredentials, input: UpdateOptionInput): Promise<CommandResult<{
151
176
  product: FormattedProduct;
152
177
  }>>;
178
+ /**
179
+ * Add tags to product (non-destructive)
180
+ * Uses tagsAdd mutation
181
+ *
182
+ * IMPORTANT:
183
+ * - Preserves existing tags
184
+ * - Duplicate tags are handled by Shopify
185
+ * - No approval required (non-destructive)
186
+ *
187
+ * @returns Formatted result with updated product tags
188
+ */
189
+ static addTags(credentials: ShopifyCredentials, input: AddTagsInput): Promise<CommandResult<{
190
+ product: {
191
+ id: string;
192
+ title: string;
193
+ tags: string[];
194
+ };
195
+ }>>;
196
+ /**
197
+ * Remove tags from product (destructive)
198
+ * Uses tagsRemove mutation
199
+ *
200
+ * IMPORTANT:
201
+ * - Removes specified tags from product
202
+ * - Requires approval (destructive operation)
203
+ * - Silently ignores tags that don't exist on product
204
+ *
205
+ * @returns Formatted result with updated product tags
206
+ */
207
+ static removeTags(credentials: ShopifyCredentials, input: RemoveTagsInput): Promise<CommandResult<{
208
+ product: {
209
+ id: string;
210
+ title: string;
211
+ tags: string[];
212
+ };
213
+ }>>;
214
+ /**
215
+ * Set/replace all product tags (destructive)
216
+ * Uses productUpdate mutation
217
+ *
218
+ * IMPORTANT:
219
+ * - REPLACES all existing tags with new tags
220
+ * - Requires approval (destructive operation)
221
+ * - Pass empty array to remove all tags
222
+ *
223
+ * @returns Formatted result with updated product tags
224
+ */
225
+ static setTags(credentials: ShopifyCredentials, input: SetTagsInput): Promise<CommandResult<{
226
+ product: {
227
+ id: string;
228
+ title: string;
229
+ tags: string[];
230
+ };
231
+ }>>;
153
232
  }
154
233
  //# sourceMappingURL=service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/commands/product/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/commands/product/service.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,8 @@
5
5
  * Follows Dependency Injection - accepts dependencies as parameters
6
6
  */
7
7
  import { shopifyGraphQL } from '../../lib/shopify-client.js';
8
- import { GET_PRODUCT_BY_ID, UPDATE_PRODUCT, PRODUCT_VARIANTS_BULK_UPDATE, PRODUCT_VARIANTS_BULK_DELETE, PRODUCT_VARIANTS_BULK_CREATE, PRODUCT_CREATE, GET_PRODUCT_METAFIELD, GET_PRODUCT_METAFIELDS, METAFIELDS_SET, PRODUCT_OPTIONS_CREATE, PRODUCT_OPTION_UPDATE, GET_PUBLICATIONS, PUBLISHABLE_PUBLISH } from './queries.js';
8
+ import { GET_PRODUCT_BY_ID, UPDATE_PRODUCT, UPDATE_PRODUCT_MEDIA, PRODUCT_VARIANTS_BULK_UPDATE, PRODUCT_VARIANTS_BULK_DELETE, PRODUCT_VARIANTS_BULK_CREATE, PRODUCT_CREATE, GET_PRODUCT_METAFIELD, GET_PRODUCT_METAFIELDS, METAFIELDS_SET, PRODUCT_OPTIONS_CREATE, PRODUCT_OPTION_UPDATE, GET_PUBLICATIONS, PUBLISHABLE_PUBLISH, TAGS_ADD, TAGS_REMOVE } from './queries.js';
9
+ import { getRandomPlaceholderImages, searchPexelsForProduct } from '../../lib/image-library.js';
9
10
  import { normalizeProductId, normalizeVariantId, normalizeTemplateName, formatProduct, isValidPrice, formatUserErrors, hasGraphQLErrors, extractGraphQLErrors } from './utils.js';
10
11
  /**
11
12
  * Product Service
@@ -34,9 +35,12 @@ export class ProductService {
34
35
  /**
35
36
  * Create a new product from scratch
36
37
  *
38
+ * @param credentials Shopify credentials
39
+ * @param input Product creation input
40
+ * @param media Optional media/images to add (null = no images, undefined/array = add images)
37
41
  * @returns Formatted result with created product data
38
42
  */
39
- static async createProduct(credentials, input) {
43
+ static async createProduct(credentials, input, media) {
40
44
  // Title is required
41
45
  if (!input.title || input.title.trim().length === 0) {
42
46
  return {
@@ -69,17 +73,15 @@ export class ProductService {
69
73
  }
70
74
  // Note: Shopify's ProductInput does not support variants field
71
75
  // Variant price/SKU will be updated after product creation if provided
72
- // Default product images (automatically added to all products)
73
- const defaultMedia = [
74
- { originalSource: "https://uyduvd6qqsmnpi4h.public.blob.vercel-storage.com/1.png", alt: "Product Image 1", mediaContentType: "IMAGE" },
75
- { originalSource: "https://uyduvd6qqsmnpi4h.public.blob.vercel-storage.com/2.png", alt: "Product Image 2", mediaContentType: "IMAGE" },
76
- { originalSource: "https://uyduvd6qqsmnpi4h.public.blob.vercel-storage.com/3.png", alt: "Product Image 3", mediaContentType: "IMAGE" },
77
- { originalSource: "https://uyduvd6qqsmnpi4h.public.blob.vercel-storage.com/4.png", alt: "Product Image 4", mediaContentType: "IMAGE" },
78
- { originalSource: "https://uyduvd6qqsmnpi4h.public.blob.vercel-storage.com/5.png", alt: "Product Image 5", mediaContentType: "IMAGE" },
79
- { originalSource: "https://uyduvd6qqsmnpi4h.public.blob.vercel-storage.com/6.png", alt: "Product Image 6", mediaContentType: "IMAGE" }
80
- ];
81
- // Execute mutation with default images
82
- const response = await shopifyGraphQL(credentials, PRODUCT_CREATE, { input: productInput, media: defaultMedia });
76
+ // Use provided media (smart images from command layer) or no images if null
77
+ // media parameter: undefined/array = add images, null = no images
78
+ const mediaToAdd = media !== null ? media : undefined;
79
+ // Execute mutation with optional media
80
+ const variables = { input: productInput };
81
+ if (mediaToAdd && mediaToAdd.length > 0) {
82
+ variables.media = mediaToAdd;
83
+ }
84
+ const response = await shopifyGraphQL(credentials, PRODUCT_CREATE, variables);
83
85
  if (hasGraphQLErrors(response)) {
84
86
  return {
85
87
  success: false,
@@ -286,6 +288,112 @@ export class ProductService {
286
288
  }
287
289
  };
288
290
  }
291
+ /**
292
+ * Update product images
293
+ * Adds new images to the product using smart, context-aware image selection
294
+ *
295
+ * Strategy:
296
+ * 1. If --images provided: Use custom URLs
297
+ * 2. If --search provided: Search Pexels with custom query
298
+ * 3. If --random provided: Generate random placeholders
299
+ * 4. Default: Use product title to search for relevant images
300
+ *
301
+ * Note: Shopify productUpdate with media parameter ADDS images, doesn't replace existing ones
302
+ *
303
+ * @returns Formatted result with updated product and media
304
+ */
305
+ static async updateImages(credentials, input) {
306
+ const { gid } = normalizeProductId(input.id);
307
+ // Build media array based on input
308
+ let mediaInputs = [];
309
+ if (input.images && input.images.length > 0) {
310
+ // Option 1: Use provided custom images
311
+ mediaInputs = input.images.map((img, index) => {
312
+ if (typeof img === 'string') {
313
+ return {
314
+ originalSource: img,
315
+ alt: `Product Image ${index + 1}`,
316
+ mediaContentType: 'IMAGE'
317
+ };
318
+ }
319
+ else {
320
+ return {
321
+ originalSource: img.url,
322
+ alt: img.alt || `Product Image ${index + 1}`,
323
+ mediaContentType: 'IMAGE'
324
+ };
325
+ }
326
+ });
327
+ console.error(`ℹ️ Adding ${mediaInputs.length} custom image(s)`);
328
+ }
329
+ else if (input.search || input.random) {
330
+ // Option 2: Generate images (either with search query or random)
331
+ const count = input.random || 6;
332
+ let images;
333
+ if (input.search) {
334
+ // Custom search query provided
335
+ if (input.source === 'picsum') {
336
+ images = getRandomPlaceholderImages(count);
337
+ }
338
+ else {
339
+ // Default to Pexels for search
340
+ images = await searchPexelsForProduct(input.search, count);
341
+ }
342
+ }
343
+ else {
344
+ // Just random, no search
345
+ images = getRandomPlaceholderImages(count);
346
+ }
347
+ mediaInputs = images.map(img => ({
348
+ originalSource: img.url,
349
+ alt: img.alt || 'Product Image',
350
+ mediaContentType: 'IMAGE'
351
+ }));
352
+ }
353
+ else {
354
+ return {
355
+ success: false,
356
+ error: 'Either --images, --search, or --random must be provided'
357
+ };
358
+ }
359
+ if (mediaInputs.length === 0) {
360
+ return {
361
+ success: false,
362
+ error: 'No images to add. Please provide valid image URLs or search parameters.'
363
+ };
364
+ }
365
+ // Execute mutation to add images
366
+ const response = await shopifyGraphQL(credentials, UPDATE_PRODUCT_MEDIA, {
367
+ product: { id: gid },
368
+ media: mediaInputs
369
+ });
370
+ if (hasGraphQLErrors(response)) {
371
+ return {
372
+ success: false,
373
+ error: `GraphQL error: ${extractGraphQLErrors(response)}`
374
+ };
375
+ }
376
+ const { product, userErrors } = response.data.productUpdate;
377
+ if (userErrors && userErrors.length > 0) {
378
+ return {
379
+ success: false,
380
+ error: formatUserErrors(userErrors)
381
+ };
382
+ }
383
+ if (!product) {
384
+ return {
385
+ success: false,
386
+ error: 'Product update failed'
387
+ };
388
+ }
389
+ return {
390
+ success: true,
391
+ data: {
392
+ product,
393
+ imagesAdded: mediaInputs.length
394
+ }
395
+ };
396
+ }
289
397
  /**
290
398
  * Set product metafield value
291
399
  *
@@ -829,5 +937,175 @@ export class ProductService {
829
937
  }
830
938
  };
831
939
  }
940
+ /**
941
+ * Add tags to product (non-destructive)
942
+ * Uses tagsAdd mutation
943
+ *
944
+ * IMPORTANT:
945
+ * - Preserves existing tags
946
+ * - Duplicate tags are handled by Shopify
947
+ * - No approval required (non-destructive)
948
+ *
949
+ * @returns Formatted result with updated product tags
950
+ */
951
+ static async addTags(credentials, input) {
952
+ try {
953
+ const { gid } = normalizeProductId(input.id);
954
+ const response = await shopifyGraphQL(credentials, TAGS_ADD, {
955
+ id: gid,
956
+ tags: input.tags
957
+ });
958
+ if (hasGraphQLErrors(response)) {
959
+ return {
960
+ success: false,
961
+ error: `GraphQL error: ${extractGraphQLErrors(response)}`
962
+ };
963
+ }
964
+ const mutation = response.data?.tagsAdd;
965
+ if (mutation && mutation.userErrors && mutation.userErrors.length > 0) {
966
+ return {
967
+ success: false,
968
+ error: formatUserErrors(mutation.userErrors)
969
+ };
970
+ }
971
+ const product = mutation?.node;
972
+ if (!product) {
973
+ return {
974
+ success: false,
975
+ error: 'No product returned from mutation'
976
+ };
977
+ }
978
+ return {
979
+ success: true,
980
+ data: {
981
+ product: {
982
+ id: product.id,
983
+ title: product.title,
984
+ tags: product.tags || []
985
+ }
986
+ }
987
+ };
988
+ }
989
+ catch (error) {
990
+ return {
991
+ success: false,
992
+ error: error instanceof Error ? error.message : 'Unknown error'
993
+ };
994
+ }
995
+ }
996
+ /**
997
+ * Remove tags from product (destructive)
998
+ * Uses tagsRemove mutation
999
+ *
1000
+ * IMPORTANT:
1001
+ * - Removes specified tags from product
1002
+ * - Requires approval (destructive operation)
1003
+ * - Silently ignores tags that don't exist on product
1004
+ *
1005
+ * @returns Formatted result with updated product tags
1006
+ */
1007
+ static async removeTags(credentials, input) {
1008
+ try {
1009
+ const { gid } = normalizeProductId(input.id);
1010
+ const response = await shopifyGraphQL(credentials, TAGS_REMOVE, {
1011
+ id: gid,
1012
+ tags: input.tags
1013
+ });
1014
+ if (hasGraphQLErrors(response)) {
1015
+ return {
1016
+ success: false,
1017
+ error: `GraphQL error: ${extractGraphQLErrors(response)}`
1018
+ };
1019
+ }
1020
+ const mutation = response.data?.tagsRemove;
1021
+ if (mutation && mutation.userErrors && mutation.userErrors.length > 0) {
1022
+ return {
1023
+ success: false,
1024
+ error: formatUserErrors(mutation.userErrors)
1025
+ };
1026
+ }
1027
+ const product = mutation?.node;
1028
+ if (!product) {
1029
+ return {
1030
+ success: false,
1031
+ error: 'No product returned from mutation'
1032
+ };
1033
+ }
1034
+ return {
1035
+ success: true,
1036
+ data: {
1037
+ product: {
1038
+ id: product.id,
1039
+ title: product.title,
1040
+ tags: product.tags || []
1041
+ }
1042
+ }
1043
+ };
1044
+ }
1045
+ catch (error) {
1046
+ return {
1047
+ success: false,
1048
+ error: error instanceof Error ? error.message : 'Unknown error'
1049
+ };
1050
+ }
1051
+ }
1052
+ /**
1053
+ * Set/replace all product tags (destructive)
1054
+ * Uses productUpdate mutation
1055
+ *
1056
+ * IMPORTANT:
1057
+ * - REPLACES all existing tags with new tags
1058
+ * - Requires approval (destructive operation)
1059
+ * - Pass empty array to remove all tags
1060
+ *
1061
+ * @returns Formatted result with updated product tags
1062
+ */
1063
+ static async setTags(credentials, input) {
1064
+ try {
1065
+ const { gid } = normalizeProductId(input.id);
1066
+ const response = await shopifyGraphQL(credentials, UPDATE_PRODUCT, {
1067
+ input: {
1068
+ id: gid,
1069
+ tags: input.tags
1070
+ }
1071
+ });
1072
+ if (hasGraphQLErrors(response)) {
1073
+ return {
1074
+ success: false,
1075
+ error: `GraphQL error: ${extractGraphQLErrors(response)}`
1076
+ };
1077
+ }
1078
+ const mutation = response.data?.productUpdate;
1079
+ if (mutation && mutation.userErrors && mutation.userErrors.length > 0) {
1080
+ return {
1081
+ success: false,
1082
+ error: formatUserErrors(mutation.userErrors)
1083
+ };
1084
+ }
1085
+ const product = mutation?.product;
1086
+ if (!product) {
1087
+ return {
1088
+ success: false,
1089
+ error: 'No product returned from update'
1090
+ };
1091
+ }
1092
+ return {
1093
+ success: true,
1094
+ data: {
1095
+ product: {
1096
+ id: product.id,
1097
+ title: product.title,
1098
+ tags: product.tags || []
1099
+ }
1100
+ }
1101
+ };
1102
+ }
1103
+ catch (error) {
1104
+ return {
1105
+ success: false,
1106
+ error: error instanceof Error ? error.message : 'Unknown error'
1107
+ };
1108
+ }
1109
+ }
832
1110
  }
833
1111
  //# sourceMappingURL=service.js.map