@doswiftly/storefront-sdk 9.1.0 → 11.0.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/CHANGELOG.md +184 -0
- package/dist/core/auth/types.d.ts +10 -3
- package/dist/core/auth/types.d.ts.map +1 -1
- package/dist/core/cart/cart-client.d.ts +98 -11
- package/dist/core/cart/cart-client.d.ts.map +1 -1
- package/dist/core/cart/cart-client.js +130 -22
- package/dist/core/cart/types.d.ts +189 -0
- package/dist/core/cart/types.d.ts.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/middleware/bot-protection.d.ts +1 -1
- package/dist/core/middleware/bot-protection.d.ts.map +1 -1
- package/dist/core/operations/auth.d.ts +5 -5
- package/dist/core/operations/auth.d.ts.map +1 -1
- package/dist/core/operations/auth.js +15 -13
- package/dist/core/operations/cart.d.ts +38 -11
- package/dist/core/operations/cart.d.ts.map +1 -1
- package/dist/core/operations/cart.js +274 -31
- package/dist/core/operations/compose.d.ts +24 -0
- package/dist/core/operations/compose.d.ts.map +1 -0
- package/dist/core/operations/compose.js +58 -0
- package/dist/react/hooks/use-cart-manager.d.ts +6 -5
- package/dist/react/hooks/use-cart-manager.d.ts.map +1 -1
- package/dist/react/hooks/use-cart-manager.js +2 -3
- package/package.json +1 -1
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
* Cart GraphQL operations — manual query strings (no codegen).
|
|
3
3
|
*
|
|
4
4
|
* SSOT: packages/backend/src/commerce/storefront-graphql/operations/
|
|
5
|
-
* - fragments.graphql (CartCost, CartLineCost, CartLine, Cart, etc.)
|
|
5
|
+
* - fragments.graphql (CartCost, CartLineCost, CartLine, Cart, Order, CartWarning, etc.)
|
|
6
6
|
* - queries.graphql (Cart query)
|
|
7
|
-
* - mutations.graphql (cartCreate,
|
|
7
|
+
* - mutations.graphql (cartCreate, cartAddLines, etc.)
|
|
8
8
|
*
|
|
9
9
|
* Validate drift: pnpm test:contract (cart-operations-drift test)
|
|
10
10
|
*
|
|
11
|
-
* Cart mutations always return full Cart + userErrors.
|
|
11
|
+
* Cart mutations always return full Cart + userErrors + warnings (non-fatal hints).
|
|
12
|
+
* Drift detection: PreToolUse hook validuje strings przeciwko storefront-operations/schema.graphql.
|
|
12
13
|
*/
|
|
14
|
+
import { composeOperation } from './compose';
|
|
13
15
|
// ---------------------------------------------------------------------------
|
|
14
16
|
// Shared fragments (matching SSOT fragments.graphql)
|
|
15
17
|
// ---------------------------------------------------------------------------
|
|
@@ -135,6 +137,53 @@ const CART_DISCOUNT_ALLOCATION_FRAGMENT = `
|
|
|
135
137
|
amount { ...Money }
|
|
136
138
|
}
|
|
137
139
|
`;
|
|
140
|
+
const MAILING_ADDRESS_FRAGMENT = `
|
|
141
|
+
fragment MailingAddress on MailingAddress {
|
|
142
|
+
id
|
|
143
|
+
firstName
|
|
144
|
+
lastName
|
|
145
|
+
name
|
|
146
|
+
company
|
|
147
|
+
streetLine1
|
|
148
|
+
streetLine2
|
|
149
|
+
city
|
|
150
|
+
state
|
|
151
|
+
stateCode
|
|
152
|
+
country
|
|
153
|
+
countryCode
|
|
154
|
+
postalCode
|
|
155
|
+
phone
|
|
156
|
+
isDefault
|
|
157
|
+
}
|
|
158
|
+
`;
|
|
159
|
+
const CART_SHIPPING_METHOD_FRAGMENT = `
|
|
160
|
+
fragment CartShippingMethod on CartShippingMethod {
|
|
161
|
+
handle
|
|
162
|
+
title
|
|
163
|
+
price { ...Money }
|
|
164
|
+
}
|
|
165
|
+
`;
|
|
166
|
+
const CART_APPLIED_GIFT_CARD_FRAGMENT = `
|
|
167
|
+
fragment CartAppliedGiftCard on CartAppliedGiftCard {
|
|
168
|
+
maskedCode
|
|
169
|
+
lastCharacters
|
|
170
|
+
appliedAmount { ...Money }
|
|
171
|
+
remainingBalance { ...Money }
|
|
172
|
+
}
|
|
173
|
+
`;
|
|
174
|
+
const CART_SELECTED_PAYMENT_METHOD_FRAGMENT = `
|
|
175
|
+
fragment CartSelectedPaymentMethod on PaymentMethod {
|
|
176
|
+
id
|
|
177
|
+
name
|
|
178
|
+
provider
|
|
179
|
+
type
|
|
180
|
+
icon
|
|
181
|
+
description
|
|
182
|
+
isDefault
|
|
183
|
+
supportedCurrencies
|
|
184
|
+
position
|
|
185
|
+
}
|
|
186
|
+
`;
|
|
138
187
|
const CART_FRAGMENT = `
|
|
139
188
|
fragment Cart on Cart {
|
|
140
189
|
id
|
|
@@ -155,6 +204,13 @@ const CART_FRAGMENT = `
|
|
|
155
204
|
discountAllocations { ...CartDiscountAllocation }
|
|
156
205
|
note
|
|
157
206
|
attributes { key value }
|
|
207
|
+
email
|
|
208
|
+
phone
|
|
209
|
+
shippingAddress { ...MailingAddress }
|
|
210
|
+
billingAddress { ...MailingAddress }
|
|
211
|
+
selectedShippingMethod { ...CartShippingMethod }
|
|
212
|
+
selectedPaymentMethod { ...CartSelectedPaymentMethod }
|
|
213
|
+
appliedGiftCards { ...CartAppliedGiftCard }
|
|
158
214
|
createdAt
|
|
159
215
|
updatedAt
|
|
160
216
|
}
|
|
@@ -163,8 +219,37 @@ const CART_FRAGMENT = `
|
|
|
163
219
|
${CART_BUYER_IDENTITY_FRAGMENT}
|
|
164
220
|
${CART_DISCOUNT_CODE_FRAGMENT}
|
|
165
221
|
${CART_DISCOUNT_ALLOCATION_FRAGMENT}
|
|
222
|
+
${MAILING_ADDRESS_FRAGMENT}
|
|
223
|
+
${CART_SHIPPING_METHOD_FRAGMENT}
|
|
224
|
+
${CART_APPLIED_GIFT_CARD_FRAGMENT}
|
|
225
|
+
${CART_SELECTED_PAYMENT_METHOD_FRAGMENT}
|
|
166
226
|
${PAGE_INFO_FRAGMENT}
|
|
167
227
|
`;
|
|
228
|
+
const ORDER_FRAGMENT = `
|
|
229
|
+
fragment Order on Order {
|
|
230
|
+
id
|
|
231
|
+
orderNumber
|
|
232
|
+
totals {
|
|
233
|
+
total { ...Money }
|
|
234
|
+
subtotal { ...Money }
|
|
235
|
+
totalTax { ...Money }
|
|
236
|
+
totalShipping { ...Money }
|
|
237
|
+
}
|
|
238
|
+
status
|
|
239
|
+
paymentStatus
|
|
240
|
+
fulfillmentStatus
|
|
241
|
+
processedAt
|
|
242
|
+
confirmedAt
|
|
243
|
+
cancelledAt
|
|
244
|
+
expiredAt
|
|
245
|
+
shippingAddress { ...MailingAddress }
|
|
246
|
+
itemCount
|
|
247
|
+
canCreatePayment
|
|
248
|
+
paymentMethodType
|
|
249
|
+
}
|
|
250
|
+
${MONEY_FRAGMENT}
|
|
251
|
+
${MAILING_ADDRESS_FRAGMENT}
|
|
252
|
+
`;
|
|
168
253
|
const USER_ERROR_FRAGMENT = `
|
|
169
254
|
fragment UserError on UserError {
|
|
170
255
|
message
|
|
@@ -172,87 +257,245 @@ const USER_ERROR_FRAGMENT = `
|
|
|
172
257
|
field
|
|
173
258
|
}
|
|
174
259
|
`;
|
|
260
|
+
const CART_WARNING_FRAGMENT = `
|
|
261
|
+
fragment CartWarning on CartWarning {
|
|
262
|
+
message
|
|
263
|
+
code
|
|
264
|
+
target
|
|
265
|
+
}
|
|
266
|
+
`;
|
|
175
267
|
// ---------------------------------------------------------------------------
|
|
176
268
|
// Queries
|
|
177
269
|
// ---------------------------------------------------------------------------
|
|
178
|
-
export const CART_QUERY = `
|
|
270
|
+
export const CART_QUERY = composeOperation(`
|
|
179
271
|
query Cart($id: ID!) {
|
|
180
272
|
cart(id: $id) {
|
|
181
273
|
...Cart
|
|
182
274
|
}
|
|
183
275
|
}
|
|
184
276
|
${CART_FRAGMENT}
|
|
185
|
-
|
|
277
|
+
`);
|
|
186
278
|
// ---------------------------------------------------------------------------
|
|
187
279
|
// Mutations
|
|
188
280
|
// ---------------------------------------------------------------------------
|
|
189
|
-
export const CART_CREATE = `
|
|
281
|
+
export const CART_CREATE = composeOperation(`
|
|
190
282
|
mutation CartCreate($input: CartCreateInput) {
|
|
191
283
|
cartCreate(input: $input) {
|
|
192
284
|
cart { ...Cart }
|
|
193
285
|
userErrors { ...UserError }
|
|
286
|
+
warnings { ...CartWarning }
|
|
194
287
|
}
|
|
195
288
|
}
|
|
196
289
|
${CART_FRAGMENT}
|
|
197
290
|
${USER_ERROR_FRAGMENT}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
291
|
+
${CART_WARNING_FRAGMENT}
|
|
292
|
+
`);
|
|
293
|
+
export const CART_ADD_LINES = composeOperation(`
|
|
294
|
+
mutation CartAddLines($id: ID!, $lines: [CartLineInput!]!) {
|
|
295
|
+
cartAddLines(id: $id, lines: $lines) {
|
|
202
296
|
cart { ...Cart }
|
|
203
297
|
userErrors { ...UserError }
|
|
298
|
+
warnings { ...CartWarning }
|
|
204
299
|
}
|
|
205
300
|
}
|
|
206
301
|
${CART_FRAGMENT}
|
|
207
302
|
${USER_ERROR_FRAGMENT}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
303
|
+
${CART_WARNING_FRAGMENT}
|
|
304
|
+
`);
|
|
305
|
+
export const CART_UPDATE_LINES = composeOperation(`
|
|
306
|
+
mutation CartUpdateLines($id: ID!, $lines: [CartLineUpdateInput!]!) {
|
|
307
|
+
cartUpdateLines(id: $id, lines: $lines) {
|
|
212
308
|
cart { ...Cart }
|
|
213
309
|
userErrors { ...UserError }
|
|
310
|
+
warnings { ...CartWarning }
|
|
214
311
|
}
|
|
215
312
|
}
|
|
216
313
|
${CART_FRAGMENT}
|
|
217
314
|
${USER_ERROR_FRAGMENT}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
315
|
+
${CART_WARNING_FRAGMENT}
|
|
316
|
+
`);
|
|
317
|
+
export const CART_REMOVE_LINES = composeOperation(`
|
|
318
|
+
mutation CartRemoveLines($id: ID!, $lineIds: [ID!]!) {
|
|
319
|
+
cartRemoveLines(id: $id, lineIds: $lineIds) {
|
|
222
320
|
cart { ...Cart }
|
|
223
321
|
userErrors { ...UserError }
|
|
322
|
+
warnings { ...CartWarning }
|
|
224
323
|
}
|
|
225
324
|
}
|
|
226
325
|
${CART_FRAGMENT}
|
|
227
326
|
${USER_ERROR_FRAGMENT}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
327
|
+
${CART_WARNING_FRAGMENT}
|
|
328
|
+
`);
|
|
329
|
+
export const CART_DISCOUNT_CODES_UPDATE = composeOperation(`
|
|
330
|
+
mutation CartDiscountCodesUpdate($id: ID!, $discountCodes: [String!]!) {
|
|
331
|
+
cartDiscountCodesUpdate(id: $id, discountCodes: $discountCodes) {
|
|
232
332
|
cart { ...Cart }
|
|
233
333
|
userErrors { ...UserError }
|
|
334
|
+
warnings { ...CartWarning }
|
|
234
335
|
}
|
|
235
336
|
}
|
|
236
337
|
${CART_FRAGMENT}
|
|
237
338
|
${USER_ERROR_FRAGMENT}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
339
|
+
${CART_WARNING_FRAGMENT}
|
|
340
|
+
`);
|
|
341
|
+
export const CART_UPDATE_NOTE = composeOperation(`
|
|
342
|
+
mutation CartUpdateNote($id: ID!, $note: String!) {
|
|
343
|
+
cartUpdateNote(id: $id, note: $note) {
|
|
242
344
|
cart { ...Cart }
|
|
243
345
|
userErrors { ...UserError }
|
|
346
|
+
warnings { ...CartWarning }
|
|
244
347
|
}
|
|
245
348
|
}
|
|
246
349
|
${CART_FRAGMENT}
|
|
247
350
|
${USER_ERROR_FRAGMENT}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
351
|
+
${CART_WARNING_FRAGMENT}
|
|
352
|
+
`);
|
|
353
|
+
export const CART_UPDATE_BUYER_IDENTITY = composeOperation(`
|
|
354
|
+
mutation CartUpdateBuyerIdentity($id: ID!, $buyerIdentity: CartBuyerIdentityInput!) {
|
|
355
|
+
cartUpdateBuyerIdentity(id: $id, buyerIdentity: $buyerIdentity) {
|
|
252
356
|
cart { ...Cart }
|
|
253
357
|
userErrors { ...UserError }
|
|
358
|
+
warnings { ...CartWarning }
|
|
254
359
|
}
|
|
255
360
|
}
|
|
256
361
|
${CART_FRAGMENT}
|
|
257
362
|
${USER_ERROR_FRAGMENT}
|
|
258
|
-
|
|
363
|
+
${CART_WARNING_FRAGMENT}
|
|
364
|
+
`);
|
|
365
|
+
// ---------------------------------------------------------------------------
|
|
366
|
+
// Phase 3 — Cart completion lifecycle mutations
|
|
367
|
+
// ---------------------------------------------------------------------------
|
|
368
|
+
export const CART_SET_SHIPPING_ADDRESS = composeOperation(`
|
|
369
|
+
mutation CartSetShippingAddress($input: CartSetShippingAddressInput!) {
|
|
370
|
+
cartSetShippingAddress(input: $input) {
|
|
371
|
+
cart { ...Cart }
|
|
372
|
+
userErrors { ...UserError }
|
|
373
|
+
warnings { ...CartWarning }
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
${CART_FRAGMENT}
|
|
377
|
+
${USER_ERROR_FRAGMENT}
|
|
378
|
+
${CART_WARNING_FRAGMENT}
|
|
379
|
+
`);
|
|
380
|
+
export const CART_SET_BILLING_ADDRESS = composeOperation(`
|
|
381
|
+
mutation CartSetBillingAddress($input: CartSetBillingAddressInput!) {
|
|
382
|
+
cartSetBillingAddress(input: $input) {
|
|
383
|
+
cart { ...Cart }
|
|
384
|
+
userErrors { ...UserError }
|
|
385
|
+
warnings { ...CartWarning }
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
${CART_FRAGMENT}
|
|
389
|
+
${USER_ERROR_FRAGMENT}
|
|
390
|
+
${CART_WARNING_FRAGMENT}
|
|
391
|
+
`);
|
|
392
|
+
export const CART_SELECT_SHIPPING_METHOD = composeOperation(`
|
|
393
|
+
mutation CartSelectShippingMethod($input: CartSelectShippingMethodInput!) {
|
|
394
|
+
cartSelectShippingMethod(input: $input) {
|
|
395
|
+
cart { ...Cart }
|
|
396
|
+
userErrors { ...UserError }
|
|
397
|
+
warnings { ...CartWarning }
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
${CART_FRAGMENT}
|
|
401
|
+
${USER_ERROR_FRAGMENT}
|
|
402
|
+
${CART_WARNING_FRAGMENT}
|
|
403
|
+
`);
|
|
404
|
+
export const CART_SELECT_PAYMENT_METHOD = composeOperation(`
|
|
405
|
+
mutation CartSelectPaymentMethod($input: CartSelectPaymentMethodInput!) {
|
|
406
|
+
cartSelectPaymentMethod(input: $input) {
|
|
407
|
+
cart { ...Cart }
|
|
408
|
+
userErrors { ...UserError }
|
|
409
|
+
warnings { ...CartWarning }
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
${CART_FRAGMENT}
|
|
413
|
+
${USER_ERROR_FRAGMENT}
|
|
414
|
+
${CART_WARNING_FRAGMENT}
|
|
415
|
+
`);
|
|
416
|
+
export const CART_APPLY_GIFT_CARD = composeOperation(`
|
|
417
|
+
mutation CartApplyGiftCard($input: CartApplyGiftCardInput!) {
|
|
418
|
+
cartApplyGiftCard(input: $input) {
|
|
419
|
+
cart { ...Cart }
|
|
420
|
+
userErrors { ...UserError }
|
|
421
|
+
warnings { ...CartWarning }
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
${CART_FRAGMENT}
|
|
425
|
+
${USER_ERROR_FRAGMENT}
|
|
426
|
+
${CART_WARNING_FRAGMENT}
|
|
427
|
+
`);
|
|
428
|
+
export const CART_REMOVE_GIFT_CARD = composeOperation(`
|
|
429
|
+
mutation CartRemoveGiftCard($input: CartRemoveGiftCardInput!) {
|
|
430
|
+
cartRemoveGiftCard(input: $input) {
|
|
431
|
+
cart { ...Cart }
|
|
432
|
+
userErrors { ...UserError }
|
|
433
|
+
warnings { ...CartWarning }
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
${CART_FRAGMENT}
|
|
437
|
+
${USER_ERROR_FRAGMENT}
|
|
438
|
+
${CART_WARNING_FRAGMENT}
|
|
439
|
+
`);
|
|
440
|
+
export const CART_UPDATE_GIFT_CARD_RECIPIENT = composeOperation(`
|
|
441
|
+
mutation CartUpdateGiftCardRecipient($input: CartUpdateGiftCardRecipientInput!) {
|
|
442
|
+
cartUpdateGiftCardRecipient(input: $input) {
|
|
443
|
+
cart { ...Cart }
|
|
444
|
+
userErrors { ...UserError }
|
|
445
|
+
warnings { ...CartWarning }
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
${CART_FRAGMENT}
|
|
449
|
+
${USER_ERROR_FRAGMENT}
|
|
450
|
+
${CART_WARNING_FRAGMENT}
|
|
451
|
+
`);
|
|
452
|
+
/**
|
|
453
|
+
* cartComplete — returns the Order created from the cart (carrying
|
|
454
|
+
* `canCreatePayment` + `paymentMethodType` signals for post-completion payment
|
|
455
|
+
* flow decisions). The cart itself is NOT returned — after completion it is
|
|
456
|
+
* CONVERTED/locked, so the storefront drops its local cart and works with the
|
|
457
|
+
* Order. `order` is non-null on success. `paymentUrl` is intentionally NOT in
|
|
458
|
+
* the payload (Decision D4) — the storefront calls a separate `paymentCreate`
|
|
459
|
+
* mutation after checking `order.canCreatePayment`.
|
|
460
|
+
*/
|
|
461
|
+
export const CART_COMPLETE = composeOperation(`
|
|
462
|
+
mutation CartComplete($input: CartCompleteInput!) {
|
|
463
|
+
cartComplete(input: $input) {
|
|
464
|
+
order { ...Order }
|
|
465
|
+
userErrors { ...UserError }
|
|
466
|
+
warnings { ...CartWarning }
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
${ORDER_FRAGMENT}
|
|
470
|
+
${USER_ERROR_FRAGMENT}
|
|
471
|
+
${CART_WARNING_FRAGMENT}
|
|
472
|
+
`);
|
|
473
|
+
/**
|
|
474
|
+
* cartValidateDiscountCode Query — read-only preview discount applicability
|
|
475
|
+
* (Decision D3). No cart side effects; storefront UI używa do inline feedback
|
|
476
|
+
* gdy klient wpisuje kod (przed wywołaniem cartDiscountCodesUpdate).
|
|
477
|
+
*
|
|
478
|
+
* Caching guidance: `fetchPolicy: 'network-only'` lub key zawierający
|
|
479
|
+
* `cart.subtotal` (discount eligibility może zależeć od minimum order amount).
|
|
480
|
+
*/
|
|
481
|
+
export const CART_VALIDATE_DISCOUNT_CODE = composeOperation(`
|
|
482
|
+
query CartValidateDiscountCode($cartId: ID!, $discountCode: String!) {
|
|
483
|
+
cartValidateDiscountCode(cartId: $cartId, discountCode: $discountCode) {
|
|
484
|
+
isValid
|
|
485
|
+
discount {
|
|
486
|
+
code
|
|
487
|
+
title
|
|
488
|
+
type
|
|
489
|
+
value
|
|
490
|
+
discountAmount {
|
|
491
|
+
amount
|
|
492
|
+
currencyCode
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
error {
|
|
496
|
+
code
|
|
497
|
+
message
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
`);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* composeOperation — assemble a GraphQL operation string from an operation body
|
|
3
|
+
* plus its fragment definitions, deduplicating fragments by name.
|
|
4
|
+
*
|
|
5
|
+
* The SDK hand-maintains operation strings (no codegen) by concatenating fragment
|
|
6
|
+
* constants. Each constant carries its own transitive dependency closure — e.g.
|
|
7
|
+
* the Cart fragment tree pulls in `Money`, and the Order fragment tree pulls in
|
|
8
|
+
* `Money` too. When one operation selects two fields whose fragment trees overlap
|
|
9
|
+
* (the only case today: `cartComplete` returns both `cart` and `order`), the naive
|
|
10
|
+
* concatenation emits the shared fragment twice → GraphQL `UniqueFragmentNames`
|
|
11
|
+
* violation → the server rejects the whole request (HTTP 400).
|
|
12
|
+
*
|
|
13
|
+
* `composeOperation` scans the concatenated string, extracts every
|
|
14
|
+
* `fragment Name on Type { ... }` block (brace-matched), keeps the first
|
|
15
|
+
* occurrence of each name, and reassembles: operation body first, then each
|
|
16
|
+
* unique fragment. Every exported operation is wrapped in it, so a future
|
|
17
|
+
* operation combining two fragment trees can never reintroduce the collision.
|
|
18
|
+
*
|
|
19
|
+
* Pure string processing — no `graphql` dependency, so `core/` stays 0-deps.
|
|
20
|
+
* Inputs are our own controlled operation constants (no GraphQL string literals
|
|
21
|
+
* or comments), so the brace-matcher does not need a full lexer.
|
|
22
|
+
*/
|
|
23
|
+
export declare function composeOperation(raw: string): string;
|
|
24
|
+
//# sourceMappingURL=compose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../../src/core/operations/compose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAuCpD"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* composeOperation — assemble a GraphQL operation string from an operation body
|
|
3
|
+
* plus its fragment definitions, deduplicating fragments by name.
|
|
4
|
+
*
|
|
5
|
+
* The SDK hand-maintains operation strings (no codegen) by concatenating fragment
|
|
6
|
+
* constants. Each constant carries its own transitive dependency closure — e.g.
|
|
7
|
+
* the Cart fragment tree pulls in `Money`, and the Order fragment tree pulls in
|
|
8
|
+
* `Money` too. When one operation selects two fields whose fragment trees overlap
|
|
9
|
+
* (the only case today: `cartComplete` returns both `cart` and `order`), the naive
|
|
10
|
+
* concatenation emits the shared fragment twice → GraphQL `UniqueFragmentNames`
|
|
11
|
+
* violation → the server rejects the whole request (HTTP 400).
|
|
12
|
+
*
|
|
13
|
+
* `composeOperation` scans the concatenated string, extracts every
|
|
14
|
+
* `fragment Name on Type { ... }` block (brace-matched), keeps the first
|
|
15
|
+
* occurrence of each name, and reassembles: operation body first, then each
|
|
16
|
+
* unique fragment. Every exported operation is wrapped in it, so a future
|
|
17
|
+
* operation combining two fragment trees can never reintroduce the collision.
|
|
18
|
+
*
|
|
19
|
+
* Pure string processing — no `graphql` dependency, so `core/` stays 0-deps.
|
|
20
|
+
* Inputs are our own controlled operation constants (no GraphQL string literals
|
|
21
|
+
* or comments), so the brace-matcher does not need a full lexer.
|
|
22
|
+
*/
|
|
23
|
+
export function composeOperation(raw) {
|
|
24
|
+
const fragmentStart = /fragment\s+(\w+)\s+on\s+\w+\s*\{/g;
|
|
25
|
+
const fragments = new Map();
|
|
26
|
+
const bodyParts = [];
|
|
27
|
+
let cursor = 0;
|
|
28
|
+
let match;
|
|
29
|
+
while ((match = fragmentStart.exec(raw)) !== null) {
|
|
30
|
+
const blockStart = match.index;
|
|
31
|
+
// Text before this fragment — the operation body on the first iteration,
|
|
32
|
+
// inter-fragment whitespace afterwards.
|
|
33
|
+
bodyParts.push(raw.slice(cursor, blockStart));
|
|
34
|
+
// Brace-match from the fragment's opening `{` to its closing `}`. Nested
|
|
35
|
+
// braces (field arguments like `url(transform: { maxWidth: 300 })`) net out.
|
|
36
|
+
let depth = 1;
|
|
37
|
+
let i = blockStart + match[0].length;
|
|
38
|
+
while (i < raw.length && depth > 0) {
|
|
39
|
+
const ch = raw[i];
|
|
40
|
+
if (ch === '{')
|
|
41
|
+
depth++;
|
|
42
|
+
else if (ch === '}')
|
|
43
|
+
depth--;
|
|
44
|
+
i++;
|
|
45
|
+
}
|
|
46
|
+
const name = match[1];
|
|
47
|
+
if (!fragments.has(name)) {
|
|
48
|
+
fragments.set(name, raw.slice(blockStart, i).trim());
|
|
49
|
+
}
|
|
50
|
+
cursor = i;
|
|
51
|
+
fragmentStart.lastIndex = i;
|
|
52
|
+
}
|
|
53
|
+
bodyParts.push(raw.slice(cursor));
|
|
54
|
+
const body = bodyParts.join('').trim();
|
|
55
|
+
return fragments.size > 0
|
|
56
|
+
? [body, ...fragments.values()].join('\n\n')
|
|
57
|
+
: body;
|
|
58
|
+
}
|
|
@@ -13,15 +13,16 @@
|
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
15
|
import type { Cart, CartLineInput, CartLineUpdateInput } from '../../core/cart/types';
|
|
16
|
+
import type { CartMutationOutcome } from '../../core/cart/cart-client';
|
|
16
17
|
export declare function useCartManager(): {
|
|
17
18
|
getCart: () => Promise<Cart | null>;
|
|
18
19
|
addItem: (lines: CartLineInput[], options?: {
|
|
19
20
|
forceNewCart?: boolean;
|
|
20
|
-
}) => Promise<
|
|
21
|
-
updateItem: (lines: CartLineUpdateInput[]) => Promise<
|
|
22
|
-
removeItem: (lineIds: string[]) => Promise<
|
|
23
|
-
updateDiscountCodes: (codes: string[]) => Promise<
|
|
24
|
-
updateNote: (note: string) => Promise<
|
|
21
|
+
}) => Promise<CartMutationOutcome>;
|
|
22
|
+
updateItem: (lines: CartLineUpdateInput[]) => Promise<CartMutationOutcome>;
|
|
23
|
+
removeItem: (lineIds: string[]) => Promise<CartMutationOutcome>;
|
|
24
|
+
updateDiscountCodes: (codes: string[]) => Promise<CartMutationOutcome>;
|
|
25
|
+
updateNote: (note: string) => Promise<CartMutationOutcome>;
|
|
25
26
|
clearCart: () => void;
|
|
26
27
|
getCartId: () => string | null;
|
|
27
28
|
isLoading: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-cart-manager.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-cart-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"use-cart-manager.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-cart-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAwBvE,wBAAgB,cAAc;mBAiCU,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;qBAoBjD,aAAa,EAAE,YACZ;QAAE,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,KACnC,OAAO,CAAC,mBAAmB,CAAC;wBAyBtB,mBAAmB,EAAE,KAC3B,OAAO,CAAC,mBAAmB,CAAC;0BAuBgB,MAAM,EAAE,KAAG,OAAO,CAAC,mBAAmB,CAAC;iCAuBhC,MAAM,EAAE,KAAG,OAAO,CAAC,mBAAmB,CAAC;uBAoBjD,MAAM,KAAG,OAAO,CAAC,mBAAmB,CAAC;;qBA2B/C,MAAM,GAAG,IAAI;;;EAiBhD"}
|
|
@@ -49,7 +49,7 @@ export function useCartManager() {
|
|
|
49
49
|
if (existing)
|
|
50
50
|
return existing;
|
|
51
51
|
}
|
|
52
|
-
const cart = await cartClient.create();
|
|
52
|
+
const { cart } = await cartClient.create();
|
|
53
53
|
setCartIdCookie(cart.id);
|
|
54
54
|
return cart.id;
|
|
55
55
|
}, [cartClient]);
|
|
@@ -90,8 +90,7 @@ export function useCartManager() {
|
|
|
90
90
|
setIsLoading(true);
|
|
91
91
|
try {
|
|
92
92
|
const cartId = await getOrCreateCartId(options?.forceNewCart);
|
|
93
|
-
|
|
94
|
-
return cart;
|
|
93
|
+
return await cartClient.addItems(cartId, lines);
|
|
95
94
|
}
|
|
96
95
|
catch (err) {
|
|
97
96
|
if (isCartExpired(err) && !options?.forceNewCart) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doswiftly/storefront-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"description": "Storefront runtime SDK for DoSwiftly Commerce — layered transport, middleware pipeline, React providers, Zustand stores, cache strategies. 0 runtime dependencies in core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|