shop-cli 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -7
- package/dist/cli/gid.d.ts +13 -2
- package/dist/cli/gid.js +75 -7
- package/dist/cli/globalFlags.d.ts +1 -0
- package/dist/cli/globalFlags.js +4 -0
- package/dist/cli/help/registry.js +188 -182
- package/dist/cli/help/render.js +7 -3
- package/dist/cli/verbs/_shared.js +4 -4
- package/dist/cli/verbs/files.js +11 -2
- package/dist/cli/verbs/mobile-platform-applications.js +4 -2
- package/dist/cli/verbs/products.js +8 -7
- package/dist/cli/verbs/publishables.js +1 -1
- package/dist/cli.js +3 -0
- package/package.json +1 -1
package/dist/cli/help/render.js
CHANGED
|
@@ -216,6 +216,10 @@ const renderTopLevelHelp = (command = (0, import_command.resolveCliCommand)()) =
|
|
|
216
216
|
" --selection <graphql> (selection override; can be @file.gql)",
|
|
217
217
|
" --quiet (IDs only when possible)",
|
|
218
218
|
"",
|
|
219
|
+
"IDs:",
|
|
220
|
+
" By default, many flags accept numeric IDs and will coerce them to gid://shopify/... IDs.",
|
|
221
|
+
" --strict-ids (or env SHOP_CLI_STRICT_IDS=1; require full gid://shopify/... IDs)",
|
|
222
|
+
"",
|
|
219
223
|
"Debug:",
|
|
220
224
|
" --dry-run (print GraphQL op + variables, do not execute)",
|
|
221
225
|
" --no-fail-on-user-errors (do not exit non-zero on userErrors)",
|
|
@@ -234,10 +238,10 @@ const renderTopLevelHelp = (command = (0, import_command.resolveCliCommand)()) =
|
|
|
234
238
|
` ${command} products list --first 5 --format table`,
|
|
235
239
|
` ${command} products get --id gid://shopify/Product/123 --format markdown`,
|
|
236
240
|
` ${command} products create --set title="Hat" --set status="ACTIVE"`,
|
|
237
|
-
` ${command} products add-tags --id 123 --tags "summer,featured"`,
|
|
241
|
+
` ${command} products add-tags --id gid://shopify/Product/123 --tags "summer,featured"`,
|
|
238
242
|
` ${command} publications resolve --publication "Online Store"`,
|
|
239
|
-
` ${command} products publish --id 123 --publication "Online Store" --now`,
|
|
240
|
-
` ${command} products metafields upsert --id 123 --set namespace=custom --set key=foo --set type=single_line_text_field --set value=bar`
|
|
243
|
+
` ${command} products publish --id gid://shopify/Product/123 --publication "Online Store" --now`,
|
|
244
|
+
` ${command} products metafields upsert --id gid://shopify/Product/123 --set namespace=custom --set key=foo --set type=single_line_text_field --set value=bar`
|
|
241
245
|
].join("\n");
|
|
242
246
|
};
|
|
243
247
|
const renderResourceHelp = (resource, command = (0, import_command.resolveCliCommand)()) => {
|
|
@@ -55,11 +55,11 @@ const parseIntFlag = (flag, value) => {
|
|
|
55
55
|
const requireId = (id, type, flag = "--id") => {
|
|
56
56
|
const normalized = typeof id === "string" ? id : typeof id === "number" && Number.isFinite(id) ? String(id) : void 0;
|
|
57
57
|
if (!normalized) throw new import_errors.CliError(`Missing ${flag}`, 2);
|
|
58
|
-
return (0, import_gid.coerceGid)(normalized, type);
|
|
58
|
+
return (0, import_gid.coerceGid)(normalized, type, flag);
|
|
59
59
|
};
|
|
60
60
|
const requireGidFlag = (value, flag, type) => {
|
|
61
61
|
if (typeof value !== "string" || !value) throw new import_errors.CliError(`Missing ${flag}`, 2);
|
|
62
|
-
return (0, import_gid.coerceGid)(value, type);
|
|
62
|
+
return (0, import_gid.coerceGid)(value, type, flag);
|
|
63
63
|
};
|
|
64
64
|
const requireStringFlag = (value, flag) => {
|
|
65
65
|
if (typeof value !== "string" || !value) throw new import_errors.CliError(`Missing ${flag}`, 2);
|
|
@@ -67,7 +67,7 @@ const requireStringFlag = (value, flag) => {
|
|
|
67
67
|
};
|
|
68
68
|
const requireLocationId = (value, flag = "--location-id") => {
|
|
69
69
|
if (typeof value !== "string" || !value) throw new import_errors.CliError(`Missing ${flag}`, 2);
|
|
70
|
-
return (0, import_gid.coerceGid)(value, "Location");
|
|
70
|
+
return (0, import_gid.coerceGid)(value, "Location", flag);
|
|
71
71
|
};
|
|
72
72
|
const parseDateTime = (value, flag) => {
|
|
73
73
|
if (typeof value !== "string" || !value) throw new import_errors.CliError(`Missing ${flag}`, 2);
|
|
@@ -87,7 +87,7 @@ const parseIds = (value, type) => {
|
|
|
87
87
|
parts.push(...v.split(",").map((s) => s.trim()).filter(Boolean));
|
|
88
88
|
}
|
|
89
89
|
if (parts.length === 0) throw new import_errors.CliError("Missing --ids", 2);
|
|
90
|
-
return parts.map((id) => (0, import_gid.coerceGid)(id, type));
|
|
90
|
+
return parts.map((id) => (0, import_gid.coerceGid)(id, type, "--ids"));
|
|
91
91
|
};
|
|
92
92
|
const readUtf8 = (path) => (0, import_node_fs.readFileSync)(path, "utf8");
|
|
93
93
|
const parseJson = (value, label) => {
|
package/dist/cli/verbs/files.js
CHANGED
|
@@ -22,6 +22,7 @@ __export(files_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(files_exports);
|
|
24
24
|
var import_errors = require("../errors");
|
|
25
|
+
var import_gid = require("../gid");
|
|
25
26
|
var import_router = require("../router");
|
|
26
27
|
var import_userErrors = require("../userErrors");
|
|
27
28
|
var import_stagedUploads = require("../workflows/files/stagedUploads");
|
|
@@ -123,8 +124,16 @@ const runFiles = async ({
|
|
|
123
124
|
if (!raw) throw new import_errors.CliError("Missing --id", 2);
|
|
124
125
|
const trimmed = raw.trim();
|
|
125
126
|
if (!trimmed) throw new import_errors.CliError("Missing --id", 2);
|
|
126
|
-
const query = trimmed.startsWith("gid://") ? `ids:${trimmed}` : /^\d+$/.test(trimmed) ?
|
|
127
|
-
|
|
127
|
+
const query = trimmed.startsWith("gid://") ? `ids:${trimmed}` : /^\d+$/.test(trimmed) ? (() => {
|
|
128
|
+
if ((0, import_gid.isStrictIdsMode)()) {
|
|
129
|
+
throw new import_errors.CliError(
|
|
130
|
+
"--id must be a full Shopify GID (gid://shopify/...). Strict IDs mode is enabled (SHOP_CLI_STRICT_IDS or --strict-ids).",
|
|
131
|
+
2
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
return `id:${trimmed}`;
|
|
135
|
+
})() : (() => {
|
|
136
|
+
throw new import_errors.CliError("--id must be a full Shopify GID (gid://shopify/...)", 2);
|
|
128
137
|
})();
|
|
129
138
|
const result = await (0, import_router.runQuery)(ctx, {
|
|
130
139
|
files: { __args: { first: 1, query }, nodes: fileSelection }
|
|
@@ -67,9 +67,11 @@ const getMobilePlatformApplicationSelection = (view) => {
|
|
|
67
67
|
const extractUnionId = (node) => node?.on_AndroidApplication?.id ?? node?.on_AppleApplication?.id;
|
|
68
68
|
const normalizeMobileAppId = (raw, platform) => {
|
|
69
69
|
if (typeof raw !== "string" || !raw) throw new import_errors.CliError("Missing --id", 2);
|
|
70
|
-
|
|
71
|
-
const p = (platform ?? "android").trim().toLowerCase();
|
|
70
|
+
const p = platform?.trim().toLowerCase();
|
|
72
71
|
const type = p === "apple" || p === "ios" ? "AppleApplication" : "AndroidApplication";
|
|
72
|
+
if (raw.startsWith("gid://")) {
|
|
73
|
+
return p ? (0, import_gid.coerceGid)(raw, type, "--id") : raw;
|
|
74
|
+
}
|
|
73
75
|
return (0, import_gid.coerceGid)(raw, type);
|
|
74
76
|
};
|
|
75
77
|
const runMobilePlatformApplications = async ({
|
|
@@ -228,10 +228,11 @@ const getTopProductMediaIds = async ({
|
|
|
228
228
|
const nodes = result.product?.media?.nodes ?? [];
|
|
229
229
|
return nodes.map((n) => typeof n?.id === "string" ? n.id : void 0).filter((id) => typeof id === "string" && id.trim() !== "");
|
|
230
230
|
};
|
|
231
|
-
const
|
|
231
|
+
const allowedMediaGidTypes = ["MediaImage", "Video", "ExternalVideo", "Model3d"];
|
|
232
|
+
const normalizeMediaId = (value, label = "Media ID") => {
|
|
232
233
|
const raw = value.trim();
|
|
233
|
-
if (!raw) throw new import_errors.CliError(
|
|
234
|
-
if (raw.startsWith("gid://")) return raw;
|
|
234
|
+
if (!raw) throw new import_errors.CliError(`${label} cannot be empty`, 2);
|
|
235
|
+
if (raw.startsWith("gid://")) return (0, import_gid.assertShopifyGidTypeIn)(raw, allowedMediaGidTypes, label);
|
|
235
236
|
throw new import_errors.CliError(
|
|
236
237
|
`Numeric media ID "${raw}" is ambiguous. Use the full GID from "shop products media list" (e.g. gid://shopify/MediaImage/${raw})`,
|
|
237
238
|
2
|
|
@@ -2190,7 +2191,7 @@ Missing <verb> for "products ${verb}"`, 2);
|
|
|
2190
2191
|
const mediaIds = args["media-id"] ?? [];
|
|
2191
2192
|
if (mediaIds.length === 0) throw new import_errors.CliError("Missing --media-id (repeatable)", 2);
|
|
2192
2193
|
const files = mediaIds.map((id) => ({
|
|
2193
|
-
id: normalizeMediaId(id),
|
|
2194
|
+
id: normalizeMediaId(id, "--media-id"),
|
|
2194
2195
|
referencesToRemove: [productId]
|
|
2195
2196
|
}));
|
|
2196
2197
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
@@ -2225,7 +2226,7 @@ Missing <verb> for "products ${verb}"`, 2);
|
|
|
2225
2226
|
if (!mediaIdRaw) throw new import_errors.CliError("Missing --media-id", 2);
|
|
2226
2227
|
const alt = args.alt;
|
|
2227
2228
|
if (alt === void 0) throw new import_errors.CliError("Missing --alt", 2);
|
|
2228
|
-
const files = [{ id: normalizeMediaId(mediaIdRaw), alt }];
|
|
2229
|
+
const files = [{ id: normalizeMediaId(mediaIdRaw, "--media-id"), alt }];
|
|
2229
2230
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
2230
2231
|
fileUpdate: {
|
|
2231
2232
|
__args: { files },
|
|
@@ -2268,7 +2269,7 @@ Missing <verb> for "products ${verb}"`, 2);
|
|
|
2268
2269
|
const pos = Number(item.slice(idx + 1).trim());
|
|
2269
2270
|
if (!mediaId) throw new import_errors.CliError("--move mediaId cannot be empty", 2);
|
|
2270
2271
|
if (!Number.isFinite(pos) || pos < 0) throw new import_errors.CliError("--move newPosition must be a non-negative number", 2);
|
|
2271
|
-
parsedMoves.push({ id: normalizeMediaId(mediaId), newPosition: String(Math.floor(pos)) });
|
|
2272
|
+
parsedMoves.push({ id: normalizeMediaId(mediaId, "--move mediaId"), newPosition: String(Math.floor(pos)) });
|
|
2272
2273
|
}
|
|
2273
2274
|
moves = parsedMoves;
|
|
2274
2275
|
}
|
|
@@ -2285,7 +2286,7 @@ Missing <verb> for "products ${verb}"`, 2);
|
|
|
2285
2286
|
if (!Number.isFinite(pos) || pos < 0) {
|
|
2286
2287
|
throw new import_errors.CliError(`moves[${i}].newPosition must be a non-negative number`, 2);
|
|
2287
2288
|
}
|
|
2288
|
-
return { id: normalizeMediaId(id2), newPosition: String(Math.floor(pos)) };
|
|
2289
|
+
return { id: normalizeMediaId(id2, `moves[${i}].id`), newPosition: String(Math.floor(pos)) };
|
|
2289
2290
|
});
|
|
2290
2291
|
const result = await (0, import_router.runMutation)(ctx, {
|
|
2291
2292
|
productReorderMedia: {
|
|
@@ -40,7 +40,7 @@ const runPublishables = async ({
|
|
|
40
40
|
" publish-to-current-channel|unpublish-to-current-channel",
|
|
41
41
|
"",
|
|
42
42
|
"Notes:",
|
|
43
|
-
" --id must be a full gid://shopify/...
|
|
43
|
+
" --id must be a full Shopify GID (gid://shopify/...)."
|
|
44
44
|
].join("\n")
|
|
45
45
|
);
|
|
46
46
|
return;
|
package/dist/cli.js
CHANGED
|
@@ -36,6 +36,7 @@ var import_command = require("./cli/command");
|
|
|
36
36
|
var import_parse_command = require("./cli/parse-command");
|
|
37
37
|
var import_output = require("./cli/output");
|
|
38
38
|
var import_suggest = require("./cli/suggest");
|
|
39
|
+
var import_gid = require("./cli/gid");
|
|
39
40
|
import_dotenv.default.config({ path: (0, import_path.resolve)(process.cwd(), ".env"), quiet: true });
|
|
40
41
|
const helpFlags = /* @__PURE__ */ new Set(["--help", "-h", "--help-full", "--help-all"]);
|
|
41
42
|
const versionFlags = /* @__PURE__ */ new Set(["--version", "-v"]);
|
|
@@ -133,6 +134,8 @@ Missing <verb> for "${resource}"`, 2);
|
|
|
133
134
|
}
|
|
134
135
|
const parsed = (0, import_globalFlags.parseGlobalFlags)(rewrittenRest);
|
|
135
136
|
const dryRun = parsed.dryRun ?? false;
|
|
137
|
+
const strictIds = parsed.strictIds ?? (0, import_gid.parseEnvBoolean)(process.env.SHOP_CLI_STRICT_IDS);
|
|
138
|
+
(0, import_gid.setStrictIdsMode)(strictIds);
|
|
136
139
|
const isOfflineCommand = verb === "fields" || isTypesCommand;
|
|
137
140
|
const shopDomain = parsed.shopDomain;
|
|
138
141
|
const graphqlEndpoint = parsed.graphqlEndpoint;
|