shop-cli 0.1.0 → 0.1.2
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/dist/cli/approvalRequired.d.ts +30 -0
- package/dist/cli/approvalRequired.js +87 -0
- package/dist/cli/errors.d.ts +4 -1
- package/dist/cli/errors.js +3 -1
- package/dist/cli/gid.d.ts +1 -1
- package/dist/cli/help/registry.js +1013 -221
- package/dist/cli/help/render.d.ts +1 -0
- package/dist/cli/help/render.js +47 -0
- package/dist/cli/parse-command.d.ts +18 -0
- package/dist/cli/parse-command.js +109 -0
- package/dist/cli/router.js +3 -0
- package/dist/cli/suggest.d.ts +5 -0
- package/dist/cli/suggest.js +88 -0
- package/dist/cli/verbs/_shared.d.ts +1 -1
- package/dist/cli/verbs/_shared.js +4 -3
- package/dist/cli/verbs/catalogs.js +1 -1
- package/dist/cli/verbs/checkout-branding.js +2 -2
- package/dist/cli/verbs/collections.js +147 -12
- package/dist/cli/verbs/companies.js +2 -2
- package/dist/cli/verbs/company-contacts.js +8 -4
- package/dist/cli/verbs/company-locations.js +1 -1
- package/dist/cli/verbs/customers.js +156 -19
- package/dist/cli/verbs/discounts-automatic.js +36 -10
- package/dist/cli/verbs/discounts-code.js +27 -10
- package/dist/cli/verbs/draft-orders.js +49 -3
- package/dist/cli/verbs/files.js +171 -55
- package/dist/cli/verbs/fulfillment-orders.js +19 -4
- package/dist/cli/verbs/fulfillments.js +8 -2
- package/dist/cli/verbs/graphql.js +2 -0
- package/dist/cli/verbs/inventory.js +7 -1
- package/dist/cli/verbs/marketing-activities.js +1 -1
- package/dist/cli/verbs/markets.js +37 -4
- package/dist/cli/verbs/metaobjects.js +10 -1
- package/dist/cli/verbs/orders.js +80 -8
- package/dist/cli/verbs/product-variants.js +67 -16
- package/dist/cli/verbs/products.js +1263 -211
- package/dist/cli/verbs/selling-plan-groups.js +32 -10
- package/dist/cli/verbs/subscription-contracts.js +1 -0
- package/dist/cli/verbs/themes.js +18 -0
- package/dist/cli/verbs/url-redirects.js +64 -6
- package/dist/cli/workflows/files/stagedUploads.d.ts +3 -3
- package/dist/cli/workflows/files/stagedUploads.js +71 -19
- package/dist/cli/workflows/files/stdinFile.d.ts +7 -0
- package/dist/cli/workflows/files/stdinFile.js +65 -0
- package/dist/cli/workflows/files/urlDownloads.d.ts +14 -0
- package/dist/cli/workflows/files/urlDownloads.js +114 -0
- package/dist/cli/workflows/files/waitForReady.d.ts +20 -0
- package/dist/cli/workflows/files/waitForReady.js +114 -0
- package/dist/cli.js +115 -29
- package/package.json +3 -2
|
@@ -23,6 +23,7 @@ __export(products_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(products_exports);
|
|
24
24
|
var import_errors = require("../errors");
|
|
25
25
|
var import_gid = require("../gid");
|
|
26
|
+
var import_render = require("../help/render");
|
|
26
27
|
var import_input = require("../input");
|
|
27
28
|
var import_output = require("../output");
|
|
28
29
|
var import_computedFields = require("../output/computedFields");
|
|
@@ -30,18 +31,48 @@ var import_router = require("../router");
|
|
|
30
31
|
var import_select = require("../selection/select");
|
|
31
32
|
var import_userErrors = require("../userErrors");
|
|
32
33
|
var import_stagedUploads = require("../workflows/files/stagedUploads");
|
|
34
|
+
var import_waitForReady = require("../workflows/files/waitForReady");
|
|
35
|
+
var import_stdinFile = require("../workflows/files/stdinFile");
|
|
33
36
|
var import_metafieldsUpsert = require("../workflows/products/metafieldsUpsert");
|
|
34
37
|
var import_publishablePublish = require("../workflows/products/publishablePublish");
|
|
35
38
|
var import_resolvePublicationId = require("../workflows/publications/resolvePublicationId");
|
|
36
39
|
var import_shared = require("./_shared");
|
|
37
|
-
const
|
|
40
|
+
const requireProductIdForSubverb = (args) => {
|
|
41
|
+
if (args.id !== void 0) {
|
|
42
|
+
throw new import_errors.CliError("Unknown flag --id, did you mean --product-id?", 2);
|
|
43
|
+
}
|
|
44
|
+
return (0, import_shared.requireGidFlag)(args["product-id"], "--product-id", "Product");
|
|
45
|
+
};
|
|
46
|
+
const requireProductIdForRootVerb = (args) => {
|
|
47
|
+
const rawId = args.id;
|
|
48
|
+
const rawProductId = args["product-id"];
|
|
49
|
+
const hasId = typeof rawId === "string" && rawId.length > 0;
|
|
50
|
+
const hasProductId = typeof rawProductId === "string" && rawProductId.length > 0;
|
|
51
|
+
if (!hasId && !hasProductId) {
|
|
52
|
+
throw new import_errors.CliError("Missing --id", 2);
|
|
53
|
+
}
|
|
54
|
+
if (hasId && hasProductId) {
|
|
55
|
+
const a = (0, import_gid.coerceGid)(rawId, "Product");
|
|
56
|
+
const b = (0, import_gid.coerceGid)(rawProductId, "Product");
|
|
57
|
+
if (a !== b) throw new import_errors.CliError("Conflicting --id and --product-id", 2);
|
|
58
|
+
return a;
|
|
59
|
+
}
|
|
60
|
+
if (hasProductId) {
|
|
61
|
+
return (0, import_shared.requireGidFlag)(rawProductId, "--product-id", "Product");
|
|
62
|
+
}
|
|
63
|
+
return (0, import_shared.requireId)(rawId, "Product");
|
|
64
|
+
};
|
|
65
|
+
const productMediaSummarySelection = {
|
|
38
66
|
id: true,
|
|
39
67
|
mediaContentType: true,
|
|
40
68
|
status: true,
|
|
41
69
|
alt: true,
|
|
42
|
-
preview: { status: true, image: { url: true } }
|
|
70
|
+
preview: { status: true, image: { url: true } }
|
|
71
|
+
};
|
|
72
|
+
const productMediaSelection = {
|
|
43
73
|
mediaErrors: { code: true, message: true },
|
|
44
|
-
mediaWarnings: { code: true, message: true }
|
|
74
|
+
mediaWarnings: { code: true, message: true },
|
|
75
|
+
...productMediaSummarySelection
|
|
45
76
|
};
|
|
46
77
|
const productSummarySelection = {
|
|
47
78
|
id: true,
|
|
@@ -63,18 +94,96 @@ const productFullSelectionForGet = {
|
|
|
63
94
|
...productFullSelection,
|
|
64
95
|
...import_computedFields.computedPublicationsSelection
|
|
65
96
|
};
|
|
97
|
+
const productTagsSummarySelection = {
|
|
98
|
+
...productSummarySelection,
|
|
99
|
+
tags: true
|
|
100
|
+
};
|
|
101
|
+
const productOptionSelection = {
|
|
102
|
+
id: true,
|
|
103
|
+
name: true,
|
|
104
|
+
position: true,
|
|
105
|
+
values: true
|
|
106
|
+
};
|
|
107
|
+
const productOptionListSummarySelection = {
|
|
108
|
+
id: true,
|
|
109
|
+
name: true,
|
|
110
|
+
position: true,
|
|
111
|
+
values: true
|
|
112
|
+
};
|
|
113
|
+
const productOptionListFullSelection = {
|
|
114
|
+
...productOptionListSummarySelection,
|
|
115
|
+
optionValues: { id: true, name: true, hasVariants: true }
|
|
116
|
+
};
|
|
117
|
+
const getProductOptionListSelection = (view) => {
|
|
118
|
+
if (view === "ids") return { id: true };
|
|
119
|
+
if (view === "full") return productOptionListFullSelection;
|
|
120
|
+
if (view === "raw") return {};
|
|
121
|
+
return productOptionListSummarySelection;
|
|
122
|
+
};
|
|
123
|
+
const productOptionsSummarySelection = {
|
|
124
|
+
...productSummarySelection,
|
|
125
|
+
options: {
|
|
126
|
+
__args: { first: 100 },
|
|
127
|
+
...productOptionSelection
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const productOptionsFullSelection = {
|
|
131
|
+
...productFullSelection,
|
|
132
|
+
options: {
|
|
133
|
+
__args: { first: 100 },
|
|
134
|
+
...productOptionSelection
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const productVariantSummarySelection = {
|
|
138
|
+
id: true,
|
|
139
|
+
displayName: true,
|
|
140
|
+
sku: true,
|
|
141
|
+
price: true,
|
|
142
|
+
availableForSale: true
|
|
143
|
+
};
|
|
144
|
+
const productVariantFullSelection = {
|
|
145
|
+
...productVariantSummarySelection,
|
|
146
|
+
barcode: true,
|
|
147
|
+
compareAtPrice: true,
|
|
148
|
+
inventoryQuantity: true,
|
|
149
|
+
product: { id: true, title: true },
|
|
150
|
+
inventoryItem: { id: true }
|
|
151
|
+
};
|
|
152
|
+
const getProductVariantSelection = (view) => {
|
|
153
|
+
if (view === "ids") return { id: true };
|
|
154
|
+
if (view === "full") return productVariantFullSelection;
|
|
155
|
+
if (view === "raw") return {};
|
|
156
|
+
return productVariantSummarySelection;
|
|
157
|
+
};
|
|
66
158
|
const getProductSelection = (view) => {
|
|
67
159
|
if (view === "ids") return { id: true };
|
|
68
160
|
if (view === "full") return productFullSelection;
|
|
69
161
|
if (view === "raw") return {};
|
|
70
162
|
return productSummarySelection;
|
|
71
163
|
};
|
|
164
|
+
const getProductSelectionForTags = (view) => {
|
|
165
|
+
if (view === "ids") return { id: true };
|
|
166
|
+
if (view === "full") return productFullSelection;
|
|
167
|
+
if (view === "raw") return {};
|
|
168
|
+
return productTagsSummarySelection;
|
|
169
|
+
};
|
|
170
|
+
const getProductSelectionForOptions = (view) => {
|
|
171
|
+
if (view === "ids") return { id: true };
|
|
172
|
+
if (view === "full") return productOptionsFullSelection;
|
|
173
|
+
if (view === "raw") return {};
|
|
174
|
+
return productOptionsSummarySelection;
|
|
175
|
+
};
|
|
72
176
|
const getProductSelectionForGet = (view) => {
|
|
73
177
|
if (view === "ids") return { id: true };
|
|
74
178
|
if (view === "full") return productFullSelectionForGet;
|
|
75
179
|
if (view === "raw") return {};
|
|
76
180
|
return productSummarySelectionForGet;
|
|
77
181
|
};
|
|
182
|
+
const getProductMediaSelection = (view) => {
|
|
183
|
+
if (view === "ids") return { id: true };
|
|
184
|
+
if (view === "summary") return productMediaSummarySelection;
|
|
185
|
+
return productMediaSelection;
|
|
186
|
+
};
|
|
78
187
|
const parseTags = (tags) => {
|
|
79
188
|
if (!tags) throw new import_errors.CliError("Missing --tags", 2);
|
|
80
189
|
const parts = tags.split(",").map((t) => t.trim()).filter(Boolean);
|
|
@@ -85,7 +194,39 @@ const normalizeMediaContentType = (value) => {
|
|
|
85
194
|
if (!value) return "IMAGE";
|
|
86
195
|
const v = value.toUpperCase();
|
|
87
196
|
if (v === "IMAGE" || v === "VIDEO" || v === "MODEL_3D" || v === "EXTERNAL_VIDEO") return v;
|
|
88
|
-
throw new import_errors.CliError("--media-type must be IMAGE|VIDEO|MODEL_3D|EXTERNAL_VIDEO", 2);
|
|
197
|
+
throw new import_errors.CliError("--media-content-type/--media-type must be IMAGE|VIDEO|MODEL_3D|EXTERNAL_VIDEO", 2);
|
|
198
|
+
};
|
|
199
|
+
const parsePositiveIntFlag = ({
|
|
200
|
+
value,
|
|
201
|
+
flag
|
|
202
|
+
}) => {
|
|
203
|
+
if (value === void 0) return void 0;
|
|
204
|
+
if (typeof value !== "string") throw new import_errors.CliError(`Invalid ${flag} value`, 2);
|
|
205
|
+
const trimmed = value.trim();
|
|
206
|
+
if (!trimmed) throw new import_errors.CliError(`Invalid ${flag} value`, 2);
|
|
207
|
+
const n = Number(trimmed);
|
|
208
|
+
if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
|
|
209
|
+
throw new import_errors.CliError(`${flag} must be a positive integer`, 2);
|
|
210
|
+
}
|
|
211
|
+
return n;
|
|
212
|
+
};
|
|
213
|
+
const getTopProductMediaIds = async ({
|
|
214
|
+
ctx,
|
|
215
|
+
productId,
|
|
216
|
+
first = 250
|
|
217
|
+
}) => {
|
|
218
|
+
const result = await (0, import_router.runQuery)(ctx, {
|
|
219
|
+
product: {
|
|
220
|
+
__args: { id: productId },
|
|
221
|
+
media: {
|
|
222
|
+
__args: { first, reverse: true, sortKey: "POSITION" },
|
|
223
|
+
nodes: { id: true }
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
if (result === void 0) return [];
|
|
228
|
+
const nodes = result.product?.media?.nodes ?? [];
|
|
229
|
+
return nodes.map((n) => typeof n?.id === "string" ? n.id : void 0).filter((id) => typeof id === "string" && id.trim() !== "");
|
|
89
230
|
};
|
|
90
231
|
const normalizeMediaId = (value) => {
|
|
91
232
|
const raw = value.trim();
|
|
@@ -108,11 +249,143 @@ const stagedResourceToMediaType = (resource) => {
|
|
|
108
249
|
if (resource === "MODEL_3D") return "MODEL_3D";
|
|
109
250
|
throw new import_errors.CliError("Only IMAGE|VIDEO|MODEL_3D can be uploaded as product media", 2);
|
|
110
251
|
};
|
|
252
|
+
const parseVariantOptionValues = (value) => {
|
|
253
|
+
if (value === void 0 || value === null) return [];
|
|
254
|
+
const raw = Array.isArray(value) ? value : [value];
|
|
255
|
+
const optionValues = [];
|
|
256
|
+
for (const entry of raw) {
|
|
257
|
+
if (typeof entry !== "string") throw new import_errors.CliError("--variant-option must be a string", 2);
|
|
258
|
+
const trimmed = entry.trim();
|
|
259
|
+
if (!trimmed) continue;
|
|
260
|
+
const eq = trimmed.indexOf("=");
|
|
261
|
+
if (eq <= 0 || eq === trimmed.length - 1) {
|
|
262
|
+
throw new import_errors.CliError(`--variant-option must be in the form OptionName=Value. Got: ${entry}`, 2);
|
|
263
|
+
}
|
|
264
|
+
const optionName = trimmed.slice(0, eq).trim();
|
|
265
|
+
const name = trimmed.slice(eq + 1).trim();
|
|
266
|
+
if (!optionName || !name) {
|
|
267
|
+
throw new import_errors.CliError(`--variant-option must be in the form OptionName=Value. Got: ${entry}`, 2);
|
|
268
|
+
}
|
|
269
|
+
optionValues.push({ optionName, name });
|
|
270
|
+
}
|
|
271
|
+
return optionValues;
|
|
272
|
+
};
|
|
273
|
+
const parseRepeatableStrings = (value, flag, { allowEmpty = false } = {}) => {
|
|
274
|
+
if (value === void 0 || value === null) {
|
|
275
|
+
if (allowEmpty) return [];
|
|
276
|
+
throw new import_errors.CliError(`Missing ${flag}`, 2);
|
|
277
|
+
}
|
|
278
|
+
const raw = Array.isArray(value) ? value : [value];
|
|
279
|
+
const out = [];
|
|
280
|
+
for (const entry of raw) {
|
|
281
|
+
if (typeof entry !== "string") throw new import_errors.CliError(`${flag} must be a string (repeatable)`, 2);
|
|
282
|
+
const trimmed = entry.trim();
|
|
283
|
+
if (!trimmed) throw new import_errors.CliError(`${flag} cannot be empty`, 2);
|
|
284
|
+
out.push(trimmed);
|
|
285
|
+
}
|
|
286
|
+
if (out.length === 0) {
|
|
287
|
+
if (allowEmpty) return [];
|
|
288
|
+
throw new import_errors.CliError(`Missing ${flag}`, 2);
|
|
289
|
+
}
|
|
290
|
+
return out;
|
|
291
|
+
};
|
|
292
|
+
const parseOptionSpec = (value, flag) => {
|
|
293
|
+
const trimmed = value.trim();
|
|
294
|
+
const eq = trimmed.indexOf("=");
|
|
295
|
+
if (eq <= 0 || eq === trimmed.length - 1) {
|
|
296
|
+
throw new import_errors.CliError(`${flag} must be in the form Name=Value1,Value2,... Got: ${value}`, 2);
|
|
297
|
+
}
|
|
298
|
+
const name = trimmed.slice(0, eq).trim();
|
|
299
|
+
const valuesRaw = trimmed.slice(eq + 1).trim();
|
|
300
|
+
if (!name || !valuesRaw) {
|
|
301
|
+
throw new import_errors.CliError(`${flag} must be in the form Name=Value1,Value2,... Got: ${value}`, 2);
|
|
302
|
+
}
|
|
303
|
+
const valueNames = valuesRaw.split(",").map((v) => v.trim()).filter(Boolean);
|
|
304
|
+
if (valueNames.length === 0) {
|
|
305
|
+
throw new import_errors.CliError(`${flag} must include at least one value. Got: ${value}`, 2);
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
name,
|
|
309
|
+
values: valueNames.map((v) => ({ name: v }))
|
|
310
|
+
};
|
|
311
|
+
};
|
|
312
|
+
const parseFromTo = (value, flag) => {
|
|
313
|
+
const trimmed = value.trim();
|
|
314
|
+
const eq = trimmed.indexOf("=");
|
|
315
|
+
if (eq <= 0 || eq === trimmed.length - 1) {
|
|
316
|
+
throw new import_errors.CliError(`${flag} must be in the form From=To. Got: ${value}`, 2);
|
|
317
|
+
}
|
|
318
|
+
const from = trimmed.slice(0, eq).trim();
|
|
319
|
+
const to = trimmed.slice(eq + 1).trim();
|
|
320
|
+
if (!from || !to) {
|
|
321
|
+
throw new import_errors.CliError(`${flag} must be in the form From=To. Got: ${value}`, 2);
|
|
322
|
+
}
|
|
323
|
+
return { from, to };
|
|
324
|
+
};
|
|
325
|
+
const looksLikeGidOrNumericId = (value) => /^gid:\/\//i.test(value) || /^\d+$/.test(value);
|
|
326
|
+
const normalizeProductOptionCreateVariantStrategy = (value) => {
|
|
327
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
328
|
+
if (typeof value !== "string") throw new import_errors.CliError("--variant-strategy must be a string", 2);
|
|
329
|
+
const v = value.trim().toUpperCase();
|
|
330
|
+
if (v === "LEAVE_AS_IS" || v === "CREATE") return v;
|
|
331
|
+
throw new import_errors.CliError("--variant-strategy must be LEAVE_AS_IS|CREATE", 2);
|
|
332
|
+
};
|
|
333
|
+
const normalizeProductOptionUpdateVariantStrategy = (value) => {
|
|
334
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
335
|
+
if (typeof value !== "string") throw new import_errors.CliError("--variant-strategy must be a string", 2);
|
|
336
|
+
const v = value.trim().toUpperCase();
|
|
337
|
+
if (v === "LEAVE_AS_IS" || v === "MANAGE") return v;
|
|
338
|
+
throw new import_errors.CliError("--variant-strategy must be LEAVE_AS_IS|MANAGE", 2);
|
|
339
|
+
};
|
|
340
|
+
const normalizeProductOptionDeleteStrategy = (value) => {
|
|
341
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
342
|
+
if (typeof value !== "string") throw new import_errors.CliError("--strategy must be a string", 2);
|
|
343
|
+
const v = value.trim().toUpperCase();
|
|
344
|
+
if (v === "DEFAULT" || v === "NON_DESTRUCTIVE" || v === "POSITION") return v;
|
|
345
|
+
throw new import_errors.CliError("--strategy must be DEFAULT|NON_DESTRUCTIVE|POSITION", 2);
|
|
346
|
+
};
|
|
347
|
+
const productOptionResolveSelection = {
|
|
348
|
+
id: true,
|
|
349
|
+
name: true,
|
|
350
|
+
position: true,
|
|
351
|
+
values: true,
|
|
352
|
+
optionValues: { id: true, name: true }
|
|
353
|
+
};
|
|
354
|
+
const fetchProductOptionsForResolution = async ({ ctx, productId }) => {
|
|
355
|
+
const result = await (0, import_router.runQuery)(ctx, {
|
|
356
|
+
product: { __args: { id: productId }, options: productOptionResolveSelection }
|
|
357
|
+
});
|
|
358
|
+
if (result === void 0) return [];
|
|
359
|
+
return result.product?.options ?? [];
|
|
360
|
+
};
|
|
361
|
+
const resolveSingleOptionByName = (options, name) => {
|
|
362
|
+
const matches = options.filter((o) => typeof o?.name === "string" && o.name === name);
|
|
363
|
+
if (matches.length === 0) return void 0;
|
|
364
|
+
if (matches.length > 1) {
|
|
365
|
+
throw new import_errors.CliError(`Multiple product options named "${name}" exist. Use --option-id instead.`, 2);
|
|
366
|
+
}
|
|
367
|
+
return matches[0];
|
|
368
|
+
};
|
|
369
|
+
const parseInventoryPolicy = (value) => {
|
|
370
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
371
|
+
if (typeof value !== "string") throw new import_errors.CliError("--inventory-policy must be a string", 2);
|
|
372
|
+
const normalized = value.trim().toUpperCase();
|
|
373
|
+
if (normalized === "DENY" || normalized === "CONTINUE") return normalized;
|
|
374
|
+
throw new import_errors.CliError(`--inventory-policy must be DENY|CONTINUE. Got: ${value}`, 2);
|
|
375
|
+
};
|
|
111
376
|
const runProducts = async ({
|
|
112
377
|
ctx,
|
|
113
378
|
verb,
|
|
114
379
|
argv
|
|
115
380
|
}) => {
|
|
381
|
+
const groupHelpVerbs = /* @__PURE__ */ new Set(["variants", "options", "media"]);
|
|
382
|
+
if (groupHelpVerbs.has(verb)) {
|
|
383
|
+
const groupHelp = (0, import_render.renderVerbGroupHelp)("products", verb);
|
|
384
|
+
if (groupHelp) console.log(groupHelp);
|
|
385
|
+
if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) return;
|
|
386
|
+
throw new import_errors.CliError(`
|
|
387
|
+
Missing <verb> for "products ${verb}"`, 2);
|
|
388
|
+
}
|
|
116
389
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
117
390
|
console.log(
|
|
118
391
|
[
|
|
@@ -125,14 +398,14 @@ const runProducts = async ({
|
|
|
125
398
|
" tags|types|vendors",
|
|
126
399
|
" change-status|set",
|
|
127
400
|
" join-selling-plan-groups|leave-selling-plan-groups",
|
|
128
|
-
"
|
|
401
|
+
" options list|options create|options update|options delete|options reorder",
|
|
402
|
+
" variants list|variants create|variants update|variants delete|variants reorder",
|
|
129
403
|
" combined-listing-update",
|
|
130
404
|
" add-tags|remove-tags|set-price",
|
|
131
405
|
" publish|unpublish|publish-all",
|
|
132
406
|
" bundle-create|bundle-update",
|
|
133
407
|
" metafields upsert",
|
|
134
408
|
" media add|media upload|media list|media remove|media reorder|media update",
|
|
135
|
-
" create-media|update-media|delete-media|reorder-media",
|
|
136
409
|
"",
|
|
137
410
|
"Common output flags:",
|
|
138
411
|
" --view summary|ids|full|raw",
|
|
@@ -142,7 +415,266 @@ const runProducts = async ({
|
|
|
142
415
|
);
|
|
143
416
|
return;
|
|
144
417
|
}
|
|
145
|
-
if (verb === "
|
|
418
|
+
if (verb === "variants list") {
|
|
419
|
+
const args = (0, import_router.parseStandardArgs)({
|
|
420
|
+
argv,
|
|
421
|
+
extraOptions: { "product-id": { type: "string" } }
|
|
422
|
+
});
|
|
423
|
+
if (args.query) {
|
|
424
|
+
throw new import_errors.CliError(
|
|
425
|
+
"--query is not supported for `shop products variants list` (product-scoped variants). Use `shop product-variants list --query ...` for global variant search.",
|
|
426
|
+
2
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
const productId = requireProductIdForSubverb(args);
|
|
430
|
+
const first = (0, import_shared.parseFirst)(args.first);
|
|
431
|
+
const after = args.after;
|
|
432
|
+
const reverse = args.reverse;
|
|
433
|
+
const sortKey = args.sort;
|
|
434
|
+
const nodeSelection = (0, import_select.resolveSelection)({
|
|
435
|
+
typeName: "ProductVariant",
|
|
436
|
+
view: ctx.view,
|
|
437
|
+
baseSelection: getProductVariantSelection(ctx.view),
|
|
438
|
+
select: args.select,
|
|
439
|
+
selection: args.selection,
|
|
440
|
+
include: args.include,
|
|
441
|
+
ensureId: ctx.quiet,
|
|
442
|
+
defaultConnectionFirst: ctx.view === "all" ? 50 : 10
|
|
443
|
+
});
|
|
444
|
+
const result = await (0, import_router.runQuery)(ctx, {
|
|
445
|
+
product: {
|
|
446
|
+
__args: { id: productId },
|
|
447
|
+
variants: {
|
|
448
|
+
__args: { first, after, reverse, sortKey },
|
|
449
|
+
pageInfo: { hasNextPage: true, endCursor: true },
|
|
450
|
+
nodes: nodeSelection
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
if (result === void 0) return;
|
|
455
|
+
const connection = result.product?.variants;
|
|
456
|
+
if (!connection) throw new import_errors.CliError("Product not found", 2);
|
|
457
|
+
(0, import_output.printConnection)({
|
|
458
|
+
connection,
|
|
459
|
+
format: ctx.format,
|
|
460
|
+
quiet: ctx.quiet,
|
|
461
|
+
nextPageArgs: {
|
|
462
|
+
base: "shop products variants list",
|
|
463
|
+
first,
|
|
464
|
+
sort: typeof sortKey === "string" ? sortKey : void 0,
|
|
465
|
+
reverse: reverse === true,
|
|
466
|
+
extraFlags: [{ flag: "--product-id", value: productId }]
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (verb === "variants create") {
|
|
472
|
+
const args = (0, import_router.parseStandardArgs)({
|
|
473
|
+
argv,
|
|
474
|
+
extraOptions: {
|
|
475
|
+
"product-id": { type: "string" },
|
|
476
|
+
"variant-option": { type: "string", multiple: true },
|
|
477
|
+
sku: { type: "string" },
|
|
478
|
+
barcode: { type: "string" },
|
|
479
|
+
price: { type: "string" },
|
|
480
|
+
"compare-at-price": { type: "string" },
|
|
481
|
+
"inventory-policy": { type: "string" },
|
|
482
|
+
strategy: { type: "string" }
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
const productId = requireProductIdForSubverb(args);
|
|
486
|
+
const optionValues = parseVariantOptionValues(args["variant-option"]);
|
|
487
|
+
if (optionValues.length === 0) {
|
|
488
|
+
throw new import_errors.CliError("Missing --variant-option OptionName=Value (repeatable)", 2);
|
|
489
|
+
}
|
|
490
|
+
const sku = args.sku;
|
|
491
|
+
const barcode = args.barcode;
|
|
492
|
+
const price = args.price;
|
|
493
|
+
const compareAtPrice = args["compare-at-price"];
|
|
494
|
+
const inventoryPolicy = parseInventoryPolicy(args["inventory-policy"]);
|
|
495
|
+
const strategy = args.strategy;
|
|
496
|
+
if (strategy && !["DEFAULT", "PRESERVE_STANDALONE_VARIANT", "REMOVE_STANDALONE_VARIANT"].includes(
|
|
497
|
+
strategy.trim().toUpperCase()
|
|
498
|
+
)) {
|
|
499
|
+
throw new import_errors.CliError(
|
|
500
|
+
`--strategy must be DEFAULT|PRESERVE_STANDALONE_VARIANT|REMOVE_STANDALONE_VARIANT. Got: ${strategy}`,
|
|
501
|
+
2
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
const normalizedStrategy = strategy ? strategy.trim().toUpperCase() : void 0;
|
|
505
|
+
const variantSelection = (0, import_select.resolveSelection)({
|
|
506
|
+
typeName: "ProductVariant",
|
|
507
|
+
view: ctx.view,
|
|
508
|
+
baseSelection: getProductVariantSelection(ctx.view),
|
|
509
|
+
select: args.select,
|
|
510
|
+
selection: args.selection,
|
|
511
|
+
include: args.include,
|
|
512
|
+
ensureId: ctx.quiet,
|
|
513
|
+
defaultConnectionFirst: ctx.view === "all" ? 50 : 10
|
|
514
|
+
});
|
|
515
|
+
const variantInput = {
|
|
516
|
+
optionValues,
|
|
517
|
+
...barcode ? { barcode } : {},
|
|
518
|
+
...price ? { price } : {},
|
|
519
|
+
...compareAtPrice ? { compareAtPrice } : {},
|
|
520
|
+
...inventoryPolicy ? { inventoryPolicy } : {},
|
|
521
|
+
...sku ? { inventoryItem: { sku } } : {}
|
|
522
|
+
};
|
|
523
|
+
const result = await (0, import_router.runMutation)(ctx, {
|
|
524
|
+
productVariantsBulkCreate: {
|
|
525
|
+
__args: {
|
|
526
|
+
productId,
|
|
527
|
+
variants: [variantInput],
|
|
528
|
+
...normalizedStrategy ? { strategy: normalizedStrategy } : {}
|
|
529
|
+
},
|
|
530
|
+
userErrors: { field: true, message: true },
|
|
531
|
+
productVariants: variantSelection
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
if (result === void 0) return;
|
|
535
|
+
(0, import_userErrors.maybeFailOnUserErrors)({
|
|
536
|
+
payload: result.productVariantsBulkCreate,
|
|
537
|
+
failOnUserErrors: ctx.failOnUserErrors
|
|
538
|
+
});
|
|
539
|
+
const created = result.productVariantsBulkCreate?.productVariants?.[0];
|
|
540
|
+
(0, import_output.printNode)({ node: created, format: ctx.format, quiet: ctx.quiet });
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
if (verb === "variants update") {
|
|
544
|
+
const args = (0, import_router.parseStandardArgs)({
|
|
545
|
+
argv,
|
|
546
|
+
extraOptions: {
|
|
547
|
+
"product-id": { type: "string" },
|
|
548
|
+
"variant-id": { type: "string" },
|
|
549
|
+
"variant-option": { type: "string", multiple: true },
|
|
550
|
+
sku: { type: "string" },
|
|
551
|
+
barcode: { type: "string" },
|
|
552
|
+
price: { type: "string" },
|
|
553
|
+
"compare-at-price": { type: "string" },
|
|
554
|
+
"inventory-policy": { type: "string" },
|
|
555
|
+
"allow-partial-updates": { type: "boolean" }
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
if (args.id !== void 0) {
|
|
559
|
+
if (args["product-id"] !== void 0) {
|
|
560
|
+
throw new import_errors.CliError("Unknown flag --id, did you mean --variant-id?", 2);
|
|
561
|
+
}
|
|
562
|
+
;
|
|
563
|
+
args["product-id"] = args.id;
|
|
564
|
+
delete args.id;
|
|
565
|
+
}
|
|
566
|
+
const productId = requireProductIdForSubverb(args);
|
|
567
|
+
const variantId = (0, import_shared.requireId)(args["variant-id"], "ProductVariant", "--variant-id");
|
|
568
|
+
const optionValues = parseVariantOptionValues(args["variant-option"]);
|
|
569
|
+
const sku = args.sku;
|
|
570
|
+
const barcode = args.barcode;
|
|
571
|
+
const price = args.price;
|
|
572
|
+
const compareAtPrice = args["compare-at-price"];
|
|
573
|
+
const inventoryPolicy = parseInventoryPolicy(args["inventory-policy"]);
|
|
574
|
+
const allowPartialUpdates = args["allow-partial-updates"] === true;
|
|
575
|
+
const variantSelection = (0, import_select.resolveSelection)({
|
|
576
|
+
typeName: "ProductVariant",
|
|
577
|
+
view: ctx.view,
|
|
578
|
+
baseSelection: getProductVariantSelection(ctx.view),
|
|
579
|
+
select: args.select,
|
|
580
|
+
selection: args.selection,
|
|
581
|
+
include: args.include,
|
|
582
|
+
ensureId: ctx.quiet,
|
|
583
|
+
defaultConnectionFirst: ctx.view === "all" ? 50 : 10
|
|
584
|
+
});
|
|
585
|
+
const variantInput = {
|
|
586
|
+
id: variantId,
|
|
587
|
+
...optionValues.length ? { optionValues } : {},
|
|
588
|
+
...barcode ? { barcode } : {},
|
|
589
|
+
...price ? { price } : {},
|
|
590
|
+
...compareAtPrice ? { compareAtPrice } : {},
|
|
591
|
+
...inventoryPolicy ? { inventoryPolicy } : {},
|
|
592
|
+
...sku ? { inventoryItem: { sku } } : {}
|
|
593
|
+
};
|
|
594
|
+
const result = await (0, import_router.runMutation)(ctx, {
|
|
595
|
+
productVariantsBulkUpdate: {
|
|
596
|
+
__args: {
|
|
597
|
+
productId,
|
|
598
|
+
allowPartialUpdates,
|
|
599
|
+
variants: [variantInput]
|
|
600
|
+
},
|
|
601
|
+
userErrors: { field: true, message: true },
|
|
602
|
+
productVariants: variantSelection
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
if (result === void 0) return;
|
|
606
|
+
(0, import_userErrors.maybeFailOnUserErrors)({
|
|
607
|
+
payload: result.productVariantsBulkUpdate,
|
|
608
|
+
failOnUserErrors: ctx.failOnUserErrors
|
|
609
|
+
});
|
|
610
|
+
const updated = result.productVariantsBulkUpdate?.productVariants?.[0];
|
|
611
|
+
(0, import_output.printNode)({ node: updated, format: ctx.format, quiet: ctx.quiet });
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
if (verb === "variants delete") {
|
|
615
|
+
const args = (0, import_router.parseStandardArgs)({
|
|
616
|
+
argv,
|
|
617
|
+
extraOptions: {
|
|
618
|
+
"product-id": { type: "string" },
|
|
619
|
+
"variant-id": { type: "string" }
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
const productId = requireProductIdForSubverb(args);
|
|
623
|
+
const variantId = (0, import_shared.requireId)(args["variant-id"], "ProductVariant", "--variant-id");
|
|
624
|
+
const result = await (0, import_router.runMutation)(ctx, {
|
|
625
|
+
productVariantsBulkDelete: {
|
|
626
|
+
__args: { productId, variantsIds: [variantId] },
|
|
627
|
+
product: { id: true },
|
|
628
|
+
userErrors: { field: true, message: true }
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
if (result === void 0) return;
|
|
632
|
+
(0, import_userErrors.maybeFailOnUserErrors)({
|
|
633
|
+
payload: result.productVariantsBulkDelete,
|
|
634
|
+
failOnUserErrors: ctx.failOnUserErrors
|
|
635
|
+
});
|
|
636
|
+
const verify = await (0, import_router.runQuery)(ctx, {
|
|
637
|
+
nodes: {
|
|
638
|
+
__args: { ids: [variantId] },
|
|
639
|
+
id: true
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
if (verify === void 0) return;
|
|
643
|
+
const stillThere = verify.nodes?.[0] !== null && verify.nodes?.[0] !== void 0;
|
|
644
|
+
const deletedVariantId = stillThere ? void 0 : variantId;
|
|
645
|
+
if (ctx.quiet) return (0, import_output.printIds)([deletedVariantId]);
|
|
646
|
+
(0, import_output.printJson)({ productId, deletedVariantId }, ctx.format !== "raw");
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
if (verb === "variants reorder") {
|
|
650
|
+
const args = (0, import_router.parseStandardArgs)({
|
|
651
|
+
argv,
|
|
652
|
+
extraOptions: {
|
|
653
|
+
"product-id": { type: "string" },
|
|
654
|
+
"variant-id": { type: "string" },
|
|
655
|
+
position: { type: "string" }
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
const productId = requireProductIdForSubverb(args);
|
|
659
|
+
const variantId = (0, import_shared.requireId)(args["variant-id"], "ProductVariant", "--variant-id");
|
|
660
|
+
const position = (0, import_shared.parseIntFlag)("--position", args.position);
|
|
661
|
+
if (position <= 0) throw new import_errors.CliError("--position must be a positive integer (1-based)", 2);
|
|
662
|
+
const result = await (0, import_router.runMutation)(ctx, {
|
|
663
|
+
productVariantsBulkReorder: {
|
|
664
|
+
__args: { productId, positions: [{ id: variantId, position }] },
|
|
665
|
+
product: { id: true },
|
|
666
|
+
userErrors: { field: true, message: true }
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
if (result === void 0) return;
|
|
670
|
+
(0, import_userErrors.maybeFailOnUserErrors)({
|
|
671
|
+
payload: result.productVariantsBulkReorder,
|
|
672
|
+
failOnUserErrors: ctx.failOnUserErrors
|
|
673
|
+
});
|
|
674
|
+
if (ctx.quiet) return (0, import_output.printIds)([variantId]);
|
|
675
|
+
(0, import_output.printJson)({ productId, variantId, position }, ctx.format !== "raw");
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
146
678
|
if (verb === "by-handle") {
|
|
147
679
|
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: { handle: { type: "string" } } });
|
|
148
680
|
const handle = args.handle;
|
|
@@ -313,21 +845,29 @@ const runProducts = async ({
|
|
|
313
845
|
return;
|
|
314
846
|
}
|
|
315
847
|
if (verb === "change-status") {
|
|
316
|
-
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: {} });
|
|
317
|
-
const productId = (
|
|
848
|
+
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: { "product-id": { type: "string" } } });
|
|
849
|
+
const productId = requireProductIdForRootVerb(args);
|
|
318
850
|
const status = args.status;
|
|
319
851
|
if (!status) throw new import_errors.CliError("Missing --status (ACTIVE|DRAFT|ARCHIVED)", 2);
|
|
852
|
+
const selection = (0, import_select.resolveSelection)({
|
|
853
|
+
resource: "products",
|
|
854
|
+
view: ctx.view,
|
|
855
|
+
baseSelection: getProductSelection(ctx.view),
|
|
856
|
+
select: args.select,
|
|
857
|
+
selection: args.selection,
|
|
858
|
+
include: args.include,
|
|
859
|
+
ensureId: ctx.quiet
|
|
860
|
+
});
|
|
320
861
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
321
862
|
productChangeStatus: {
|
|
322
863
|
__args: { productId, status },
|
|
323
|
-
product:
|
|
864
|
+
product: selection,
|
|
324
865
|
userErrors: { field: true, message: true }
|
|
325
866
|
}
|
|
326
867
|
});
|
|
327
868
|
if (result === void 0) return;
|
|
328
869
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productChangeStatus, failOnUserErrors: ctx.failOnUserErrors });
|
|
329
|
-
|
|
330
|
-
(0, import_output.printJson)(result.productChangeStatus, ctx.format !== "raw");
|
|
870
|
+
(0, import_output.printNode)({ node: result.productChangeStatus?.product, format: ctx.format, quiet: ctx.quiet });
|
|
331
871
|
return;
|
|
332
872
|
}
|
|
333
873
|
if (verb === "set") {
|
|
@@ -381,192 +921,439 @@ const runProducts = async ({
|
|
|
381
921
|
return;
|
|
382
922
|
}
|
|
383
923
|
if (verb === "join-selling-plan-groups" || verb === "leave-selling-plan-groups") {
|
|
384
|
-
const args = (0, import_router.parseStandardArgs)({
|
|
385
|
-
|
|
924
|
+
const args = (0, import_router.parseStandardArgs)({
|
|
925
|
+
argv,
|
|
926
|
+
extraOptions: { "product-id": { type: "string" }, "group-ids": { type: "string", multiple: true } }
|
|
927
|
+
});
|
|
928
|
+
const id = requireProductIdForRootVerb(args);
|
|
386
929
|
const sellingPlanGroupIds = (0, import_shared.parseIds)(args["group-ids"], "SellingPlanGroup");
|
|
930
|
+
const selection = (0, import_select.resolveSelection)({
|
|
931
|
+
resource: "products",
|
|
932
|
+
view: ctx.view,
|
|
933
|
+
baseSelection: getProductSelection(ctx.view),
|
|
934
|
+
select: args.select,
|
|
935
|
+
selection: args.selection,
|
|
936
|
+
include: args.include,
|
|
937
|
+
ensureId: ctx.quiet
|
|
938
|
+
});
|
|
387
939
|
const mutation = verb === "join-selling-plan-groups" ? "productJoinSellingPlanGroups" : "productLeaveSellingPlanGroups";
|
|
388
940
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
389
941
|
[mutation]: {
|
|
390
942
|
__args: { id, sellingPlanGroupIds },
|
|
391
|
-
product:
|
|
943
|
+
product: selection,
|
|
392
944
|
userErrors: { field: true, message: true }
|
|
393
945
|
}
|
|
394
946
|
});
|
|
395
947
|
if (result === void 0) return;
|
|
396
948
|
const payload = result[mutation];
|
|
397
949
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload, failOnUserErrors: ctx.failOnUserErrors });
|
|
398
|
-
|
|
399
|
-
(0, import_output.printJson)(payload, ctx.format !== "raw");
|
|
950
|
+
(0, import_output.printNode)({ node: payload?.product, format: ctx.format, quiet: ctx.quiet });
|
|
400
951
|
return;
|
|
401
952
|
}
|
|
402
|
-
if (verb === "
|
|
403
|
-
const args = (0, import_router.parseStandardArgs)({
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
953
|
+
if (verb === "options list") {
|
|
954
|
+
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: { "product-id": { type: "string" } } });
|
|
955
|
+
const productId = requireProductIdForSubverb(args);
|
|
956
|
+
const selection = (0, import_select.resolveSelection)({
|
|
957
|
+
typeName: "ProductOption",
|
|
958
|
+
view: ctx.view,
|
|
959
|
+
baseSelection: getProductOptionListSelection(ctx.view),
|
|
960
|
+
select: args.select,
|
|
961
|
+
selection: args.selection,
|
|
962
|
+
include: args.include,
|
|
963
|
+
ensureId: ctx.quiet
|
|
409
964
|
});
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
const result = await (0, import_router.runMutation)(ctx, {
|
|
415
|
-
[mutation]: {
|
|
416
|
-
__args: { productId, media },
|
|
417
|
-
media: productMediaSelection,
|
|
418
|
-
mediaUserErrors: { code: true, field: true, message: true },
|
|
419
|
-
product: { id: true, title: true }
|
|
965
|
+
const result = await (0, import_router.runQuery)(ctx, {
|
|
966
|
+
product: {
|
|
967
|
+
__args: { id: productId },
|
|
968
|
+
options: selection
|
|
420
969
|
}
|
|
421
970
|
});
|
|
422
971
|
if (result === void 0) return;
|
|
423
|
-
const
|
|
424
|
-
(0,
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
}
|
|
429
|
-
if (verb === "delete-media") {
|
|
430
|
-
const args = (0, import_router.parseStandardArgs)({
|
|
431
|
-
argv,
|
|
432
|
-
extraOptions: {
|
|
433
|
-
"product-id": { type: "string" },
|
|
434
|
-
"media-ids": { type: "string", multiple: true }
|
|
435
|
-
}
|
|
436
|
-
});
|
|
437
|
-
const productId = (0, import_shared.requireId)(args["product-id"], "Product");
|
|
438
|
-
const mediaIds = (0, import_shared.parseStringList)(args["media-ids"], "--media-ids");
|
|
439
|
-
const result = await (0, import_router.runMutation)(ctx, {
|
|
440
|
-
productDeleteMedia: {
|
|
441
|
-
__args: { productId, mediaIds },
|
|
442
|
-
deletedMediaIds: true,
|
|
443
|
-
deletedProductImageIds: true,
|
|
444
|
-
mediaUserErrors: { code: true, field: true, message: true },
|
|
445
|
-
product: { id: true, title: true }
|
|
446
|
-
}
|
|
972
|
+
const options = result.product?.options ?? [];
|
|
973
|
+
(0, import_output.printConnection)({
|
|
974
|
+
connection: { nodes: options, pageInfo: void 0 },
|
|
975
|
+
format: ctx.format,
|
|
976
|
+
quiet: ctx.quiet
|
|
447
977
|
});
|
|
448
|
-
if (result === void 0) return;
|
|
449
|
-
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productDeleteMedia, failOnUserErrors: ctx.failOnUserErrors });
|
|
450
|
-
if (ctx.quiet) return console.log(result.productDeleteMedia?.product?.id ?? "");
|
|
451
|
-
(0, import_output.printJson)(result.productDeleteMedia, ctx.format !== "raw");
|
|
452
978
|
return;
|
|
453
979
|
}
|
|
454
|
-
if (verb === "
|
|
980
|
+
if (verb === "options create") {
|
|
455
981
|
const args = (0, import_router.parseStandardArgs)({
|
|
456
982
|
argv,
|
|
457
983
|
extraOptions: {
|
|
458
984
|
"product-id": { type: "string" },
|
|
459
|
-
option: { type: "string" },
|
|
460
|
-
"
|
|
461
|
-
"option-values-to-delete": { type: "string" },
|
|
462
|
-
"option-values-to-update": { type: "string" },
|
|
985
|
+
option: { type: "string", multiple: true },
|
|
986
|
+
"options-json": { type: "string" },
|
|
463
987
|
"variant-strategy": { type: "string" }
|
|
464
988
|
}
|
|
465
989
|
});
|
|
466
|
-
const productId = (
|
|
467
|
-
const
|
|
468
|
-
const
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
990
|
+
const productId = requireProductIdForSubverb(args);
|
|
991
|
+
const optionSpecs = parseRepeatableStrings(args.option, "--option", { allowEmpty: true });
|
|
992
|
+
const optionsJsonRaw = args["options-json"];
|
|
993
|
+
if (optionSpecs.length > 0 && optionsJsonRaw) {
|
|
994
|
+
throw new import_errors.CliError("Do not pass both --option and --options-json", 2);
|
|
995
|
+
}
|
|
996
|
+
const options = optionsJsonRaw !== void 0 ? (0, import_shared.parseJsonArg)(optionsJsonRaw, "--options-json") : optionSpecs.map((s) => parseOptionSpec(s, "--option"));
|
|
997
|
+
if (!Array.isArray(options) || options.length === 0) {
|
|
998
|
+
throw new import_errors.CliError("Missing options: pass one or more --option entries, or --options-json", 2);
|
|
999
|
+
}
|
|
1000
|
+
const variantStrategy = normalizeProductOptionCreateVariantStrategy(args["variant-strategy"]);
|
|
1001
|
+
const selection = (0, import_select.resolveSelection)({
|
|
1002
|
+
resource: "products",
|
|
1003
|
+
view: ctx.view,
|
|
1004
|
+
baseSelection: getProductSelectionForOptions(ctx.view),
|
|
1005
|
+
select: args.select,
|
|
1006
|
+
selection: args.selection,
|
|
1007
|
+
include: args.include,
|
|
1008
|
+
ensureId: ctx.quiet
|
|
1009
|
+
});
|
|
472
1010
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
473
|
-
|
|
474
|
-
__args: {
|
|
475
|
-
|
|
476
|
-
option,
|
|
477
|
-
...optionValuesToAdd !== void 0 ? { optionValuesToAdd } : {},
|
|
478
|
-
...optionValuesToDelete !== void 0 ? { optionValuesToDelete } : {},
|
|
479
|
-
...optionValuesToUpdate !== void 0 ? { optionValuesToUpdate } : {},
|
|
480
|
-
...variantStrategy ? { variantStrategy } : {}
|
|
481
|
-
},
|
|
482
|
-
product: productSummarySelection,
|
|
1011
|
+
productOptionsCreate: {
|
|
1012
|
+
__args: { productId, options, ...variantStrategy ? { variantStrategy } : {} },
|
|
1013
|
+
product: selection,
|
|
483
1014
|
userErrors: { code: true, field: true, message: true }
|
|
484
1015
|
}
|
|
485
1016
|
});
|
|
486
1017
|
if (result === void 0) return;
|
|
487
|
-
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.
|
|
488
|
-
|
|
489
|
-
(0, import_output.printJson)(result.productOptionUpdate, ctx.format !== "raw");
|
|
1018
|
+
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productOptionsCreate, failOnUserErrors: ctx.failOnUserErrors });
|
|
1019
|
+
(0, import_output.printNode)({ node: result.productOptionsCreate?.product, format: ctx.format, quiet: ctx.quiet });
|
|
490
1020
|
return;
|
|
491
1021
|
}
|
|
492
|
-
if (verb === "options
|
|
1022
|
+
if (verb === "options update") {
|
|
493
1023
|
const args = (0, import_router.parseStandardArgs)({
|
|
494
1024
|
argv,
|
|
495
1025
|
extraOptions: {
|
|
496
1026
|
"product-id": { type: "string" },
|
|
497
|
-
|
|
1027
|
+
"option-id": { type: "string" },
|
|
1028
|
+
name: { type: "string" },
|
|
1029
|
+
position: { type: "string" },
|
|
1030
|
+
"add-value": { type: "string", multiple: true },
|
|
1031
|
+
"delete-value": { type: "string", multiple: true },
|
|
1032
|
+
"rename-value": { type: "string", multiple: true },
|
|
1033
|
+
"delete-value-id": { type: "string", multiple: true },
|
|
1034
|
+
"rename-value-id": { type: "string", multiple: true },
|
|
1035
|
+
"option-json": { type: "string" },
|
|
1036
|
+
"add-values-json": { type: "string" },
|
|
1037
|
+
"delete-value-ids-json": { type: "string" },
|
|
1038
|
+
"update-values-json": { type: "string" },
|
|
498
1039
|
"variant-strategy": { type: "string" }
|
|
499
1040
|
}
|
|
500
1041
|
});
|
|
501
|
-
const productId = (
|
|
502
|
-
const
|
|
503
|
-
if (!
|
|
504
|
-
const
|
|
1042
|
+
const productId = requireProductIdForSubverb(args);
|
|
1043
|
+
const optionIdRaw = args["option-id"];
|
|
1044
|
+
if (!optionIdRaw) throw new import_errors.CliError("Missing --option-id", 2);
|
|
1045
|
+
const optionId = (0, import_gid.coerceGid)(optionIdRaw, "ProductOption");
|
|
1046
|
+
const optionJsonRaw = args["option-json"];
|
|
1047
|
+
const addValuesJsonRaw = args["add-values-json"];
|
|
1048
|
+
const deleteValueIdsJsonRaw = args["delete-value-ids-json"];
|
|
1049
|
+
const updateValuesJsonRaw = args["update-values-json"];
|
|
1050
|
+
const hasJsonMode = Boolean(optionJsonRaw || addValuesJsonRaw || deleteValueIdsJsonRaw || updateValuesJsonRaw);
|
|
1051
|
+
const addValueNames = parseRepeatableStrings(args["add-value"], "--add-value", { allowEmpty: true });
|
|
1052
|
+
const deleteValueNames = parseRepeatableStrings(args["delete-value"], "--delete-value", { allowEmpty: true });
|
|
1053
|
+
const renameValueSpecs = parseRepeatableStrings(args["rename-value"], "--rename-value", { allowEmpty: true });
|
|
1054
|
+
const deleteValueIdSpecs = parseRepeatableStrings(args["delete-value-id"], "--delete-value-id", {
|
|
1055
|
+
allowEmpty: true
|
|
1056
|
+
});
|
|
1057
|
+
const renameValueIdSpecs = parseRepeatableStrings(args["rename-value-id"], "--rename-value-id", {
|
|
1058
|
+
allowEmpty: true
|
|
1059
|
+
});
|
|
1060
|
+
if (hasJsonMode) {
|
|
1061
|
+
if (addValueNames.length || deleteValueNames.length || renameValueSpecs.length || deleteValueIdSpecs.length || renameValueIdSpecs.length || args.name !== void 0 || args.position !== void 0) {
|
|
1062
|
+
throw new import_errors.CliError("Do not mix JSON flags with non-JSON option update flags", 2);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
const position = parsePositiveIntFlag({ value: args.position, flag: "--position" });
|
|
1066
|
+
const hasNonJsonOptionChange = typeof args.name === "string" && args.name.trim() !== "" || position !== void 0;
|
|
1067
|
+
const hasNonJsonValueChange = addValueNames.length > 0 || deleteValueNames.length > 0 || renameValueSpecs.length > 0 || deleteValueIdSpecs.length > 0 || renameValueIdSpecs.length > 0;
|
|
1068
|
+
if (!hasJsonMode && !hasNonJsonOptionChange && !hasNonJsonValueChange) {
|
|
1069
|
+
throw new import_errors.CliError(
|
|
1070
|
+
"No changes specified. Pass --name/--position and/or value change flags (e.g. --add-value, --delete-value, --rename-value).",
|
|
1071
|
+
2
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
const optionUpdate = optionJsonRaw !== void 0 ? (0, import_shared.parseJsonArg)(optionJsonRaw, "--option-json") : {
|
|
1075
|
+
id: optionId,
|
|
1076
|
+
...typeof args.name === "string" && args.name.trim() ? { name: args.name.trim() } : {},
|
|
1077
|
+
...position !== void 0 ? { position } : {}
|
|
1078
|
+
};
|
|
1079
|
+
if (!optionUpdate || typeof optionUpdate !== "object") {
|
|
1080
|
+
throw new import_errors.CliError("--option-json must be a JSON object", 2);
|
|
1081
|
+
}
|
|
1082
|
+
if (!optionUpdate.id) optionUpdate.id = optionId;
|
|
1083
|
+
const optionValuesToAdd = addValuesJsonRaw !== void 0 ? (0, import_shared.parseJsonArg)(addValuesJsonRaw, "--add-values-json") : addValueNames.map((name) => ({ name }));
|
|
1084
|
+
const optionValuesToDeleteJson = deleteValueIdsJsonRaw !== void 0 ? (0, import_shared.parseJsonArg)(deleteValueIdsJsonRaw, "--delete-value-ids-json") : void 0;
|
|
1085
|
+
const optionValuesToUpdate = updateValuesJsonRaw !== void 0 ? (0, import_shared.parseJsonArg)(updateValuesJsonRaw, "--update-values-json") : void 0;
|
|
1086
|
+
const optionValuesToDeleteFromIds = deleteValueIdSpecs.map((id) => (0, import_gid.coerceGid)(id, "ProductOptionValue"));
|
|
1087
|
+
const needsResolutionByName = deleteValueNames.length > 0 || renameValueSpecs.length > 0;
|
|
1088
|
+
if (needsResolutionByName && ctx.dryRun) {
|
|
1089
|
+
throw new import_errors.CliError(
|
|
1090
|
+
"Name-based value changes are not supported in --dry-run mode. Use --delete-value-id/--rename-value-id or JSON flags.",
|
|
1091
|
+
2
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
let resolvedDeletesFromNames = [];
|
|
1095
|
+
let resolvedUpdatesFromNames = [];
|
|
1096
|
+
if (needsResolutionByName) {
|
|
1097
|
+
const options = await fetchProductOptionsForResolution({ ctx, productId });
|
|
1098
|
+
const option = options.find((o) => typeof o?.id === "string" && o.id === optionId);
|
|
1099
|
+
if (!option) throw new import_errors.CliError(`Option not found on product: ${optionId}`, 2);
|
|
1100
|
+
const optionValues = option.optionValues ?? [];
|
|
1101
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1102
|
+
for (const ov of optionValues) {
|
|
1103
|
+
const n = typeof ov?.name === "string" ? ov.name : void 0;
|
|
1104
|
+
if (!n) continue;
|
|
1105
|
+
const list = byName.get(n) ?? [];
|
|
1106
|
+
list.push(ov);
|
|
1107
|
+
byName.set(n, list);
|
|
1108
|
+
}
|
|
1109
|
+
for (const name of deleteValueNames) {
|
|
1110
|
+
const matches = byName.get(name) ?? [];
|
|
1111
|
+
if (matches.length === 0) throw new import_errors.CliError(`Option value not found: "${name}"`, 2);
|
|
1112
|
+
if (matches.length > 1) {
|
|
1113
|
+
throw new import_errors.CliError(`Multiple option values named "${name}" exist. Use --delete-value-id instead.`, 2);
|
|
1114
|
+
}
|
|
1115
|
+
const id = matches[0]?.id;
|
|
1116
|
+
if (typeof id !== "string" || !id) throw new import_errors.CliError(`Option value "${name}" is missing an ID`, 2);
|
|
1117
|
+
resolvedDeletesFromNames.push(id);
|
|
1118
|
+
}
|
|
1119
|
+
for (const spec of renameValueSpecs) {
|
|
1120
|
+
const { from, to } = parseFromTo(spec, "--rename-value");
|
|
1121
|
+
const matches = byName.get(from) ?? [];
|
|
1122
|
+
if (matches.length === 0) throw new import_errors.CliError(`Option value not found: "${from}"`, 2);
|
|
1123
|
+
if (matches.length > 1) {
|
|
1124
|
+
throw new import_errors.CliError(`Multiple option values named "${from}" exist. Use --rename-value-id instead.`, 2);
|
|
1125
|
+
}
|
|
1126
|
+
const id = matches[0]?.id;
|
|
1127
|
+
if (typeof id !== "string" || !id) throw new import_errors.CliError(`Option value "${from}" is missing an ID`, 2);
|
|
1128
|
+
resolvedUpdatesFromNames.push({ id, name: to });
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
const renameUpdatesFromIds = [];
|
|
1132
|
+
for (const spec of renameValueIdSpecs) {
|
|
1133
|
+
const { from, to } = parseFromTo(spec, "--rename-value-id");
|
|
1134
|
+
renameUpdatesFromIds.push({ id: (0, import_gid.coerceGid)(from, "ProductOptionValue"), name: to });
|
|
1135
|
+
}
|
|
1136
|
+
const deletesFromJson = optionValuesToDeleteJson !== void 0 ? (() => {
|
|
1137
|
+
if (!Array.isArray(optionValuesToDeleteJson)) {
|
|
1138
|
+
throw new import_errors.CliError("--delete-value-ids-json must be a JSON array", 2);
|
|
1139
|
+
}
|
|
1140
|
+
return optionValuesToDeleteJson.map((id) => {
|
|
1141
|
+
if (typeof id !== "string" || !id.trim()) throw new import_errors.CliError("delete-value-ids-json must contain strings", 2);
|
|
1142
|
+
return id;
|
|
1143
|
+
});
|
|
1144
|
+
})() : [];
|
|
1145
|
+
const deletes = Array.from(/* @__PURE__ */ new Set([...optionValuesToDeleteFromIds, ...resolvedDeletesFromNames, ...deletesFromJson]));
|
|
1146
|
+
const updates = [
|
|
1147
|
+
...Array.isArray(optionValuesToUpdate) ? optionValuesToUpdate : optionValuesToUpdate ? [optionValuesToUpdate] : [],
|
|
1148
|
+
...resolvedUpdatesFromNames,
|
|
1149
|
+
...renameUpdatesFromIds
|
|
1150
|
+
];
|
|
1151
|
+
if (optionValuesToAdd !== void 0 && optionValuesToAdd !== null && !Array.isArray(optionValuesToAdd)) {
|
|
1152
|
+
throw new import_errors.CliError("--add-values-json must be a JSON array", 2);
|
|
1153
|
+
}
|
|
1154
|
+
if (optionValuesToUpdate !== void 0 && optionValuesToUpdate !== null && !Array.isArray(optionValuesToUpdate)) {
|
|
1155
|
+
throw new import_errors.CliError("--update-values-json must be a JSON array", 2);
|
|
1156
|
+
}
|
|
1157
|
+
const variantStrategy = normalizeProductOptionUpdateVariantStrategy(args["variant-strategy"]);
|
|
1158
|
+
const selection = (0, import_select.resolveSelection)({
|
|
1159
|
+
resource: "products",
|
|
1160
|
+
view: ctx.view,
|
|
1161
|
+
baseSelection: getProductSelectionForOptions(ctx.view),
|
|
1162
|
+
select: args.select,
|
|
1163
|
+
selection: args.selection,
|
|
1164
|
+
include: args.include,
|
|
1165
|
+
ensureId: ctx.quiet
|
|
1166
|
+
});
|
|
505
1167
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
506
|
-
|
|
1168
|
+
productOptionUpdate: {
|
|
507
1169
|
__args: {
|
|
508
1170
|
productId,
|
|
509
|
-
|
|
1171
|
+
option: optionUpdate,
|
|
1172
|
+
...Array.isArray(optionValuesToAdd) && optionValuesToAdd.length ? { optionValuesToAdd } : {},
|
|
1173
|
+
...deletes.length ? { optionValuesToDelete: deletes } : {},
|
|
1174
|
+
...updates.length ? { optionValuesToUpdate: updates } : {},
|
|
510
1175
|
...variantStrategy ? { variantStrategy } : {}
|
|
511
1176
|
},
|
|
512
|
-
product:
|
|
1177
|
+
product: selection,
|
|
513
1178
|
userErrors: { code: true, field: true, message: true }
|
|
514
1179
|
}
|
|
515
1180
|
});
|
|
516
1181
|
if (result === void 0) return;
|
|
517
|
-
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.
|
|
518
|
-
|
|
519
|
-
(0, import_output.printJson)(result.productOptionsCreate, ctx.format !== "raw");
|
|
1182
|
+
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productOptionUpdate, failOnUserErrors: ctx.failOnUserErrors });
|
|
1183
|
+
(0, import_output.printNode)({ node: result.productOptionUpdate?.product, format: ctx.format, quiet: ctx.quiet });
|
|
520
1184
|
return;
|
|
521
1185
|
}
|
|
522
|
-
if (verb === "options
|
|
1186
|
+
if (verb === "options delete") {
|
|
523
1187
|
const args = (0, import_router.parseStandardArgs)({
|
|
524
1188
|
argv,
|
|
525
1189
|
extraOptions: {
|
|
526
1190
|
"product-id": { type: "string" },
|
|
527
|
-
"option-
|
|
1191
|
+
"option-id": { type: "string", multiple: true },
|
|
1192
|
+
"option-name": { type: "string", multiple: true },
|
|
528
1193
|
strategy: { type: "string" }
|
|
529
1194
|
}
|
|
530
1195
|
});
|
|
531
|
-
const productId = (
|
|
532
|
-
const
|
|
533
|
-
const
|
|
1196
|
+
const productId = requireProductIdForSubverb(args);
|
|
1197
|
+
const optionIdsRaw = (0, import_shared.parseStringList)(args["option-id"], "--option-id", { allowEmpty: true });
|
|
1198
|
+
const optionNames = (0, import_shared.parseStringList)(args["option-name"], "--option-name", { allowEmpty: true });
|
|
1199
|
+
const strategy = normalizeProductOptionDeleteStrategy(args.strategy);
|
|
1200
|
+
if (optionIdsRaw.length === 0 && optionNames.length === 0) {
|
|
1201
|
+
throw new import_errors.CliError("Missing options: pass one or more --option-id and/or --option-name entries", 2);
|
|
1202
|
+
}
|
|
1203
|
+
if (ctx.dryRun && optionNames.length > 0) {
|
|
1204
|
+
throw new import_errors.CliError("Option name resolution is not supported in --dry-run mode. Use --option-id instead.", 2);
|
|
1205
|
+
}
|
|
1206
|
+
const optionIds = optionIdsRaw.map((id) => (0, import_gid.coerceGid)(id, "ProductOption"));
|
|
1207
|
+
if (optionNames.length > 0) {
|
|
1208
|
+
const options = await fetchProductOptionsForResolution({ ctx, productId });
|
|
1209
|
+
for (const name of optionNames) {
|
|
1210
|
+
const opt = resolveSingleOptionByName(options, name);
|
|
1211
|
+
if (!opt) throw new import_errors.CliError(`Option not found on product: "${name}"`, 2);
|
|
1212
|
+
const id = opt?.id;
|
|
1213
|
+
if (typeof id !== "string" || !id) throw new import_errors.CliError(`Option "${name}" is missing an ID`, 2);
|
|
1214
|
+
optionIds.push(id);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
const uniqueOptionIds = Array.from(new Set(optionIds));
|
|
534
1218
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
535
1219
|
productOptionsDelete: {
|
|
536
|
-
__args: { productId, options, ...strategy ? { strategy } : {} },
|
|
1220
|
+
__args: { productId, options: uniqueOptionIds, ...strategy ? { strategy } : {} },
|
|
537
1221
|
deletedOptionsIds: true,
|
|
538
|
-
product: productSummarySelection,
|
|
539
1222
|
userErrors: { code: true, field: true, message: true }
|
|
540
1223
|
}
|
|
541
1224
|
});
|
|
542
1225
|
if (result === void 0) return;
|
|
543
1226
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productOptionsDelete, failOnUserErrors: ctx.failOnUserErrors });
|
|
544
|
-
|
|
545
|
-
|
|
1227
|
+
const deleted = result.productOptionsDelete?.deletedOptionsIds ?? [];
|
|
1228
|
+
if (ctx.quiet) {
|
|
1229
|
+
for (const id of deleted) {
|
|
1230
|
+
if (typeof id === "string" && id) console.log(id);
|
|
1231
|
+
}
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
(0, import_output.printNode)({
|
|
1235
|
+
node: { deletedOptionsIds: deleted.filter((id) => typeof id === "string" && id.length > 0) },
|
|
1236
|
+
format: ctx.format,
|
|
1237
|
+
quiet: false
|
|
1238
|
+
});
|
|
546
1239
|
return;
|
|
547
1240
|
}
|
|
548
|
-
if (verb === "options
|
|
1241
|
+
if (verb === "options reorder") {
|
|
549
1242
|
const args = (0, import_router.parseStandardArgs)({
|
|
550
1243
|
argv,
|
|
551
1244
|
extraOptions: {
|
|
552
1245
|
"product-id": { type: "string" },
|
|
553
|
-
|
|
1246
|
+
order: { type: "string", multiple: true },
|
|
1247
|
+
"options-json": { type: "string" }
|
|
554
1248
|
}
|
|
555
1249
|
});
|
|
556
|
-
const productId = (
|
|
557
|
-
const
|
|
558
|
-
|
|
1250
|
+
const productId = requireProductIdForSubverb(args);
|
|
1251
|
+
const orderSpecs = parseRepeatableStrings(args.order, "--order", { allowEmpty: true });
|
|
1252
|
+
const optionsJsonRaw = args["options-json"];
|
|
1253
|
+
if (orderSpecs.length > 0 && optionsJsonRaw) {
|
|
1254
|
+
throw new import_errors.CliError("Do not pass both --order and --options-json", 2);
|
|
1255
|
+
}
|
|
1256
|
+
const selection = (0, import_select.resolveSelection)({
|
|
1257
|
+
resource: "products",
|
|
1258
|
+
view: ctx.view,
|
|
1259
|
+
baseSelection: getProductSelectionForOptions(ctx.view),
|
|
1260
|
+
select: args.select,
|
|
1261
|
+
selection: args.selection,
|
|
1262
|
+
include: args.include,
|
|
1263
|
+
ensureId: ctx.quiet
|
|
1264
|
+
});
|
|
1265
|
+
const optionsInput = optionsJsonRaw !== void 0 ? (0, import_shared.parseJsonArg)(optionsJsonRaw, "--options-json") : void 0;
|
|
1266
|
+
let options = [];
|
|
1267
|
+
if (optionsInput !== void 0) {
|
|
1268
|
+
if (!Array.isArray(optionsInput)) throw new import_errors.CliError("--options-json must be a JSON array", 2);
|
|
1269
|
+
options = optionsInput;
|
|
1270
|
+
} else {
|
|
1271
|
+
if (orderSpecs.length === 0) throw new import_errors.CliError("Missing order: pass one or more --order entries, or --options-json", 2);
|
|
1272
|
+
const parsed = [];
|
|
1273
|
+
const hasAnyValueOrder = orderSpecs.some((s) => s.includes("="));
|
|
1274
|
+
if (hasAnyValueOrder && ctx.dryRun) {
|
|
1275
|
+
throw new import_errors.CliError("Value reordering via --order is not supported in --dry-run mode. Use --options-json.", 2);
|
|
1276
|
+
}
|
|
1277
|
+
let optionsForValidation;
|
|
1278
|
+
if (hasAnyValueOrder) {
|
|
1279
|
+
optionsForValidation = await fetchProductOptionsForResolution({ ctx, productId });
|
|
1280
|
+
}
|
|
1281
|
+
for (const spec of orderSpecs) {
|
|
1282
|
+
const trimmed = spec.trim();
|
|
1283
|
+
const eq = trimmed.indexOf("=");
|
|
1284
|
+
const optionToken = (eq === -1 ? trimmed : trimmed.slice(0, eq)).trim();
|
|
1285
|
+
if (!optionToken) throw new import_errors.CliError("--order cannot be empty", 2);
|
|
1286
|
+
const optionInput = looksLikeGidOrNumericId(optionToken) ? { id: (0, import_gid.coerceGid)(optionToken, "ProductOption") } : { name: optionToken };
|
|
1287
|
+
if (eq !== -1) {
|
|
1288
|
+
const valuesPart = trimmed.slice(eq + 1).trim();
|
|
1289
|
+
if (!valuesPart) throw new import_errors.CliError(`--order "${spec}" must include at least one value after '='`, 2);
|
|
1290
|
+
const valueTokens = valuesPart.split(",").map((v) => v.trim()).filter(Boolean);
|
|
1291
|
+
if (valueTokens.length === 0) throw new import_errors.CliError(`--order "${spec}" must include at least one value after '='`, 2);
|
|
1292
|
+
if (!optionsForValidation) throw new import_errors.CliError("Internal error: missing options for validation", 2);
|
|
1293
|
+
const resolvedOption = "id" in optionInput ? optionsForValidation.find((o) => typeof o?.id === "string" && o.id === optionInput.id) : resolveSingleOptionByName(optionsForValidation, optionInput.name);
|
|
1294
|
+
if (!resolvedOption) {
|
|
1295
|
+
const ref = "id" in optionInput ? optionInput.id : `"${optionInput.name}"`;
|
|
1296
|
+
throw new import_errors.CliError(`Option not found on product: ${ref}`, 2);
|
|
1297
|
+
}
|
|
1298
|
+
const optionValues = resolvedOption.optionValues ?? [];
|
|
1299
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1300
|
+
const existingIds = [];
|
|
1301
|
+
for (const ov of optionValues) {
|
|
1302
|
+
const id = typeof ov?.id === "string" ? ov.id : void 0;
|
|
1303
|
+
const name = typeof ov?.name === "string" ? ov.name : void 0;
|
|
1304
|
+
if (id) existingIds.push(id);
|
|
1305
|
+
if (name) {
|
|
1306
|
+
const list = byName.get(name) ?? [];
|
|
1307
|
+
list.push(ov);
|
|
1308
|
+
byName.set(name, list);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
const providedIds = [];
|
|
1312
|
+
for (const vt of valueTokens) {
|
|
1313
|
+
if (looksLikeGidOrNumericId(vt)) {
|
|
1314
|
+
providedIds.push((0, import_gid.coerceGid)(vt, "ProductOptionValue"));
|
|
1315
|
+
continue;
|
|
1316
|
+
}
|
|
1317
|
+
const matches = byName.get(vt) ?? [];
|
|
1318
|
+
if (matches.length === 0) throw new import_errors.CliError(`Option value not found: "${vt}"`, 2);
|
|
1319
|
+
if (matches.length > 1) throw new import_errors.CliError(`Multiple option values named "${vt}" exist. Use IDs.`, 2);
|
|
1320
|
+
const id = matches[0]?.id;
|
|
1321
|
+
if (typeof id !== "string" || !id) throw new import_errors.CliError(`Option value "${vt}" is missing an ID`, 2);
|
|
1322
|
+
providedIds.push(id);
|
|
1323
|
+
}
|
|
1324
|
+
const existingSet = new Set(existingIds);
|
|
1325
|
+
const providedSet = new Set(providedIds);
|
|
1326
|
+
if (providedSet.size !== providedIds.length) {
|
|
1327
|
+
throw new import_errors.CliError("Duplicate option values provided in --order value list", 2);
|
|
1328
|
+
}
|
|
1329
|
+
const missing = existingIds.filter((id) => !providedSet.has(id));
|
|
1330
|
+
const extra = providedIds.filter((id) => !existingSet.has(id));
|
|
1331
|
+
if (missing.length || extra.length) {
|
|
1332
|
+
throw new import_errors.CliError(
|
|
1333
|
+
`--order "${optionToken}=..." must include the full value order for that option.`,
|
|
1334
|
+
2
|
|
1335
|
+
);
|
|
1336
|
+
}
|
|
1337
|
+
parsed.push({
|
|
1338
|
+
id: resolvedOption.id,
|
|
1339
|
+
values: providedIds.map((id) => ({ id }))
|
|
1340
|
+
});
|
|
1341
|
+
} else {
|
|
1342
|
+
parsed.push(optionInput);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
options = parsed;
|
|
1346
|
+
}
|
|
559
1347
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
560
1348
|
productOptionsReorder: {
|
|
561
1349
|
__args: { productId, options },
|
|
562
|
-
product:
|
|
1350
|
+
product: selection,
|
|
563
1351
|
userErrors: { code: true, field: true, message: true }
|
|
564
1352
|
}
|
|
565
1353
|
});
|
|
566
1354
|
if (result === void 0) return;
|
|
567
1355
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productOptionsReorder, failOnUserErrors: ctx.failOnUserErrors });
|
|
568
|
-
|
|
569
|
-
(0, import_output.printJson)(result.productOptionsReorder, ctx.format !== "raw");
|
|
1356
|
+
(0, import_output.printNode)({ node: result.productOptionsReorder?.product, format: ctx.format, quiet: ctx.quiet });
|
|
570
1357
|
return;
|
|
571
1358
|
}
|
|
572
1359
|
if (verb === "combined-listing-update") {
|
|
@@ -581,12 +1368,21 @@ const runProducts = async ({
|
|
|
581
1368
|
"options-and-values": { type: "string" }
|
|
582
1369
|
}
|
|
583
1370
|
});
|
|
584
|
-
const parentProductId = (0, import_shared.requireId)(args["parent-product-id"], "Product");
|
|
1371
|
+
const parentProductId = (0, import_shared.requireId)(args["parent-product-id"], "Product", "--parent-product-id");
|
|
585
1372
|
const optionsAndValues = args["options-and-values"] ? (0, import_shared.parseJsonArg)(args["options-and-values"], "--options-and-values") : void 0;
|
|
586
1373
|
const productsAdded = args["products-added"] ? (0, import_shared.parseJsonArg)(args["products-added"], "--products-added") : void 0;
|
|
587
1374
|
const productsEdited = args["products-edited"] ? (0, import_shared.parseJsonArg)(args["products-edited"], "--products-edited") : void 0;
|
|
588
1375
|
const productsRemovedIds = args["products-removed-ids"] ? (0, import_shared.parseIds)(args["products-removed-ids"], "Product") : void 0;
|
|
589
1376
|
const title = args.title;
|
|
1377
|
+
const selection = (0, import_select.resolveSelection)({
|
|
1378
|
+
resource: "products",
|
|
1379
|
+
view: ctx.view,
|
|
1380
|
+
baseSelection: getProductSelection(ctx.view),
|
|
1381
|
+
select: args.select,
|
|
1382
|
+
selection: args.selection,
|
|
1383
|
+
include: args.include,
|
|
1384
|
+
ensureId: ctx.quiet
|
|
1385
|
+
});
|
|
590
1386
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
591
1387
|
combinedListingUpdate: {
|
|
592
1388
|
__args: {
|
|
@@ -597,14 +1393,13 @@ const runProducts = async ({
|
|
|
597
1393
|
...productsEdited !== void 0 ? { productsEdited } : {},
|
|
598
1394
|
...productsRemovedIds !== void 0 ? { productsRemovedIds } : {}
|
|
599
1395
|
},
|
|
600
|
-
product:
|
|
1396
|
+
product: selection,
|
|
601
1397
|
userErrors: { code: true, field: true, message: true }
|
|
602
1398
|
}
|
|
603
1399
|
});
|
|
604
1400
|
if (result === void 0) return;
|
|
605
1401
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.combinedListingUpdate, failOnUserErrors: ctx.failOnUserErrors });
|
|
606
|
-
|
|
607
|
-
(0, import_output.printJson)(result.combinedListingUpdate, ctx.format !== "raw");
|
|
1402
|
+
(0, import_output.printNode)({ node: result.combinedListingUpdate?.product, format: ctx.format, quiet: ctx.quiet });
|
|
608
1403
|
return;
|
|
609
1404
|
}
|
|
610
1405
|
if (verb === "bundle-create" || verb === "bundle-update") {
|
|
@@ -615,6 +1410,15 @@ const runProducts = async ({
|
|
|
615
1410
|
setJsonArgs: args["set-json"]
|
|
616
1411
|
});
|
|
617
1412
|
if (!built.used) throw new import_errors.CliError("Missing --input or --set/--set-json", 2);
|
|
1413
|
+
const productSelection = (0, import_select.resolveSelection)({
|
|
1414
|
+
resource: "products",
|
|
1415
|
+
view: ctx.view,
|
|
1416
|
+
baseSelection: getProductSelection(ctx.view),
|
|
1417
|
+
select: args.select,
|
|
1418
|
+
selection: args.selection,
|
|
1419
|
+
include: args.include,
|
|
1420
|
+
ensureId: ctx.quiet
|
|
1421
|
+
});
|
|
618
1422
|
const mutation = verb === "bundle-create" ? "productBundleCreate" : "productBundleUpdate";
|
|
619
1423
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
620
1424
|
[mutation]: {
|
|
@@ -622,8 +1426,7 @@ const runProducts = async ({
|
|
|
622
1426
|
productBundleOperation: {
|
|
623
1427
|
id: true,
|
|
624
1428
|
status: true,
|
|
625
|
-
product:
|
|
626
|
-
userErrors: { field: true, message: true }
|
|
1429
|
+
product: productSelection
|
|
627
1430
|
},
|
|
628
1431
|
userErrors: { field: true, message: true }
|
|
629
1432
|
}
|
|
@@ -631,8 +1434,28 @@ const runProducts = async ({
|
|
|
631
1434
|
if (result === void 0) return;
|
|
632
1435
|
const payload = result[mutation];
|
|
633
1436
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload, failOnUserErrors: ctx.failOnUserErrors });
|
|
634
|
-
|
|
635
|
-
|
|
1437
|
+
const operation = payload?.productBundleOperation ? {
|
|
1438
|
+
id: payload.productBundleOperation.id,
|
|
1439
|
+
status: payload.productBundleOperation.status
|
|
1440
|
+
} : void 0;
|
|
1441
|
+
const product = payload?.productBundleOperation?.product;
|
|
1442
|
+
if (product && typeof product === "object") {
|
|
1443
|
+
(0, import_output.printNode)({
|
|
1444
|
+
node: { ...product, ...operation ? { operation } : {} },
|
|
1445
|
+
format: ctx.format,
|
|
1446
|
+
quiet: ctx.quiet
|
|
1447
|
+
});
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
if (ctx.quiet) return;
|
|
1451
|
+
(0, import_output.printJson)(
|
|
1452
|
+
{
|
|
1453
|
+
product: product ?? null,
|
|
1454
|
+
...operation ? { operation } : {},
|
|
1455
|
+
userErrors: payload?.userErrors ?? []
|
|
1456
|
+
},
|
|
1457
|
+
ctx.format !== "raw"
|
|
1458
|
+
);
|
|
636
1459
|
return;
|
|
637
1460
|
}
|
|
638
1461
|
if (verb === "count") {
|
|
@@ -671,12 +1494,14 @@ const runProducts = async ({
|
|
|
671
1494
|
const args = (0, import_router.parseStandardArgs)({
|
|
672
1495
|
argv,
|
|
673
1496
|
extraOptions: {
|
|
1497
|
+
"product-id": { type: "string" },
|
|
674
1498
|
"publication-id": { type: "string", multiple: true },
|
|
675
1499
|
publication: { type: "string", multiple: true },
|
|
676
1500
|
at: { type: "string" },
|
|
677
1501
|
now: { type: "boolean" }
|
|
678
1502
|
}
|
|
679
1503
|
});
|
|
1504
|
+
const id = requireProductIdForRootVerb(args);
|
|
680
1505
|
const publicationIds = args["publication-id"] ?? [];
|
|
681
1506
|
const publicationNames = args.publication ?? [];
|
|
682
1507
|
const resolvedPublicationIds = await (0, import_publishablePublish.resolvePublicationIds)({
|
|
@@ -688,7 +1513,7 @@ const runProducts = async ({
|
|
|
688
1513
|
const publishDate = (0, import_publishablePublish.parsePublishDate)({ at: args.at, now: args.now });
|
|
689
1514
|
const payload2 = await (0, import_publishablePublish.publishProduct)({
|
|
690
1515
|
ctx,
|
|
691
|
-
id
|
|
1516
|
+
id,
|
|
692
1517
|
publicationIds: resolvedPublicationIds,
|
|
693
1518
|
publishDate
|
|
694
1519
|
});
|
|
@@ -699,7 +1524,7 @@ const runProducts = async ({
|
|
|
699
1524
|
}
|
|
700
1525
|
const payload = await (0, import_publishablePublish.unpublishProduct)({
|
|
701
1526
|
ctx,
|
|
702
|
-
id
|
|
1527
|
+
id,
|
|
703
1528
|
publicationIds: resolvedPublicationIds
|
|
704
1529
|
});
|
|
705
1530
|
if (payload === void 0) return;
|
|
@@ -711,6 +1536,7 @@ const runProducts = async ({
|
|
|
711
1536
|
const args = (0, import_router.parseStandardArgs)({
|
|
712
1537
|
argv,
|
|
713
1538
|
extraOptions: {
|
|
1539
|
+
"product-id": { type: "string" },
|
|
714
1540
|
at: { type: "string" },
|
|
715
1541
|
now: { type: "boolean" }
|
|
716
1542
|
}
|
|
@@ -719,13 +1545,14 @@ const runProducts = async ({
|
|
|
719
1545
|
await (0, import_resolvePublicationId.listPublications)(ctx);
|
|
720
1546
|
return;
|
|
721
1547
|
}
|
|
1548
|
+
const id = requireProductIdForRootVerb(args);
|
|
722
1549
|
const publishDate = (0, import_publishablePublish.parsePublishDate)({ at: args.at, now: args.now });
|
|
723
1550
|
const publications = await (0, import_resolvePublicationId.listPublications)(ctx);
|
|
724
1551
|
const publicationIds = publications.map((p) => p.id).filter(Boolean);
|
|
725
1552
|
if (publicationIds.length === 0) throw new import_errors.CliError("No publications found to publish to", 2);
|
|
726
1553
|
const payload = await (0, import_publishablePublish.publishProduct)({
|
|
727
1554
|
ctx,
|
|
728
|
-
id
|
|
1555
|
+
id,
|
|
729
1556
|
publicationIds,
|
|
730
1557
|
publishDate
|
|
731
1558
|
});
|
|
@@ -735,21 +1562,22 @@ const runProducts = async ({
|
|
|
735
1562
|
return;
|
|
736
1563
|
}
|
|
737
1564
|
if (verb === "metafields upsert") {
|
|
738
|
-
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: {} });
|
|
1565
|
+
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: { "product-id": { type: "string" } } });
|
|
1566
|
+
const productId = requireProductIdForSubverb(args);
|
|
739
1567
|
const built = (0, import_input.buildInput)({
|
|
740
1568
|
inputArg: args.input,
|
|
741
1569
|
setArgs: args.set,
|
|
742
1570
|
setJsonArgs: args["set-json"]
|
|
743
1571
|
});
|
|
744
1572
|
if (!built.used) throw new import_errors.CliError("Missing --input or --set/--set-json", 2);
|
|
745
|
-
const result = await (0, import_metafieldsUpsert.metafieldsUpsert)({ ctx, id:
|
|
1573
|
+
const result = await (0, import_metafieldsUpsert.metafieldsUpsert)({ ctx, id: productId, input: built.input });
|
|
746
1574
|
if (result === void 0) return;
|
|
747
1575
|
(0, import_output.printJson)(result);
|
|
748
1576
|
return;
|
|
749
1577
|
}
|
|
750
1578
|
if (verb === "get") {
|
|
751
|
-
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: {} });
|
|
752
|
-
const id = (
|
|
1579
|
+
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: { "product-id": { type: "string" } } });
|
|
1580
|
+
const id = requireProductIdForRootVerb(args);
|
|
753
1581
|
const selectValues = Array.isArray(args.select) ? args.select : args.select ? [args.select] : [];
|
|
754
1582
|
const selectionOverride = typeof args.selection === "string" && args.selection.length > 0;
|
|
755
1583
|
const select = !selectionOverride && ctx.view !== "raw" && ctx.view !== "ids" ? Array.from(/* @__PURE__ */ new Set([...selectValues, "resourcePublicationsV2.nodes.publication.name"])) : args.select;
|
|
@@ -829,39 +1657,57 @@ const runProducts = async ({
|
|
|
829
1657
|
setJsonArgs: args["set-json"]
|
|
830
1658
|
});
|
|
831
1659
|
if (!built.used) throw new import_errors.CliError("Missing --input or --set/--set-json", 2);
|
|
1660
|
+
const selection = (0, import_select.resolveSelection)({
|
|
1661
|
+
resource: "products",
|
|
1662
|
+
view: ctx.view,
|
|
1663
|
+
baseSelection: getProductSelection(ctx.view),
|
|
1664
|
+
select: args.select,
|
|
1665
|
+
selection: args.selection,
|
|
1666
|
+
include: args.include,
|
|
1667
|
+
ensureId: ctx.quiet,
|
|
1668
|
+
defaultConnectionFirst: ctx.view === "all" ? 50 : 10
|
|
1669
|
+
});
|
|
832
1670
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
833
1671
|
productCreate: {
|
|
834
1672
|
__args: { input: built.input },
|
|
835
|
-
product:
|
|
1673
|
+
product: selection,
|
|
836
1674
|
userErrors: { field: true, message: true }
|
|
837
1675
|
}
|
|
838
1676
|
});
|
|
839
1677
|
if (result === void 0) return;
|
|
840
1678
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productCreate, failOnUserErrors: ctx.failOnUserErrors });
|
|
841
|
-
|
|
842
|
-
(0, import_output.printJson)(result.productCreate, ctx.format !== "raw");
|
|
1679
|
+
(0, import_output.printNode)({ node: result.productCreate?.product, format: ctx.format, quiet: ctx.quiet });
|
|
843
1680
|
return;
|
|
844
1681
|
}
|
|
845
1682
|
if (verb === "archive" || verb === "unarchive") {
|
|
846
|
-
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: {} });
|
|
847
|
-
const id = (
|
|
1683
|
+
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: { "product-id": { type: "string" } } });
|
|
1684
|
+
const id = requireProductIdForRootVerb(args);
|
|
848
1685
|
const status = verb === "archive" ? "ARCHIVED" : args.status ?? "DRAFT";
|
|
1686
|
+
const selection = (0, import_select.resolveSelection)({
|
|
1687
|
+
resource: "products",
|
|
1688
|
+
view: ctx.view,
|
|
1689
|
+
baseSelection: getProductSelection(ctx.view),
|
|
1690
|
+
select: args.select,
|
|
1691
|
+
selection: args.selection,
|
|
1692
|
+
include: args.include,
|
|
1693
|
+
ensureId: ctx.quiet,
|
|
1694
|
+
defaultConnectionFirst: ctx.view === "all" ? 50 : 10
|
|
1695
|
+
});
|
|
849
1696
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
850
1697
|
productUpdate: {
|
|
851
1698
|
__args: { input: { id, status } },
|
|
852
|
-
product:
|
|
1699
|
+
product: selection,
|
|
853
1700
|
userErrors: { field: true, message: true }
|
|
854
1701
|
}
|
|
855
1702
|
});
|
|
856
1703
|
if (result === void 0) return;
|
|
857
1704
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productUpdate, failOnUserErrors: ctx.failOnUserErrors });
|
|
858
|
-
|
|
859
|
-
(0, import_output.printJson)(result.productUpdate, ctx.format !== "raw");
|
|
1705
|
+
(0, import_output.printNode)({ node: result.productUpdate?.product, format: ctx.format, quiet: ctx.quiet });
|
|
860
1706
|
return;
|
|
861
1707
|
}
|
|
862
1708
|
if (verb === "update") {
|
|
863
|
-
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: {} });
|
|
864
|
-
const id = (
|
|
1709
|
+
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: { "product-id": { type: "string" } } });
|
|
1710
|
+
const id = requireProductIdForRootVerb(args);
|
|
865
1711
|
const built = (0, import_input.buildInput)({
|
|
866
1712
|
inputArg: args.input,
|
|
867
1713
|
setArgs: args.set,
|
|
@@ -869,22 +1715,31 @@ const runProducts = async ({
|
|
|
869
1715
|
});
|
|
870
1716
|
if (!built.used) throw new import_errors.CliError("Missing --input or --set/--set-json", 2);
|
|
871
1717
|
const input = { ...built.input, id };
|
|
1718
|
+
const selection = (0, import_select.resolveSelection)({
|
|
1719
|
+
resource: "products",
|
|
1720
|
+
view: ctx.view,
|
|
1721
|
+
baseSelection: getProductSelection(ctx.view),
|
|
1722
|
+
select: args.select,
|
|
1723
|
+
selection: args.selection,
|
|
1724
|
+
include: args.include,
|
|
1725
|
+
ensureId: ctx.quiet,
|
|
1726
|
+
defaultConnectionFirst: ctx.view === "all" ? 50 : 10
|
|
1727
|
+
});
|
|
872
1728
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
873
1729
|
productUpdate: {
|
|
874
1730
|
__args: { input },
|
|
875
|
-
product:
|
|
1731
|
+
product: selection,
|
|
876
1732
|
userErrors: { field: true, message: true }
|
|
877
1733
|
}
|
|
878
1734
|
});
|
|
879
1735
|
if (result === void 0) return;
|
|
880
1736
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productUpdate, failOnUserErrors: ctx.failOnUserErrors });
|
|
881
|
-
|
|
882
|
-
(0, import_output.printJson)(result.productUpdate, ctx.format !== "raw");
|
|
1737
|
+
(0, import_output.printNode)({ node: result.productUpdate?.product, format: ctx.format, quiet: ctx.quiet });
|
|
883
1738
|
return;
|
|
884
1739
|
}
|
|
885
1740
|
if (verb === "delete") {
|
|
886
|
-
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: {} });
|
|
887
|
-
const id = (
|
|
1741
|
+
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: { "product-id": { type: "string" } } });
|
|
1742
|
+
const id = requireProductIdForRootVerb(args);
|
|
888
1743
|
if (!args.yes) throw new import_errors.CliError("Refusing to delete without --yes", 2);
|
|
889
1744
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
890
1745
|
productDelete: {
|
|
@@ -900,8 +1755,8 @@ const runProducts = async ({
|
|
|
900
1755
|
return;
|
|
901
1756
|
}
|
|
902
1757
|
if (verb === "duplicate") {
|
|
903
|
-
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: {} });
|
|
904
|
-
const id = (
|
|
1758
|
+
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: { "product-id": { type: "string" } } });
|
|
1759
|
+
const id = requireProductIdForRootVerb(args);
|
|
905
1760
|
const built = (0, import_input.buildInput)({
|
|
906
1761
|
inputArg: void 0,
|
|
907
1762
|
setArgs: args.set,
|
|
@@ -920,35 +1775,53 @@ const runProducts = async ({
|
|
|
920
1775
|
newTitle,
|
|
921
1776
|
...built.used ? built.input : {}
|
|
922
1777
|
};
|
|
1778
|
+
const selection = (0, import_select.resolveSelection)({
|
|
1779
|
+
resource: "products",
|
|
1780
|
+
view: ctx.view,
|
|
1781
|
+
baseSelection: getProductSelection(ctx.view),
|
|
1782
|
+
select: args.select,
|
|
1783
|
+
selection: args.selection,
|
|
1784
|
+
include: args.include,
|
|
1785
|
+
ensureId: ctx.quiet,
|
|
1786
|
+
defaultConnectionFirst: ctx.view === "all" ? 50 : 10
|
|
1787
|
+
});
|
|
923
1788
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
924
1789
|
productDuplicate: {
|
|
925
1790
|
__args: mutationArgs,
|
|
926
|
-
newProduct:
|
|
1791
|
+
newProduct: selection,
|
|
927
1792
|
userErrors: { field: true, message: true }
|
|
928
1793
|
}
|
|
929
1794
|
});
|
|
930
1795
|
if (result === void 0) return;
|
|
931
1796
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productDuplicate, failOnUserErrors: ctx.failOnUserErrors });
|
|
932
|
-
|
|
933
|
-
(0, import_output.printJson)(result.productDuplicate, ctx.format !== "raw");
|
|
1797
|
+
(0, import_output.printNode)({ node: result.productDuplicate?.newProduct, format: ctx.format, quiet: ctx.quiet });
|
|
934
1798
|
return;
|
|
935
1799
|
}
|
|
936
1800
|
if (verb === "set-status") {
|
|
937
|
-
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: {} });
|
|
938
|
-
const id = (
|
|
1801
|
+
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: { "product-id": { type: "string" } } });
|
|
1802
|
+
const id = requireProductIdForRootVerb(args);
|
|
939
1803
|
const status = args.status;
|
|
940
1804
|
if (!status) throw new import_errors.CliError("Missing --status (ACTIVE|DRAFT|ARCHIVED)", 2);
|
|
1805
|
+
const selection = (0, import_select.resolveSelection)({
|
|
1806
|
+
resource: "products",
|
|
1807
|
+
view: ctx.view,
|
|
1808
|
+
baseSelection: getProductSelection(ctx.view),
|
|
1809
|
+
select: args.select,
|
|
1810
|
+
selection: args.selection,
|
|
1811
|
+
include: args.include,
|
|
1812
|
+
ensureId: ctx.quiet,
|
|
1813
|
+
defaultConnectionFirst: ctx.view === "all" ? 50 : 10
|
|
1814
|
+
});
|
|
941
1815
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
942
1816
|
productUpdate: {
|
|
943
1817
|
__args: { input: { id, status } },
|
|
944
|
-
product:
|
|
1818
|
+
product: selection,
|
|
945
1819
|
userErrors: { field: true, message: true }
|
|
946
1820
|
}
|
|
947
1821
|
});
|
|
948
1822
|
if (result === void 0) return;
|
|
949
1823
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productUpdate, failOnUserErrors: ctx.failOnUserErrors });
|
|
950
|
-
|
|
951
|
-
(0, import_output.printJson)(result.productUpdate, ctx.format !== "raw");
|
|
1824
|
+
(0, import_output.printNode)({ node: result.productUpdate?.product, format: ctx.format, quiet: ctx.quiet });
|
|
952
1825
|
return;
|
|
953
1826
|
}
|
|
954
1827
|
if (verb === "set-price") {
|
|
@@ -961,7 +1834,7 @@ const runProducts = async ({
|
|
|
961
1834
|
"product-id": { type: "string" }
|
|
962
1835
|
}
|
|
963
1836
|
});
|
|
964
|
-
const variantId = (0, import_shared.requireId)(args["variant-id"], "ProductVariant");
|
|
1837
|
+
const variantId = (0, import_shared.requireId)(args["variant-id"], "ProductVariant", "--variant-id");
|
|
965
1838
|
const price = args.price;
|
|
966
1839
|
if (!price) throw new import_errors.CliError("Missing --price", 2);
|
|
967
1840
|
const compareAtPrice = args["compare-at-price"];
|
|
@@ -984,6 +1857,16 @@ const runProducts = async ({
|
|
|
984
1857
|
if (!pid) throw new import_errors.CliError("Could not resolve productId from --variant-id", 2);
|
|
985
1858
|
productId = pid;
|
|
986
1859
|
}
|
|
1860
|
+
const variantSelection = (0, import_select.resolveSelection)({
|
|
1861
|
+
typeName: "ProductVariant",
|
|
1862
|
+
view: ctx.view,
|
|
1863
|
+
baseSelection: getProductVariantSelection(ctx.view),
|
|
1864
|
+
select: args.select,
|
|
1865
|
+
selection: args.selection,
|
|
1866
|
+
include: args.include,
|
|
1867
|
+
ensureId: ctx.quiet,
|
|
1868
|
+
defaultConnectionFirst: ctx.view === "all" ? 50 : 10
|
|
1869
|
+
});
|
|
987
1870
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
988
1871
|
productVariantsBulkUpdate: {
|
|
989
1872
|
__args: {
|
|
@@ -996,7 +1879,8 @@ const runProducts = async ({
|
|
|
996
1879
|
}
|
|
997
1880
|
]
|
|
998
1881
|
},
|
|
999
|
-
userErrors: { field: true, message: true }
|
|
1882
|
+
userErrors: { field: true, message: true },
|
|
1883
|
+
productVariants: variantSelection
|
|
1000
1884
|
}
|
|
1001
1885
|
});
|
|
1002
1886
|
if (result === void 0) return;
|
|
@@ -1004,19 +1888,29 @@ const runProducts = async ({
|
|
|
1004
1888
|
payload: result.productVariantsBulkUpdate,
|
|
1005
1889
|
failOnUserErrors: ctx.failOnUserErrors
|
|
1006
1890
|
});
|
|
1007
|
-
|
|
1008
|
-
(0, import_output.
|
|
1891
|
+
const variant = result.productVariantsBulkUpdate?.productVariants?.[0];
|
|
1892
|
+
(0, import_output.printNode)({ node: variant, format: ctx.format, quiet: ctx.quiet });
|
|
1009
1893
|
return;
|
|
1010
1894
|
}
|
|
1011
1895
|
if (verb === "add-tags" || verb === "remove-tags") {
|
|
1012
|
-
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: {} });
|
|
1013
|
-
const id = (
|
|
1896
|
+
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: { "product-id": { type: "string" } } });
|
|
1897
|
+
const id = requireProductIdForRootVerb(args);
|
|
1014
1898
|
const tags = parseTags(args.tags);
|
|
1015
1899
|
const mutationField = verb === "add-tags" ? "tagsAdd" : "tagsRemove";
|
|
1900
|
+
const nodeSelection = (0, import_select.resolveSelection)({
|
|
1901
|
+
typeName: "Product",
|
|
1902
|
+
view: ctx.view,
|
|
1903
|
+
baseSelection: getProductSelectionForTags(ctx.view),
|
|
1904
|
+
select: args.select,
|
|
1905
|
+
selection: args.selection,
|
|
1906
|
+
include: args.include,
|
|
1907
|
+
ensureId: ctx.quiet,
|
|
1908
|
+
defaultConnectionFirst: ctx.view === "all" ? 50 : 10
|
|
1909
|
+
});
|
|
1016
1910
|
const request = {
|
|
1017
1911
|
[mutationField]: {
|
|
1018
1912
|
__args: { id, tags },
|
|
1019
|
-
node: {
|
|
1913
|
+
node: { __typename: true, on_Product: nodeSelection },
|
|
1020
1914
|
userErrors: { field: true, message: true }
|
|
1021
1915
|
}
|
|
1022
1916
|
};
|
|
@@ -1024,91 +1918,240 @@ const runProducts = async ({
|
|
|
1024
1918
|
if (result === void 0) return;
|
|
1025
1919
|
const payload = result[mutationField];
|
|
1026
1920
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload, failOnUserErrors: ctx.failOnUserErrors });
|
|
1027
|
-
|
|
1028
|
-
(0, import_output.printJson)(payload, ctx.format !== "raw");
|
|
1921
|
+
(0, import_output.printNode)({ node: payload?.node, format: ctx.format, quiet: ctx.quiet });
|
|
1029
1922
|
return;
|
|
1030
1923
|
}
|
|
1031
1924
|
if (verb === "media add") {
|
|
1032
1925
|
const args = (0, import_router.parseStandardArgs)({
|
|
1033
1926
|
argv,
|
|
1034
1927
|
extraOptions: {
|
|
1928
|
+
"product-id": { type: "string" },
|
|
1035
1929
|
url: { type: "string", multiple: true },
|
|
1036
1930
|
alt: { type: "string" },
|
|
1037
|
-
"media-type": { type: "string" }
|
|
1931
|
+
"media-type": { type: "string" },
|
|
1932
|
+
"media-content-type": { type: "string" },
|
|
1933
|
+
wait: { type: "boolean" },
|
|
1934
|
+
"poll-interval-ms": { type: "string" },
|
|
1935
|
+
"timeout-ms": { type: "string" }
|
|
1038
1936
|
}
|
|
1039
1937
|
});
|
|
1040
|
-
const
|
|
1938
|
+
const productId = requireProductIdForSubverb(args);
|
|
1041
1939
|
const urls = args.url ?? [];
|
|
1042
1940
|
if (urls.length === 0) throw new import_errors.CliError("Missing --url (repeatable)", 2);
|
|
1043
|
-
const
|
|
1941
|
+
const mediaContentTypeRaw = args["media-content-type"];
|
|
1942
|
+
const mediaTypeRaw = args["media-type"];
|
|
1943
|
+
if (mediaContentTypeRaw && mediaTypeRaw) {
|
|
1944
|
+
const a = mediaContentTypeRaw.trim().toUpperCase();
|
|
1945
|
+
const b = mediaTypeRaw.trim().toUpperCase();
|
|
1946
|
+
if (a && b && a !== b) {
|
|
1947
|
+
throw new import_errors.CliError("Do not pass both --media-content-type and --media-type with different values", 2);
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
const mediaContentType = normalizeMediaContentType(mediaContentTypeRaw ?? mediaTypeRaw);
|
|
1044
1951
|
const alt = args.alt;
|
|
1952
|
+
const wait = args.wait === true;
|
|
1953
|
+
const pollIntervalMs = parsePositiveIntFlag({ value: args["poll-interval-ms"], flag: "--poll-interval-ms" }) ?? 1e3;
|
|
1954
|
+
const timeoutMs = parsePositiveIntFlag({ value: args["timeout-ms"], flag: "--timeout-ms" }) ?? 10 * 60 * 1e3;
|
|
1955
|
+
const shouldWait = wait && !ctx.dryRun;
|
|
1956
|
+
const beforeIds = shouldWait ? await getTopProductMediaIds({ ctx, productId }) : [];
|
|
1045
1957
|
const media = urls.map((url) => ({
|
|
1046
1958
|
originalSource: url,
|
|
1047
1959
|
mediaContentType,
|
|
1048
1960
|
...alt ? { alt } : {}
|
|
1049
1961
|
}));
|
|
1962
|
+
const viewForSelection = ctx.view === "all" ? "full" : ctx.view;
|
|
1963
|
+
const nodeSelection = (0, import_select.resolveSelection)({
|
|
1964
|
+
typeName: "Media",
|
|
1965
|
+
view: viewForSelection,
|
|
1966
|
+
baseSelection: getProductMediaSelection(viewForSelection),
|
|
1967
|
+
select: args.select,
|
|
1968
|
+
selection: args.selection,
|
|
1969
|
+
include: args.include,
|
|
1970
|
+
ensureId: ctx.quiet,
|
|
1971
|
+
defaultConnectionFirst: 10
|
|
1972
|
+
});
|
|
1050
1973
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
1051
1974
|
productUpdate: {
|
|
1052
|
-
__args: { product: { id }, media },
|
|
1053
|
-
product:
|
|
1975
|
+
__args: { product: { id: productId }, media },
|
|
1976
|
+
product: {
|
|
1977
|
+
id: true,
|
|
1978
|
+
media: {
|
|
1979
|
+
__args: { last: media.length, sortKey: "POSITION" },
|
|
1980
|
+
nodes: nodeSelection
|
|
1981
|
+
}
|
|
1982
|
+
},
|
|
1054
1983
|
userErrors: { field: true, message: true }
|
|
1055
1984
|
}
|
|
1056
1985
|
});
|
|
1057
1986
|
if (result === void 0) return;
|
|
1058
1987
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productUpdate, failOnUserErrors: ctx.failOnUserErrors });
|
|
1059
|
-
if (
|
|
1060
|
-
|
|
1988
|
+
if (!shouldWait) {
|
|
1989
|
+
const connection = result.productUpdate?.product?.media ?? { nodes: [], pageInfo: void 0 };
|
|
1990
|
+
(0, import_output.printConnection)({ connection, format: ctx.format, quiet: ctx.quiet });
|
|
1991
|
+
return;
|
|
1992
|
+
}
|
|
1993
|
+
const afterIds = await getTopProductMediaIds({ ctx, productId });
|
|
1994
|
+
const before = new Set(beforeIds);
|
|
1995
|
+
const createdIds = afterIds.filter((mid) => !before.has(mid)).slice(0, urls.length);
|
|
1996
|
+
if (createdIds.length !== urls.length) {
|
|
1997
|
+
throw new import_errors.CliError(
|
|
1998
|
+
`Unable to determine created media IDs for waiting (expected ${urls.length}, got ${createdIds.length}).`,
|
|
1999
|
+
2
|
|
2000
|
+
);
|
|
2001
|
+
}
|
|
2002
|
+
const final = await (0, import_waitForReady.waitForFilesReadyOrFailed)({ ctx, ids: createdIds, pollIntervalMs, timeoutMs });
|
|
2003
|
+
if (ctx.quiet) {
|
|
2004
|
+
for (const mid of createdIds) console.log(mid);
|
|
2005
|
+
} else {
|
|
2006
|
+
(0, import_output.printConnection)({
|
|
2007
|
+
connection: { nodes: final.nodes, pageInfo: void 0 },
|
|
2008
|
+
format: ctx.format,
|
|
2009
|
+
quiet: false
|
|
2010
|
+
});
|
|
2011
|
+
}
|
|
2012
|
+
if (final.failedIds.length > 0) {
|
|
2013
|
+
throw new import_errors.CliError(`One or more media files failed processing: ${final.failedIds.join(", ")}`, 2);
|
|
2014
|
+
}
|
|
1061
2015
|
return;
|
|
1062
2016
|
}
|
|
1063
2017
|
if (verb === "media upload") {
|
|
1064
2018
|
const args = (0, import_router.parseStandardArgs)({
|
|
1065
2019
|
argv,
|
|
1066
2020
|
extraOptions: {
|
|
2021
|
+
"product-id": { type: "string" },
|
|
1067
2022
|
file: { type: "string", multiple: true },
|
|
2023
|
+
filename: { type: "string" },
|
|
1068
2024
|
alt: { type: "string" },
|
|
1069
2025
|
"content-type": { type: "string" },
|
|
1070
|
-
"
|
|
2026
|
+
"mime-type": { type: "string" },
|
|
2027
|
+
"media-type": { type: "string" },
|
|
2028
|
+
"media-content-type": { type: "string" },
|
|
2029
|
+
wait: { type: "boolean" },
|
|
2030
|
+
"poll-interval-ms": { type: "string" },
|
|
2031
|
+
"timeout-ms": { type: "string" }
|
|
1071
2032
|
}
|
|
1072
2033
|
});
|
|
1073
|
-
const id = (
|
|
2034
|
+
const id = requireProductIdForSubverb(args);
|
|
1074
2035
|
const filePaths = args.file ?? [];
|
|
1075
2036
|
if (filePaths.length === 0) throw new import_errors.CliError("Missing --file (repeatable)", 2);
|
|
1076
|
-
const
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
const media = targets.map((t, i) => {
|
|
1088
|
-
const local = localFiles[i];
|
|
1089
|
-
if (!t.resourceUrl) throw new import_errors.CliError(`Missing staged target resourceUrl for ${local.filename}`, 2);
|
|
1090
|
-
return {
|
|
1091
|
-
originalSource: t.resourceUrl,
|
|
1092
|
-
mediaContentType: forced ?? stagedResourceToMediaType(local.resource),
|
|
1093
|
-
...alt ? { alt } : {}
|
|
1094
|
-
};
|
|
1095
|
-
});
|
|
1096
|
-
const result = await (0, import_router.runMutation)(ctx, {
|
|
1097
|
-
productUpdate: {
|
|
1098
|
-
__args: { product: { id }, media },
|
|
1099
|
-
product: productSummarySelection,
|
|
1100
|
-
userErrors: { field: true, message: true }
|
|
2037
|
+
const usesStdin = filePaths.includes("-");
|
|
2038
|
+
if (usesStdin && filePaths.length !== 1) {
|
|
2039
|
+
throw new import_errors.CliError("When using --file -, provide exactly one --file", 2);
|
|
2040
|
+
}
|
|
2041
|
+
let cleanupStdin;
|
|
2042
|
+
try {
|
|
2043
|
+
let effectiveFilePaths = filePaths;
|
|
2044
|
+
if (usesStdin) {
|
|
2045
|
+
const stdinFile = await (0, import_stdinFile.writeStdinToTempFile)({ filename: args.filename ?? "" });
|
|
2046
|
+
cleanupStdin = stdinFile.cleanup;
|
|
2047
|
+
effectiveFilePaths = [stdinFile.filePath];
|
|
1101
2048
|
}
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
2049
|
+
const mediaContentTypeRaw = args["media-content-type"];
|
|
2050
|
+
const mediaTypeRaw = args["media-type"];
|
|
2051
|
+
if (mediaContentTypeRaw && mediaTypeRaw) {
|
|
2052
|
+
const a = mediaContentTypeRaw.trim().toUpperCase();
|
|
2053
|
+
const b = mediaTypeRaw.trim().toUpperCase();
|
|
2054
|
+
if (a && b && a !== b) {
|
|
2055
|
+
throw new import_errors.CliError("Do not pass both --media-content-type and --media-type with different values", 2);
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
const forcedMediaType = mediaContentTypeRaw ?? mediaTypeRaw;
|
|
2059
|
+
const forced = forcedMediaType ? normalizeMediaContentType(forcedMediaType) : void 0;
|
|
2060
|
+
const resourceOverride = forced ? mediaTypeToStagedResource(forced) : void 0;
|
|
2061
|
+
const mimeTypeRaw = args["mime-type"];
|
|
2062
|
+
const contentTypeRaw = args["content-type"];
|
|
2063
|
+
if (mimeTypeRaw && contentTypeRaw) {
|
|
2064
|
+
const a = mimeTypeRaw.trim();
|
|
2065
|
+
const b = contentTypeRaw.trim();
|
|
2066
|
+
if (a && b && a !== b) {
|
|
2067
|
+
throw new import_errors.CliError("Do not pass both --mime-type and --content-type with different values", 2);
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
const mimeType = mimeTypeRaw ?? contentTypeRaw;
|
|
2071
|
+
const wait = args.wait === true;
|
|
2072
|
+
const pollIntervalMs = parsePositiveIntFlag({ value: args["poll-interval-ms"], flag: "--poll-interval-ms" }) ?? 1e3;
|
|
2073
|
+
const timeoutMs = parsePositiveIntFlag({ value: args["timeout-ms"], flag: "--timeout-ms" }) ?? 10 * 60 * 1e3;
|
|
2074
|
+
const shouldWait = wait && !ctx.dryRun;
|
|
2075
|
+
const beforeIds = shouldWait ? await getTopProductMediaIds({ ctx, productId: id }) : [];
|
|
2076
|
+
const localFiles = await (0, import_stagedUploads.buildLocalFilesForStagedUpload)({
|
|
2077
|
+
filePaths: effectiveFilePaths,
|
|
2078
|
+
mimeType,
|
|
2079
|
+
resource: resourceOverride
|
|
2080
|
+
});
|
|
2081
|
+
const targets = await (0, import_stagedUploads.stagedUploadLocalFiles)(ctx, localFiles);
|
|
2082
|
+
if (targets === void 0) return;
|
|
2083
|
+
const alt = args.alt;
|
|
2084
|
+
const media = targets.map((t, i) => {
|
|
2085
|
+
const local = localFiles[i];
|
|
2086
|
+
if (!t.resourceUrl) throw new import_errors.CliError(`Missing staged target resourceUrl for ${local.filename}`, 2);
|
|
2087
|
+
return {
|
|
2088
|
+
originalSource: t.resourceUrl,
|
|
2089
|
+
mediaContentType: forced ?? stagedResourceToMediaType(local.resource),
|
|
2090
|
+
...alt ? { alt } : {}
|
|
2091
|
+
};
|
|
2092
|
+
});
|
|
2093
|
+
const viewForSelection = ctx.view === "all" ? "full" : ctx.view;
|
|
2094
|
+
const nodeSelection = (0, import_select.resolveSelection)({
|
|
2095
|
+
typeName: "Media",
|
|
2096
|
+
view: viewForSelection,
|
|
2097
|
+
baseSelection: getProductMediaSelection(viewForSelection),
|
|
2098
|
+
select: args.select,
|
|
2099
|
+
selection: args.selection,
|
|
2100
|
+
include: args.include,
|
|
2101
|
+
ensureId: ctx.quiet,
|
|
2102
|
+
defaultConnectionFirst: 10
|
|
2103
|
+
});
|
|
2104
|
+
const result = await (0, import_router.runMutation)(ctx, {
|
|
2105
|
+
productUpdate: {
|
|
2106
|
+
__args: { product: { id }, media },
|
|
2107
|
+
product: {
|
|
2108
|
+
id: true,
|
|
2109
|
+
media: {
|
|
2110
|
+
__args: { last: media.length, sortKey: "POSITION" },
|
|
2111
|
+
nodes: nodeSelection
|
|
2112
|
+
}
|
|
2113
|
+
},
|
|
2114
|
+
userErrors: { field: true, message: true }
|
|
2115
|
+
}
|
|
2116
|
+
});
|
|
2117
|
+
if (result === void 0) return;
|
|
2118
|
+
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.productUpdate, failOnUserErrors: ctx.failOnUserErrors });
|
|
2119
|
+
const connection = result.productUpdate?.product?.media ?? { nodes: [], pageInfo: void 0 };
|
|
2120
|
+
if (!shouldWait) {
|
|
2121
|
+
(0, import_output.printConnection)({ connection, format: ctx.format, quiet: ctx.quiet });
|
|
2122
|
+
return;
|
|
2123
|
+
}
|
|
2124
|
+
const afterIds = await getTopProductMediaIds({ ctx, productId: id });
|
|
2125
|
+
const before = new Set(beforeIds);
|
|
2126
|
+
const expectedCount = localFiles.length;
|
|
2127
|
+
const createdIds = afterIds.filter((mid) => !before.has(mid)).slice(0, expectedCount);
|
|
2128
|
+
if (createdIds.length !== expectedCount) {
|
|
2129
|
+
throw new import_errors.CliError(
|
|
2130
|
+
`Unable to determine created media IDs for waiting (expected ${expectedCount}, got ${createdIds.length}).`,
|
|
2131
|
+
2
|
|
2132
|
+
);
|
|
2133
|
+
}
|
|
2134
|
+
const final = await (0, import_waitForReady.waitForFilesReadyOrFailed)({ ctx, ids: createdIds, pollIntervalMs, timeoutMs });
|
|
2135
|
+
if (ctx.quiet) {
|
|
2136
|
+
for (const mid of createdIds) console.log(mid);
|
|
2137
|
+
} else {
|
|
2138
|
+
(0, import_output.printConnection)({
|
|
2139
|
+
connection: { nodes: final.nodes, pageInfo: void 0 },
|
|
2140
|
+
format: ctx.format,
|
|
2141
|
+
quiet: false
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
if (final.failedIds.length > 0) {
|
|
2145
|
+
throw new import_errors.CliError(`One or more media files failed processing: ${final.failedIds.join(", ")}`, 2);
|
|
2146
|
+
}
|
|
2147
|
+
return;
|
|
2148
|
+
} finally {
|
|
2149
|
+
if (cleanupStdin) await cleanupStdin();
|
|
2150
|
+
}
|
|
1108
2151
|
}
|
|
1109
2152
|
if (verb === "media list") {
|
|
1110
|
-
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: {} });
|
|
1111
|
-
const id = (
|
|
2153
|
+
const args = (0, import_router.parseStandardArgs)({ argv, extraOptions: { "product-id": { type: "string" } } });
|
|
2154
|
+
const id = requireProductIdForSubverb(args);
|
|
1112
2155
|
const first = (0, import_shared.parseFirst)(args.first);
|
|
1113
2156
|
const after = args.after;
|
|
1114
2157
|
const result = await (0, import_router.runQuery)(ctx, {
|
|
@@ -1130,7 +2173,7 @@ const runProducts = async ({
|
|
|
1130
2173
|
nextPageArgs: {
|
|
1131
2174
|
base: "shop products media list",
|
|
1132
2175
|
first,
|
|
1133
|
-
extraFlags: [{ flag: "--id", value: id }]
|
|
2176
|
+
extraFlags: [{ flag: "--product-id", value: id }]
|
|
1134
2177
|
}
|
|
1135
2178
|
});
|
|
1136
2179
|
return;
|
|
@@ -1139,10 +2182,11 @@ const runProducts = async ({
|
|
|
1139
2182
|
const args = (0, import_router.parseStandardArgs)({
|
|
1140
2183
|
argv,
|
|
1141
2184
|
extraOptions: {
|
|
2185
|
+
"product-id": { type: "string" },
|
|
1142
2186
|
"media-id": { type: "string", multiple: true }
|
|
1143
2187
|
}
|
|
1144
2188
|
});
|
|
1145
|
-
const productId = (
|
|
2189
|
+
const productId = requireProductIdForSubverb(args);
|
|
1146
2190
|
const mediaIds = args["media-id"] ?? [];
|
|
1147
2191
|
if (mediaIds.length === 0) throw new import_errors.CliError("Missing --media-id (repeatable)", 2);
|
|
1148
2192
|
const files = mediaIds.map((id) => ({
|
|
@@ -1158,8 +2202,15 @@ const runProducts = async ({
|
|
|
1158
2202
|
});
|
|
1159
2203
|
if (result === void 0) return;
|
|
1160
2204
|
(0, import_userErrors.maybeFailOnUserErrors)({ payload: result.fileUpdate, failOnUserErrors: ctx.failOnUserErrors });
|
|
1161
|
-
|
|
1162
|
-
(0, import_output.
|
|
2205
|
+
const removedMediaIds = (result.fileUpdate?.files ?? []).map((f) => typeof f?.id === "string" ? f.id : void 0).filter((id) => typeof id === "string" && id.trim() !== "");
|
|
2206
|
+
if (ctx.quiet) return (0, import_output.printIds)(removedMediaIds);
|
|
2207
|
+
(0, import_output.printJson)(
|
|
2208
|
+
{
|
|
2209
|
+
productId,
|
|
2210
|
+
removedMediaIds
|
|
2211
|
+
},
|
|
2212
|
+
ctx.format !== "raw"
|
|
2213
|
+
);
|
|
1163
2214
|
return;
|
|
1164
2215
|
}
|
|
1165
2216
|
if (verb === "media update") {
|
|
@@ -1192,11 +2243,12 @@ const runProducts = async ({
|
|
|
1192
2243
|
const args = (0, import_router.parseStandardArgs)({
|
|
1193
2244
|
argv,
|
|
1194
2245
|
extraOptions: {
|
|
2246
|
+
"product-id": { type: "string" },
|
|
1195
2247
|
moves: { type: "string" },
|
|
1196
2248
|
move: { type: "string", multiple: true }
|
|
1197
2249
|
}
|
|
1198
2250
|
});
|
|
1199
|
-
const id = (
|
|
2251
|
+
const id = requireProductIdForSubverb(args);
|
|
1200
2252
|
let moves = [];
|
|
1201
2253
|
if (args.moves) {
|
|
1202
2254
|
try {
|