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 CHANGED
@@ -137,7 +137,7 @@ shop products list --select seo.title --select seo.description
137
137
  Include connections when using `--view all`:
138
138
 
139
139
  ```bash
140
- shop products get --id 123 --view all --include variants --include images
140
+ shop products get --id gid://shopify/Product/123 --view all --include variants --include images
141
141
  ```
142
142
 
143
143
  Override selection entirely with raw GraphQL:
@@ -155,7 +155,7 @@ With `--select`, use the `on_TypeName` prefix:
155
155
 
156
156
  ```bash
157
157
  # Select apps from an AppCatalog via publications
158
- shop products get --id 123 --include resourcePublicationsV2 \
158
+ shop products get --id gid://shopify/Product/123 --include resourcePublicationsV2 \
159
159
  --select resourcePublicationsV2.nodes.publication.catalog.on_AppCatalog.apps.nodes.title
160
160
  ```
161
161
 
@@ -204,6 +204,7 @@ shop products list --quiet
204
204
  | `--set-json` | Set a field value as JSON (repeatable) |
205
205
  | `--tags` | Comma-separated tags |
206
206
  | `--dry-run` | Print GraphQL operation without executing |
207
+ | `--strict-ids` | Require full `gid://shopify/...` IDs (or env `SHOP_CLI_STRICT_IDS=1`) |
207
208
 
208
209
  ## Raw GraphQL
209
210
 
@@ -229,23 +230,23 @@ shop products list --first 5
229
230
  shop products list --published
230
231
 
231
232
  # Get a specific product
232
- shop products get --id 123
233
+ shop products get --id gid://shopify/Product/123
233
234
 
234
235
  # Create a product
235
236
  shop products create --set title="My Product" --set status="ACTIVE"
236
237
 
237
238
  # Update a product
238
- shop products update --id 123 --set title="Updated Title"
239
+ shop products update --id gid://shopify/Product/123 --set title="Updated Title"
239
240
 
240
241
  # Add tags to a product
241
- shop products add-tags --id 123 --tags "summer,featured"
242
+ shop products add-tags --id gid://shopify/Product/123 --tags "summer,featured"
242
243
 
243
244
  # Publish to a sales channel
244
245
  shop publications resolve --publication "Online Store"
245
- shop products publish --id 123 --publication "Online Store" --now
246
+ shop products publish --id gid://shopify/Product/123 --publication "Online Store" --now
246
247
 
247
248
  # Work with metafields
248
- shop products metafields upsert --id 123 \
249
+ shop products metafields upsert --id gid://shopify/Product/123 \
249
250
  --set namespace=custom \
250
251
  --set key=foo \
251
252
  --set type=single_line_text_field \
