@doswiftly/storefront-operations 7.0.0 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/mutations.graphql CHANGED
@@ -7,6 +7,7 @@
7
7
  # Cart Mutations
8
8
  # ============================================
9
9
 
10
+ # Creates a new cart and optionally pre-populates it with line items. Cart ID is a UUID stored by the SDK in the `cart-id` cookie (30-day TTL); the cart itself expires server-side after 72 hours of inactivity. The `warnings` field is reserved for non-blocking issues — current implementation returns it empty in this path.
10
11
  mutation CartCreate($input: CartCreateInput) {
11
12
  cartCreate(input: $input) {
12
13
  cart {
@@ -21,6 +22,7 @@ mutation CartCreate($input: CartCreateInput) {
21
22
  }
22
23
  }
23
24
 
25
+ # Adds line items to a cart. Each line is `{ merchandiseId, quantity, attributes?, attributeSelections? }`. If the same variant + identical attributes are added twice, quantities merge into one row instead of duplicating. Validates stock (`INSUFFICIENT_STOCK`) and configurator attributes (`ATTRIBUTE_REQUIRED`, `ATTRIBUTE_OPTION_INVALID`). Triggers cart re-pricing including discount recalculation.
24
26
  mutation CartAddLines($id: ID!, $lines: [CartLineInput!]!) {
25
27
  cartAddLines(id: $id, lines: $lines) {
26
28
  cart {
@@ -35,6 +37,7 @@ mutation CartAddLines($id: ID!, $lines: [CartLineInput!]!) {
35
37
  }
36
38
  }
37
39
 
40
+ # Updates quantity and/or attributes of existing cart lines by `id`. Setting `quantity: 0` auto-deletes the line. Passing `attributes: []` clears them; omitting the field preserves existing values. Re-validates stock and re-prices the cart after each update.
38
41
  mutation CartUpdateLines($id: ID!, $lines: [CartLineUpdateInput!]!) {
39
42
  cartUpdateLines(id: $id, lines: $lines) {
40
43
  cart {
@@ -49,6 +52,7 @@ mutation CartUpdateLines($id: ID!, $lines: [CartLineUpdateInput!]!) {
49
52
  }
50
53
  }
51
54
 
55
+ # Removes specific lines from cart by `lineIds[]`. Internally delegates to `cartUpdateLines` with `quantity: 0` — both endpoints are functionally equivalent; this one exists for API ergonomics when intent is explicit removal. Triggers cart re-pricing.
52
56
  mutation CartRemoveLines($id: ID!, $lineIds: [ID!]!) {
53
57
  cartRemoveLines(id: $id, lineIds: $lineIds) {
54
58
  cart {
@@ -63,6 +67,7 @@ mutation CartRemoveLines($id: ID!, $lineIds: [ID!]!) {
63
67
  }
64
68
  }
65
69
 
70
+ # Replaces (NOT appends) the cart's discount codes with the given list. Pass `[]` to clear all codes. Each code is validated against `discounts` table (existence, active status); invalid codes appear in `userErrors[]` as `DISCOUNT_CODE_INVALID`. Triggers cart re-pricing — discount allocations are recomputed and stored in `cart.discountAmount`.
66
71
  mutation CartApplyDiscountCodes($id: ID!, $discountCodes: [String!]!) {
67
72
  cartApplyDiscountCodes(id: $id, discountCodes: $discountCodes) {
68
73
  cart {
@@ -77,6 +82,7 @@ mutation CartApplyDiscountCodes($id: ID!, $discountCodes: [String!]!) {
77
82
  }
78
83
  }
79
84
 
85
+ # Associates a customer with the cart. Despite the input shape accepting `email`, `phone`, `countryCode`, `languageCode`, only `customerId` is currently persisted — other fields are silently ignored. Does NOT trigger tax / shipping recalculation; pure cart-to-customer linking. Use during login or guest-to-account upgrade.
80
86
  mutation CartUpdateBuyerIdentity($id: ID!, $buyerIdentity: CartBuyerIdentityInput!) {
81
87
  cartUpdateBuyerIdentity(id: $id, buyerIdentity: $buyerIdentity) {
82
88
  cart {
@@ -91,6 +97,7 @@ mutation CartUpdateBuyerIdentity($id: ID!, $buyerIdentity: CartBuyerIdentityInpu
91
97
  }
92
98
  }
93
99
 
100
+ # Sets a free-text note on the cart (gift message, special instructions). Pass empty string to clear. Stored on the `Cart` row, propagated to the `Order` at checkout completion, visible to merchant in admin.
94
101
  mutation CartUpdateNote($id: ID!, $note: String!) {
95
102
  cartUpdateNote(id: $id, note: $note) {
96
103
  cart {
@@ -109,6 +116,7 @@ mutation CartUpdateNote($id: ID!, $note: String!) {
109
116
  # Customer Auth Mutations
110
117
  # ============================================
111
118
 
119
+ # Registers a new customer. Returns `customerAccessToken` immediately — the customer record is created with status `ACTIVE` (no pending state). The activation email containing `customerActivate` token is sent for `emailVerified=true` confirmation, but is NOT required for login. Cookie: `customerAccessToken`, 30-day max-age, httpOnly. JWT TTL: 24h. Bot-protection guarded.
112
120
  mutation CustomerSignup($input: CustomerCreateInput!) {
113
121
  customerSignup(input: $input) {
114
122
  customer {
@@ -123,6 +131,7 @@ mutation CustomerSignup($input: CustomerCreateInput!) {
123
131
  }
124
132
  }
125
133
 
134
+ # Logs in with email + password. JWT lifetime 24h; cookie max-age 30d (cookie outlives JWT — call `customerRefreshToken` before JWT expiry to extend session). Brute-force protected: 10 failed attempts per email = 15-min Redis-backed lockout. Failed attempts are recorded for non-existent emails too (timing-attack safe).
126
135
  mutation CustomerLogin($input: CustomerAccessTokenCreateInput!) {
127
136
  customerLogin(input: $input) {
128
137
  customerAccessToken {
@@ -134,6 +143,7 @@ mutation CustomerLogin($input: CustomerAccessTokenCreateInput!) {
134
143
  }
135
144
  }
136
145
 
146
+ # Clears the `customerAccessToken` cookie. Note: the JWT itself is NOT server-side invalidated — it remains valid until its 24h expiry. Server-side token revocation is on the roadmap. Idempotent.
137
147
  mutation CustomerLogout {
138
148
  customerLogout {
139
149
  deletedAccessToken
@@ -144,6 +154,7 @@ mutation CustomerLogout {
144
154
  }
145
155
  }
146
156
 
157
+ # Issues a fresh JWT (24h TTL) for the currently-authenticated customer. Reads identity from the current cookie/Bearer token; takes no input. Use proactively before JWT expiry or reactively on a 401 retry. The new token replaces the cookie value.
147
158
  mutation CustomerRefreshToken {
148
159
  customerRefreshToken {
149
160
  customerAccessToken {
@@ -159,6 +170,7 @@ mutation CustomerRefreshToken {
159
170
  # Customer Profile Mutations
160
171
  # ============================================
161
172
 
173
+ # Updates the logged-in customer's profile. Supported fields include `firstName`, `lastName`, `phone`, marketing preferences, and B2B identity (`customerType`, `companyName`, `taxId`, `vatNumber`, `regon`). Concurrent updates from the storefront and the merchant admin are reconciled safely — the loser of a race retries against the latest version. Marketing consent changes are recorded separately for audit purposes.
162
174
  mutation CustomerUpdate($customer: CustomerUpdateInput!) {
163
175
  customerUpdate(customer: $customer) {
164
176
  customer {
@@ -174,6 +186,7 @@ mutation CustomerUpdate($customer: CustomerUpdateInput!) {
174
186
  # Customer Address Mutations
175
187
  # ============================================
176
188
 
189
+ # Adds a new mailing address. If `isDefaultShipping` or `isDefaultBilling` is `true` in the input, the new address is set as default and any other address for this customer holding that flag is atomically cleared in the same transaction.
177
190
  mutation CustomerAddAddress($address: MailingAddressInput!) {
178
191
  customerAddAddress(address: $address) {
179
192
  address {
@@ -185,6 +198,7 @@ mutation CustomerAddAddress($address: MailingAddressInput!) {
185
198
  }
186
199
  }
187
200
 
201
+ # Updates an existing address owned by the logged-in customer. If `isDefaultShipping` or `isDefaultBilling` toggles to `true`, default flag is atomically cleared on all other addresses for this customer.
188
202
  mutation CustomerUpdateAddress($id: ID!, $address: MailingAddressInput!) {
189
203
  customerUpdateAddress(id: $id, address: $address) {
190
204
  address {
@@ -196,6 +210,7 @@ mutation CustomerUpdateAddress($id: ID!, $address: MailingAddressInput!) {
196
210
  }
197
211
  }
198
212
 
213
+ # Hard-deletes an address row from `customer_addresses`. Historical orders that referenced this address are unaffected (address is snapshotted into the order at checkout completion).
199
214
  mutation CustomerRemoveAddress($id: ID!) {
200
215
  customerRemoveAddress(id: $id) {
201
216
  deletedAddressId
@@ -205,6 +220,7 @@ mutation CustomerRemoveAddress($id: ID!) {
205
220
  }
206
221
  }
207
222
 
223
+ # Marks the given address as the customer's default **shipping** address. Atomically clears the shipping-default flag from all other addresses. Note: there is no separate setter for default billing — set `isDefaultBilling: true` via `customerAddAddress` / `customerUpdateAddress` instead.
208
224
  mutation CustomerSetDefaultAddress($addressId: ID!) {
209
225
  customerSetDefaultAddress(addressId: $addressId) {
210
226
  customer {
@@ -220,6 +236,7 @@ mutation CustomerSetDefaultAddress($addressId: ID!) {
220
236
  # Customer Password Mutations
221
237
  # ============================================
222
238
 
239
+ # Sends a password reset email. Always returns success regardless of whether the email exists (no account enumeration). The email is dispatched asynchronously, so a small delay between request and inbox arrival is normal. Rate-limited to 3 requests per 10 minutes.
223
240
  mutation CustomerRequestPasswordReset($email: String!) {
224
241
  customerRequestPasswordReset(email: $email) {
225
242
  userErrors {
@@ -228,6 +245,7 @@ mutation CustomerRequestPasswordReset($email: String!) {
228
245
  }
229
246
  }
230
247
 
248
+ # Activates a newly-created account using the 64-hex activation token from the welcome email + a chosen password. Token TTL is 24h, single-use (atomically marked `used_at`). On success: sets `email_verified=true`, transitions status `INACTIVE`→`ACTIVE`, returns a fresh JWT for auto-login. Rate-limited.
231
249
  mutation CustomerActivate($token: String!, $password: String!) {
232
250
  customerActivate(token: $token, password: $password) {
233
251
  customer {
@@ -242,6 +260,7 @@ mutation CustomerActivate($token: String!, $password: String!) {
242
260
  }
243
261
  }
244
262
 
263
+ # Resets the password using the 64-hex reset token from the password-reset email. Token TTL is 1h, single-use (atomically marked `used_at`). On success: updates the password hash and returns a fresh JWT for auto-login (no second login step needed). Rate-limited.
245
264
  mutation CustomerResetPassword($token: String!, $newPassword: String!) {
246
265
  customerResetPassword(token: $token, newPassword: $newPassword) {
247
266
  customer {
@@ -260,6 +279,7 @@ mutation CustomerResetPassword($token: String!, $newPassword: String!) {
260
279
  # Checkout Mutations
261
280
  # ============================================
262
281
 
282
+ # Creates a new checkout session for the given cart (or a fresh cart if `cartId` is omitted). Inherits applied discounts and gift cards from the cart by reference (not snapshot). Errors: `CART_NOT_FOUND`, `EMPTY_CART`, `ALREADY_COMPLETED` (cart already converted to order). NOT idempotent — multiple calls create multiple checkouts.
263
283
  mutation CheckoutCreate($input: CheckoutCreateInput!) {
264
284
  checkoutCreate(input: $input) {
265
285
  checkout {
@@ -271,6 +291,7 @@ mutation CheckoutCreate($input: CheckoutCreateInput!) {
271
291
  }
272
292
  }
273
293
 
294
+ # Sets the shipping address (full replace, not patch). Triggers cart re-pricing. Address format is NOT validated here — full validation runs at `checkoutComplete` (`validateOrderReadiness`).
274
295
  mutation CheckoutShippingAddressUpdate($checkoutId: ID!, $shippingAddress: CheckoutAddressInput!) {
275
296
  checkoutShippingAddressUpdate(checkoutId: $checkoutId, shippingAddress: $shippingAddress) {
276
297
  checkout {
@@ -282,6 +303,7 @@ mutation CheckoutShippingAddressUpdate($checkoutId: ID!, $shippingAddress: Check
282
303
  }
283
304
  }
284
305
 
306
+ # Sets the billing address (full replace). Independent of shipping address — pass it explicitly even when "billing same as shipping".
285
307
  mutation CheckoutBillingAddressUpdate($checkoutId: ID!, $billingAddress: CheckoutAddressInput!) {
286
308
  checkoutBillingAddressUpdate(checkoutId: $checkoutId, billingAddress: $billingAddress) {
287
309
  checkout {
@@ -293,6 +315,7 @@ mutation CheckoutBillingAddressUpdate($checkoutId: ID!, $billingAddress: Checkou
293
315
  }
294
316
  }
295
317
 
318
+ # Sets or updates the contact email on the checkout (used for guest checkout, order confirmation, and tracking emails). Validated against a regex; returns `INVALID` for malformed format.
296
319
  mutation CheckoutEmailUpdate($checkoutId: ID!, $email: String!) {
297
320
  checkoutEmailUpdate(checkoutId: $checkoutId, email: $email) {
298
321
  checkout {
@@ -304,6 +327,7 @@ mutation CheckoutEmailUpdate($checkoutId: ID!, $email: String!) {
304
327
  }
305
328
  }
306
329
 
330
+ # Selects a shipping method by `shippingRateHandle` (a stable shipping-method UUID, NOT an opaque per-request token). The id comes from `availableShippingMethods` query, computed for the current address + cart subtotal at request time.
307
331
  mutation CheckoutShippingLineUpdate($checkoutId: ID!, $shippingRateHandle: String!) {
308
332
  checkoutShippingLineUpdate(checkoutId: $checkoutId, shippingRateHandle: $shippingRateHandle) {
309
333
  checkout {
@@ -315,6 +339,7 @@ mutation CheckoutShippingLineUpdate($checkoutId: ID!, $shippingRateHandle: Strin
315
339
  }
316
340
  }
317
341
 
342
+ # Appends a discount code to the cart's `discount_codes` array. Note: while multiple codes can be stored, the pricing engine currently uses **only the first applied code** — codes do not stack. Validated for existence, active status, and customer usage limits via `discountService.validateDiscount`.
318
343
  mutation CheckoutDiscountCodeApply($checkoutId: ID!, $discountCode: String!) {
319
344
  checkoutDiscountCodeApply(checkoutId: $checkoutId, discountCode: $discountCode) {
320
345
  checkout {
@@ -326,6 +351,7 @@ mutation CheckoutDiscountCodeApply($checkoutId: ID!, $discountCode: String!) {
326
351
  }
327
352
  }
328
353
 
354
+ # Removes a code from the cart's `discount_codes` array (filters by exact match). Triggers re-pricing.
329
355
  mutation CheckoutDiscountCodeRemove($checkoutId: ID!, $discountCode: String!) {
330
356
  checkoutDiscountCodeRemove(checkoutId: $checkoutId, discountCode: $discountCode) {
331
357
  checkout {
@@ -337,6 +363,7 @@ mutation CheckoutDiscountCodeRemove($checkoutId: ID!, $discountCode: String!) {
337
363
  }
338
364
  }
339
365
 
366
+ # READ-ONLY validation of a discount code against the current checkout — does NOT modify state. Returns `{ isValid, discount, error }` for previewing the effect (e.g. inline UI feedback as the user types).
340
367
  mutation CheckoutDiscountCodeValidate($checkoutId: ID!, $discountCode: String!) {
341
368
  checkoutDiscountCodeValidate(checkoutId: $checkoutId, discountCode: $discountCode) {
342
369
  result {
@@ -362,6 +389,7 @@ mutation CheckoutDiscountCodeValidate($checkoutId: ID!, $discountCode: String!)
362
389
  }
363
390
  }
364
391
 
392
+ # Selects a payment method by `paymentMethodId` (UUID from `availablePaymentMethods` query). Validates existence and active status; no pre-authorization is performed here.
365
393
  mutation CheckoutPaymentMethodUpdate($checkoutId: ID!, $paymentMethodId: ID!) {
366
394
  checkoutPaymentMethodUpdate(checkoutId: $checkoutId, paymentMethodId: $paymentMethodId) {
367
395
  checkout {
@@ -373,6 +401,7 @@ mutation CheckoutPaymentMethodUpdate($checkoutId: ID!, $paymentMethodId: ID!) {
373
401
  }
374
402
  }
375
403
 
404
+ # Finalizes the checkout: creates the `Order`, marks the cart `CONVERTED`, deducts gift cards, emits `ORDER_CREATED` (and `ORDER_CONFIRMED` for COD) — all in a single serializable transaction. **Idempotent on `idempotencyKey`** (NOT on `checkoutId`); auto-generated from `cartId + timestamp` if the caller omits it. The `paymentUrl` field is reserved but is NOT populated here — for hosted gateways (PayU, P24) the storefront calls a separate `paymentCreate` mutation after this returns.
376
405
  mutation CheckoutComplete($checkoutId: ID!, $input: CheckoutCompleteInput) {
377
406
  checkoutComplete(checkoutId: $checkoutId, input: $input) {
378
407
  checkout {
@@ -389,9 +418,10 @@ mutation CheckoutComplete($checkoutId: ID!, $input: CheckoutCompleteInput) {
389
418
  }
390
419
 
391
420
  # ============================================
392
- # Gift Card Checkout Mutations (GAP-001)
421
+ # Gift Card Checkout Mutations
393
422
  # ============================================
394
423
 
424
+ # Applies a gift card to the cart, stackable with discount codes. Consumption is FIFO: each card consumes `min(remainingBalance, paymentDue)` against the current cart total in the order they were applied. The gift card balance is NOT debited yet — actual deduction happens atomically inside the `checkoutComplete` transaction. Errors: `GIFT_CARD_NOT_FOUND`, `GIFT_CARD_DEPLETED`, `GIFT_CARD_UNUSABLE`, `GIFT_CARD_ALREADY_APPLIED`.
395
425
  mutation CheckoutGiftCardApply($checkoutId: ID!, $giftCardCode: String!) {
396
426
  checkoutGiftCardApply(checkoutId: $checkoutId, giftCardCode: $giftCardCode) {
397
427
  checkout {
@@ -403,6 +433,7 @@ mutation CheckoutGiftCardApply($checkoutId: ID!, $giftCardCode: String!) {
403
433
  }
404
434
  }
405
435
 
436
+ # Removes a gift card from the applied list and recalculates FIFO `appliedAmount` for the remaining cards. Since gift card balances are only debited at `checkoutComplete`, removing before completion has no effect on the underlying gift card balance.
406
437
  mutation CheckoutGiftCardRemove($checkoutId: ID!, $giftCardCode: String!) {
407
438
  checkoutGiftCardRemove(checkoutId: $checkoutId, giftCardCode: $giftCardCode) {
408
439
  checkout {
@@ -414,6 +445,7 @@ mutation CheckoutGiftCardRemove($checkoutId: ID!, $giftCardCode: String!) {
414
445
  }
415
446
  }
416
447
 
448
+ # Sets per-line-item recipient details (name, email, message, delivery date) for digital gift card products in the cart (variants with `type: GIFT_CARD`). Required before `checkoutComplete` for any line item with a gift-card variant. Recipient details are associated with each gift-card line item and propagated to the resulting order.
417
449
  mutation CheckoutGiftCardRecipientUpdate($input: CheckoutGiftCardRecipientInput!) {
418
450
  checkoutGiftCardRecipientUpdate(input: $input) {
419
451
  checkout {
@@ -426,9 +458,10 @@ mutation CheckoutGiftCardRecipientUpdate($input: CheckoutGiftCardRecipientInput!
426
458
  }
427
459
 
428
460
  # ============================================
429
- # Return Mutations (R30 - Returns/RMA)
461
+ # Return Mutations
430
462
  # ============================================
431
463
 
464
+ # Creates an RMA in `REQUESTED` status (awaits merchant approval — NOT auto-approved). Input: `orderId`, `reason`, `items[{ variantId, quantity, reason, condition }]`, optional `compensationType` (REFUND or STORE_CREDIT) and `customerNote`. Validates the order's `fulfillmentStatus` permits returns and that requested quantities don't exceed already-shipped/unreturned quantities. Supports optional `idempotencyKey` for retry-safe creation.
432
465
  mutation ReturnCreate($input: ReturnCreateInput!) {
433
466
  returnCreate(input: $input) {
434
467
  return {
@@ -440,6 +473,7 @@ mutation ReturnCreate($input: ReturnCreateInput!) {
440
473
  }
441
474
  }
442
475
 
476
+ # Cancels a return that is currently in `REQUESTED`, `APPROVED`, or `DRAFT` status (cancellation is allowed even AFTER merchant approval, as long as the return shipment hasn't been processed). Sets `cancelled_at` timestamp. Customer can only cancel returns they own.
443
477
  mutation ReturnCancel($id: ID!) {
444
478
  returnCancel(id: $id) {
445
479
  return {
@@ -452,15 +486,17 @@ mutation ReturnCancel($id: ID!) {
452
486
  }
453
487
 
454
488
  # ============================================
455
- # Loyalty Program Mutations (R8, R10.4)
489
+ # Loyalty Program Mutations
456
490
  # ============================================
457
491
 
492
+ # Redeems a loyalty reward by `rewardId`. Three reward types are supported, distinguished by which output field is populated: `discountCode` (issues a `LOYALTY-XXXX` code with 30-day expiry), `productDiscountCode` (issues a single-use 100%-off code for a specific product), or `giftCardCode` (creates a new gift card for the customer). Points are deducted atomically inside a transaction — if external creation (e.g. gift card service) fails after deduction, points are reversed.
458
493
  mutation RedeemLoyaltyReward($input: RedeemRewardInput!) {
459
494
  redeemLoyaltyReward(input: $input) {
460
495
  ...RedeemRewardPayload
461
496
  }
462
497
  }
463
498
 
499
+ # Returns the customer's referral code, generating one on first call. Idempotent UPSERT — subsequent calls return the existing code from `customers.referral_code`. Format: `REF-XXXXXXXX` (8 random alphanumeric chars). Output also includes a `shareUrl` built from the shop's domain.
464
500
  mutation GenerateReferralCode {
465
501
  generateReferralCode {
466
502
  ...GenerateReferralCodePayload
@@ -471,6 +507,7 @@ mutation GenerateReferralCode {
471
507
  # Review Mutations
472
508
  # ============================================
473
509
 
510
+ # Submits a product review (rating 1-5, content 10-5000 chars, sanitized via `sanitizePlainText`). Default state is `PENDING` — review is hidden from public until merchant approves. If the input includes `orderId`, `isVerifiedPurchase` is auto-set to `true`. Bot-protected and rate-limited (10/min by default).
474
511
  mutation ReviewCreate($input: ReviewCreateInput!) {
475
512
  reviewCreate(input: $input) {
476
513
  review {
@@ -482,6 +519,7 @@ mutation ReviewCreate($input: ReviewCreateInput!) {
482
519
  }
483
520
  }
484
521
 
522
+ # Records an upvote (helpful) on a review. UPSERT semantics — one `ReviewVote` row per `(reviewId, customerId)`. Calling upvote twice is a no-op; calling downvote afterwards replaces the vote. Increments `helpful_count` on the review (and decrements `unhelpful_count` if replacing a downvote).
485
523
  mutation ReviewUpvote($reviewId: ID!) {
486
524
  reviewUpvote(reviewId: $reviewId) {
487
525
  review {
@@ -493,6 +531,7 @@ mutation ReviewUpvote($reviewId: ID!) {
493
531
  }
494
532
  }
495
533
 
534
+ # Records a downvote (unhelpful) on a review. Same UPSERT semantics as `reviewUpvote` — one vote row per `(reviewId, customerId)`, replacing any prior vote. Increments `unhelpful_count`.
496
535
  mutation ReviewDownvote($reviewId: ID!) {
497
536
  reviewDownvote(reviewId: $reviewId) {
498
537
  review {
@@ -508,6 +547,7 @@ mutation ReviewDownvote($reviewId: ID!) {
508
547
  # Wishlist Mutations
509
548
  # ============================================
510
549
 
550
+ # Creates a new wishlist for the logged-in customer. `name` is optional (defaults to "My Wishlist"); name uniqueness is NOT enforced — customers can have multiple lists with the same name. Setting `isPublic: true` generates a 16-byte hex `shareToken` for public sharing.
511
551
  mutation WishlistCreate($input: WishlistCreateInput!) {
512
552
  wishlistCreate(input: $input) {
513
553
  wishlist {
@@ -517,6 +557,7 @@ mutation WishlistCreate($input: WishlistCreateInput!) {
517
557
  }
518
558
  }
519
559
 
560
+ # Adds an item by `productId` (and optional `variantId`) to a wishlist. Idempotent on the `(wishlist_id, product_id, variant_id)` unique constraint — adding an already-present item is a silent no-op (`ON CONFLICT DO NOTHING`). Captures `priceAtAdd` for price-drop notifications.
520
561
  mutation WishlistAddItem($wishlistId: ID!, $input: WishlistItemInput!) {
521
562
  wishlistAddItem(wishlistId: $wishlistId, input: $input) {
522
563
  wishlist {
@@ -526,6 +567,7 @@ mutation WishlistAddItem($wishlistId: ID!, $input: WishlistItemInput!) {
526
567
  }
527
568
  }
528
569
 
570
+ # Hard-deletes a wishlist item by `itemId` (the `WishlistItem` row id, NOT the product id).
529
571
  mutation WishlistRemoveItem($wishlistId: ID!, $itemId: ID!) {
530
572
  wishlistRemoveItem(wishlistId: $wishlistId, itemId: $itemId) {
531
573
  wishlist {
@@ -535,6 +577,7 @@ mutation WishlistRemoveItem($wishlistId: ID!, $itemId: ID!) {
535
577
  }
536
578
  }
537
579
 
580
+ # Hard-deletes the wishlist row. All `WishlistItem` rows are removed via FK cascade. No soft-delete; cannot be undone.
538
581
  mutation WishlistDelete($wishlistId: ID!) {
539
582
  wishlistDelete(wishlistId: $wishlistId) {
540
583
  wishlist {
@@ -548,6 +591,7 @@ mutation WishlistDelete($wishlistId: ID!) {
548
591
  # Cart Attributes
549
592
  # ============================================
550
593
 
594
+ # Replaces (NOT merges) the cart's custom attributes — free-form `[{ key, value }]` pairs visible to merchant in admin. Use for delivery instructions, gift wrap flags, B2B PO numbers, etc. Limit: 250 pairs per cart (returns `CART_ATTRIBUTES_LIMIT_EXCEEDED`); each `key` max 255 chars.
551
595
  mutation CartUpdateAttributes($id: ID!, $attributes: [CartAttributeInput!]!) {
552
596
  cartUpdateAttributes(id: $id, attributes: $attributes) {
553
597
  cart {