package/dist/cli/gid.d.ts CHANGED
@@ -1,3 +1,14 @@
1
- export type ShopifyGidType = 'AbandonedCheckout' | 'Abandonment' | 'AndroidApplication' | 'App' | 'Metafield' | 'Job' | 'Product' | 'ProductOption' | 'ProductOptionValue' | 'ProductFeed' | 'ProductVariant' | 'Collection' | 'Customer' | 'CustomerPaymentMethod' | 'CustomerSegmentMembersQuery' | 'StaffMember' | 'Order' | 'OrderTransaction' | 'CalculatedOrder' | 'CalculatedLineItem' | 'CalculatedDiscountApplication' | 'CalculatedShippingLine' | 'AppInstallation' | 'AppSubscription' | 'DiscountAutomaticNode' | 'DiscountCodeNode' | 'DiscountNode' | 'DiscountRedeemCode' | 'DiscountRedeemCodeBulkCreation' | 'InventoryItem' | 'InventoryLevel' | 'InventoryShipment' | 'InventoryTransfer' | 'InventoryTransferLineItem' | 'Location' | 'FulfillmentOrder' | 'Fulfillment' | 'FulfillmentHold' | 'FulfillmentService' | 'FulfillmentConstraintRule' | 'GiftCard' | 'Return' | 'ReturnLineItem' | 'ReturnReasonDefinition' | 'ReturnableFulfillment' | 'DeliveryProfile' | 'DeliveryCustomization' | 'DeliveryCarrierService' | 'File' | 'PaymentTerms' | 'PaymentTermsTemplate' | 'PaymentSchedule' | 'PaymentMandate' | 'PaymentCustomization' | 'PriceList' | 'Publication' | 'Refund' | 'Article' | 'Blog' | 'Page' | 'Comment' | 'Event' | 'Menu' | 'Channel' | 'Catalog' | 'Market' | 'MarketRegionCountry' | 'MarketWebPresence' | 'BusinessEntity' | 'Company' | 'CompanyAddress' | 'CompanyContact' | 'CompanyContactRole' | 'CompanyContactRoleAssignment' | 'CompanyLocation' | 'CompanyLocationStaffMemberAssignment' | 'StoreCreditAccount' | 'StorefrontAccessToken' | 'DraftOrder' | 'DraftOrderTag' | 'BulkOperation' | 'UrlRedirect' | 'UrlRedirectImport' | 'Segment' | 'SavedSearch' | 'ScriptTag' | 'CartTransform' | 'Validation' | 'OnlineStoreTheme' | 'CheckoutProfile' | 'WebPixel' | 'ServerPixel' | 'MarketingActivity' | 'MarketingEvent' | 'WebhookSubscription' | 'Domain' | 'MetafieldDefinition' | 'Metaobject' | 'MetaobjectDefinition' | 'Shop' | 'MarketWebPresence' | 'SellingPlanGroup' | 'ShippingPackage' | 'ShopifyPaymentsDispute' | 'ShopifyPaymentsDisputeEvidence' | 'SubscriptionContract' | 'SubscriptionDraft' | 'SubscriptionLine' | 'SubscriptionManualDiscount' | 'SubscriptionBillingAttempt' | 'AppleApplication' | 'CashTrackingSession' | 'PointOfSaleDevice' | 'CustomerAccountPage' | 'FlowActionDefinition' | 'MailingAddress';
1
+ export type ShopifyGidType = 'AbandonedCheckout' | 'Abandonment' | 'AndroidApplication' | 'App' | 'Metafield' | 'Job' | 'Product' | 'ProductOption' | 'ProductOptionValue' | 'ProductFeed' | 'ProductVariant' | 'Collection' | 'Customer' | 'CustomerPaymentMethod' | 'CustomerSegmentMembersQuery' | 'StaffMember' | 'Order' | 'OrderTransaction' | 'CalculatedOrder' | 'CalculatedLineItem' | 'CalculatedDiscountApplication' | 'CalculatedShippingLine' | 'AppInstallation' | 'AppSubscription' | 'DiscountAutomaticNode' | 'DiscountCodeNode' | 'DiscountNode' | 'DiscountRedeemCode' | 'DiscountRedeemCodeBulkCreation' | 'InventoryItem' | 'InventoryLevel' | 'InventoryShipment' | 'InventoryTransfer' | 'InventoryTransferLineItem' | 'Location' | 'FulfillmentOrder' | 'Fulfillment' | 'FulfillmentHold' | 'FulfillmentService' | 'FulfillmentConstraintRule' | 'GiftCard' | 'Return' | 'ReturnLineItem' | 'ReturnReasonDefinition' | 'ReturnableFulfillment' | 'DeliveryProfile' | 'DeliveryCustomization' | 'DeliveryCarrierService' | 'File' | 'PaymentTerms' | 'PaymentTermsTemplate' | 'PaymentSchedule' | 'PaymentMandate' | 'PaymentCustomization' | 'PriceList' | 'Publication' | 'Refund' | 'Article' | 'Blog' | 'Page' | 'Comment' | 'Event' | 'Menu' | 'Channel' | 'Catalog' | 'Market' | 'MarketRegionCountry' | 'MarketWebPresence' | 'BusinessEntity' | 'Company' | 'CompanyAddress' | 'CompanyContact' | 'CompanyContactRole' | 'CompanyContactRoleAssignment' | 'CompanyLocation' | 'CompanyLocationStaffMemberAssignment' | 'StoreCreditAccount' | 'StorefrontAccessToken' | 'DraftOrder' | 'DraftOrderTag' | 'BulkOperation' | 'UrlRedirect' | 'UrlRedirectImport' | 'Segment' | 'SavedSearch' | 'ScriptTag' | 'CartTransform' | 'Validation' | 'OnlineStoreTheme' | 'CheckoutProfile' | 'WebPixel' | 'ServerPixel' | 'MarketingActivity' | 'MarketingEvent' | 'WebhookSubscription' | 'Domain' | 'ExternalVideo' | 'MediaImage' | 'Model3d' | 'MetafieldDefinition' | 'Metaobject' | 'MetaobjectDefinition' | 'Shop' | 'MarketWebPresence' | 'SellingPlanGroup' | 'ShippingPackage' | 'ShopifyPaymentsDispute' | 'ShopifyPaymentsDisputeEvidence' | 'SubscriptionContract' | 'SubscriptionDraft' | 'SubscriptionLine' | 'SubscriptionManualDiscount' | 'SubscriptionBillingAttempt' | 'Video' | 'AppleApplication' | 'CashTrackingSession' | 'PointOfSaleDevice' | 'CustomerAccountPage' | 'FlowActionDefinition' | 'MailingAddress';
2
2
  export declare const isGid: (value: string) => boolean;
3
- export declare const coerceGid: (value: string, type: ShopifyGidType) => string;
3
+ export declare const parseEnvBoolean: (value: string | undefined) => boolean;
4
+ export declare const setStrictIdsMode: (enabled: boolean) => void;
5
+ export declare const isStrictIdsMode: () => boolean;
6
+ export declare const parseShopifyGid: (value: string) => {
7
+ raw: string;
8
+ type: string;
9
+ id: string;
10
+ };
11
+ export declare const getShopifyGidType: (value: string) => string;
12
+ export declare const assertShopifyGidType: (value: string, expectedType: ShopifyGidType, label?: string) => string;
13
+ export declare const assertShopifyGidTypeIn: (value: string, allowedTypes: readonly ShopifyGidType[], label?: string) => string;
14
+ export declare const coerceGid: (value: string, type: ShopifyGidType, label?: string) => string;
package/dist/cli/gid.js CHANGED
@@ -18,25 +18,93 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var gid_exports = {};
20
20
  __export(gid_exports, {
21
+ assertShopifyGidType: () => assertShopifyGidType,
22
+ assertShopifyGidTypeIn: () => assertShopifyGidTypeIn,
21
23
  coerceGid: () => coerceGid,
22
- isGid: () => isGid
24
+ getShopifyGidType: () => getShopifyGidType,
25
+ isGid: () => isGid,
26
+ isStrictIdsMode: () => isStrictIdsMode,
27
+ parseEnvBoolean: () => parseEnvBoolean,
28
+ parseShopifyGid: () => parseShopifyGid,
29
+ setStrictIdsMode: () => setStrictIdsMode
23
30
  });
24
31
  module.exports = __toCommonJS(gid_exports);
25
32
  var import_errors = require("./errors");
26
- const isGid = (value) => value.startsWith("gid://");
27
- const coerceGid = (value, type) => {
28
- if (isGid(value)) return value;
29
- if (!/^\d+$/.test(value)) {
33
+ const isGid = (value) => value.trim().startsWith("gid://");
34
+ const parseEnvBoolean = (value) => {
35
+ if (value === void 0) return false;
36
+ const v = value.trim().toLowerCase();
37
+ if (v === "") return true;
38
+ if (v === "1" || v === "true" || v === "yes" || v === "y" || v === "on") return true;
39
+ if (v === "0" || v === "false" || v === "no" || v === "n" || v === "off") return false;
40
+ return true;
41
+ };
42
+ let strictIdsMode = parseEnvBoolean(process.env.SHOP_CLI_STRICT_IDS);
43
+ const setStrictIdsMode = (enabled) => {
44
+ strictIdsMode = enabled;
45
+ };
46
+ const isStrictIdsMode = () => strictIdsMode;
47
+ const parseShopifyGid = (value) => {
48
+ const raw = value.trim();
49
+ if (!raw.startsWith("gid://")) throw new import_errors.CliError(`Invalid Shopify GID: ${value}`, 2);
50
+ const parts = raw.split("/");
51
+ const scheme = parts[0];
52
+ const host = parts[2];
53
+ const type = parts[3];
54
+ const id = parts.slice(4).join("/");
55
+ if (scheme !== "gid:" || host !== "shopify" || !type || !id) {
56
+ throw new import_errors.CliError(`Invalid Shopify GID: ${value}`, 2);
57
+ }
58
+ return { raw, type, id };
59
+ };
60
+ const getShopifyGidType = (value) => parseShopifyGid(value).type;
61
+ const assertShopifyGidType = (value, expectedType, label = "GID") => {
62
+ const parsed = parseShopifyGid(value);
63
+ if (parsed.type !== expectedType) {
64
+ throw new import_errors.CliError(
65
+ `${label} must be a Shopify GID of type ${expectedType}. Got type ${parsed.type}: ${parsed.raw}`,
66
+ 2
67
+ );
68
+ }
69
+ return parsed.raw;
70
+ };
71
+ const assertShopifyGidTypeIn = (value, allowedTypes, label = "GID") => {
72
+ const parsed = parseShopifyGid(value);
73
+ if (!allowedTypes.includes(parsed.type)) {
74
+ throw new import_errors.CliError(
75
+ `${label} must be a Shopify GID of type one of ${allowedTypes.join(", ")}. Got type ${parsed.type}: ${parsed.raw}`,
76
+ 2
77
+ );
78
+ }
79
+ return parsed.raw;
80
+ };
81
+ const coerceGid = (value, type, label = `ID for ${type}`) => {
82
+ const raw = value.trim();
83
+ if (isGid(raw)) return assertShopifyGidType(raw, type, label);
84
+ if (isStrictIdsMode()) {
85
+ throw new import_errors.CliError(
86
+ `${label} must be a full Shopify GID of type ${type} (gid://shopify/${type}/...). Strict IDs mode is enabled (SHOP_CLI_STRICT_IDS or --strict-ids). Got: ${value}`,
87
+ 2
88
+ );
89
+ }
90
+ if (!/^\d+$/.test(raw)) {
30
91
  throw new import_errors.CliError(
31
92
  `Expected a numeric ID or full GID for ${type}. Got: ${value}`,
32
93
  2
33
94
  );
34
95
  }
35
- return `gid://shopify/${type}/${value}`;
96
+ return `gid://shopify/${type}/${raw}`;
36
97
  };
37
98
  // Annotate the CommonJS export names for ESM import in node:
38
99
  0 && (module.exports = {
100
+ assertShopifyGidType,
101
+ assertShopifyGidTypeIn,
39
102
  coerceGid,
40
- isGid
103
+ getShopifyGidType,
104
+ isGid,
105
+ isStrictIdsMode,
106
+ parseEnvBoolean,
107
+ parseShopifyGid,
108
+ setStrictIdsMode
41
109
  });
42
110
  //# sourceMappingURL=gid.js.map
@@ -7,6 +7,7 @@ export type GlobalParsed = {
7
7
  format?: string;
8
8
  quiet?: boolean;
9
9
  dryRun?: boolean;
10
+ strictIds?: boolean;
10
11
  noFailOnUserErrors?: boolean;
11
12
  view?: string;
12
13
  headers: string[];
@@ -76,6 +76,10 @@ const parseGlobalFlags = (args) => {
76
76
  parsed.dryRun = true;
77
77
  continue;
78
78
  }
79
+ if (flag === "--strict-ids") {
80
+ parsed.strictIds = true;
81
+ continue;
82
+ }
79
83
  if (flag === "--no-fail-on-user-errors") {
80
84
  parsed.noFailOnUserErrors = true;
81
85
  continue;