@reactionary/source 0.0.41 → 0.0.48

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.
Files changed (125) hide show
  1. package/.claude/settings.local.json +28 -0
  2. package/.env-template +8 -5
  3. package/.vscode/settings.json +5 -0
  4. package/README.md +41 -0
  5. package/core/package.json +3 -1
  6. package/core/src/cache/cache.interface.ts +14 -18
  7. package/core/src/cache/memory-cache.ts +56 -0
  8. package/core/src/cache/noop-cache.ts +5 -23
  9. package/core/src/cache/redis-cache.ts +28 -38
  10. package/core/src/client/client-builder.ts +3 -3
  11. package/core/src/client/client.ts +11 -9
  12. package/core/src/decorators/reactionary.decorator.ts +80 -8
  13. package/core/src/index.ts +5 -29
  14. package/core/src/initialization.ts +43 -0
  15. package/core/src/providers/analytics.provider.ts +1 -1
  16. package/core/src/providers/base.provider.ts +61 -25
  17. package/core/src/providers/cart-payment.provider.ts +57 -0
  18. package/core/src/providers/cart.provider.ts +131 -8
  19. package/core/src/providers/category.provider.ts +9 -9
  20. package/core/src/providers/identity.provider.ts +8 -7
  21. package/core/src/providers/index.ts +12 -0
  22. package/core/src/providers/inventory.provider.ts +4 -4
  23. package/core/src/providers/price.provider.ts +7 -7
  24. package/core/src/providers/product.provider.ts +17 -5
  25. package/core/src/providers/profile.provider.ts +22 -0
  26. package/core/src/providers/search.provider.ts +4 -4
  27. package/core/src/providers/store.provider.ts +14 -0
  28. package/core/src/schemas/capabilities.schema.ts +3 -1
  29. package/core/src/schemas/models/analytics.model.ts +1 -1
  30. package/core/src/schemas/models/cart.model.ts +16 -3
  31. package/core/src/schemas/models/identifiers.model.ts +90 -22
  32. package/core/src/schemas/models/identity.model.ts +23 -7
  33. package/core/src/schemas/models/index.ts +15 -0
  34. package/core/src/schemas/models/payment.model.ts +41 -0
  35. package/core/src/schemas/models/profile.model.ts +35 -0
  36. package/core/src/schemas/models/shipping-method.model.ts +14 -0
  37. package/core/src/schemas/models/store.model.ts +11 -0
  38. package/core/src/schemas/mutations/cart-payment.mutation.ts +21 -0
  39. package/core/src/schemas/mutations/cart.mutation.ts +62 -3
  40. package/core/src/schemas/mutations/identity.mutation.ts +8 -1
  41. package/core/src/schemas/mutations/index.ts +10 -0
  42. package/core/src/schemas/mutations/profile.mutation.ts +9 -0
  43. package/core/src/schemas/queries/cart-payment.query.ts +12 -0
  44. package/core/src/schemas/queries/cart.query.ts +1 -1
  45. package/core/src/schemas/queries/identity.query.ts +1 -1
  46. package/core/src/schemas/queries/index.ts +3 -0
  47. package/core/src/schemas/queries/inventory.query.ts +4 -12
  48. package/core/src/schemas/queries/price.query.ts +1 -1
  49. package/core/src/schemas/queries/profile.query.ts +7 -0
  50. package/core/src/schemas/queries/search.query.ts +1 -1
  51. package/core/src/schemas/queries/store.query.ts +11 -0
  52. package/core/src/schemas/session.schema.ts +31 -6
  53. package/eslint.config.mjs +7 -0
  54. package/examples/next/src/app/page.tsx +4 -12
  55. package/examples/node/package.json +1 -3
  56. package/examples/node/src/basic/basic-node-provider-model-extension.spec.ts +9 -8
  57. package/examples/node/src/basic/basic-node-provider-query-extension.spec.ts +4 -3
  58. package/examples/node/src/basic/basic-node-setup.spec.ts +4 -5
  59. package/nx.json +1 -0
  60. package/otel/src/metrics.ts +2 -1
  61. package/otel/src/provider-instrumentation.ts +2 -1
  62. package/otel/src/tracer.ts +7 -6
  63. package/otel/src/trpc-middleware.ts +3 -2
  64. package/package.json +2 -1
  65. package/providers/algolia/src/core/initialize.ts +4 -3
  66. package/providers/algolia/src/providers/product.provider.ts +15 -13
  67. package/providers/algolia/src/providers/search.provider.ts +9 -9
  68. package/providers/algolia/src/schema/capabilities.schema.ts +1 -1
  69. package/providers/algolia/src/test/search.provider.spec.ts +10 -10
  70. package/providers/algolia/src/test/test-utils.ts +9 -4
  71. package/providers/commercetools/README.md +27 -0
  72. package/providers/commercetools/src/core/client.ts +164 -117
  73. package/providers/commercetools/src/core/initialize.ts +24 -14
  74. package/providers/commercetools/src/providers/cart-payment.provider.ts +193 -0
  75. package/providers/commercetools/src/providers/cart.provider.ts +402 -125
  76. package/providers/commercetools/src/providers/category.provider.ts +35 -35
  77. package/providers/commercetools/src/providers/identity.provider.ts +23 -75
  78. package/providers/commercetools/src/providers/index.ts +2 -0
  79. package/providers/commercetools/src/providers/inventory.provider.ts +69 -40
  80. package/providers/commercetools/src/providers/price.provider.ts +79 -47
  81. package/providers/commercetools/src/providers/product.provider.ts +36 -30
  82. package/providers/commercetools/src/providers/profile.provider.ts +61 -0
  83. package/providers/commercetools/src/providers/search.provider.ts +16 -12
  84. package/providers/commercetools/src/providers/store.provider.ts +78 -0
  85. package/providers/commercetools/src/schema/capabilities.schema.ts +3 -1
  86. package/providers/commercetools/src/schema/commercetools.schema.ts +18 -0
  87. package/providers/commercetools/src/schema/configuration.schema.ts +2 -1
  88. package/providers/commercetools/src/test/cart-payment.provider.spec.ts +145 -0
  89. package/providers/commercetools/src/test/cart.provider.spec.ts +82 -22
  90. package/providers/commercetools/src/test/category.provider.spec.ts +18 -17
  91. package/providers/commercetools/src/test/identity.provider.spec.ts +88 -0
  92. package/providers/commercetools/src/test/inventory.provider.spec.ts +41 -0
  93. package/providers/commercetools/src/test/price.provider.spec.ts +9 -8
  94. package/providers/commercetools/src/test/product.provider.spec.ts +33 -5
  95. package/providers/commercetools/src/test/profile.provider.spec.ts +49 -0
  96. package/providers/commercetools/src/test/search.provider.spec.ts +8 -7
  97. package/providers/commercetools/src/test/store.provider.spec.ts +37 -0
  98. package/providers/commercetools/src/test/test-utils.ts +7 -31
  99. package/providers/fake/src/core/initialize.ts +96 -38
  100. package/providers/fake/src/providers/analytics.provider.ts +6 -5
  101. package/providers/fake/src/providers/cart.provider.ts +66 -19
  102. package/providers/fake/src/providers/category.provider.ts +12 -12
  103. package/providers/fake/src/providers/identity.provider.ts +22 -14
  104. package/providers/fake/src/providers/index.ts +1 -0
  105. package/providers/fake/src/providers/inventory.provider.ts +13 -13
  106. package/providers/fake/src/providers/price.provider.ts +13 -13
  107. package/providers/fake/src/providers/product.provider.ts +13 -10
  108. package/providers/fake/src/providers/search.provider.ts +7 -5
  109. package/providers/fake/src/providers/store.provider.ts +47 -0
  110. package/providers/fake/src/schema/capabilities.schema.ts +4 -1
  111. package/providers/fake/src/test/cart.provider.spec.ts +18 -18
  112. package/providers/fake/src/test/category.provider.spec.ts +55 -37
  113. package/providers/fake/src/test/price.provider.spec.ts +9 -14
  114. package/providers/fake/src/test/product.provider.spec.ts +27 -0
  115. package/providers/fake/src/test/test-utils.ts +2 -28
  116. package/providers/posthog/src/core/initialize.ts +3 -3
  117. package/providers/posthog/src/schema/capabilities.schema.ts +1 -1
  118. package/trpc/src/client.ts +42 -41
  119. package/trpc/src/index.ts +4 -3
  120. package/trpc/src/integration.spec.ts +11 -11
  121. package/trpc/src/server.ts +26 -24
  122. package/trpc/src/test-utils.ts +9 -4
  123. package/trpc/src/types.ts +24 -22
  124. package/core/src/cache/cache-evaluation.interface.ts +0 -19
  125. package/examples/node/src/test-utils.ts +0 -26
@@ -1,23 +1,38 @@
1
1
  import {
2
- Cart,
3
2
  CartItemSchema,
4
- CartProvider,
5
- Cache,
6
- Currency,
3
+ CartProvider
7
4
  } from '@reactionary/core';
8
5
  import type {
9
6
  CartMutationItemAdd,
10
7
  CartMutationItemQuantityChange,
11
8
  CartMutationItemRemove,
12
9
  CartQueryById,
13
- Session,
10
+ CartIdentifier, CartMutationApplyCoupon,
11
+ CartMutationCheckout,
12
+ CartMutationDeleteCart,
13
+ CartMutationRemoveCoupon, CartMutationSetBillingAddress,
14
+ CartMutationSetShippingInfo,
15
+ CartMutationChangeCurrency, OrderIdentifier,
16
+ RequestContext,
17
+ Cart,
18
+ Currency
19
+ ,
20
+ Cache
14
21
  } from '@reactionary/core';
15
- import { CommercetoolsConfiguration } from '../schema/configuration.schema';
16
- import { z } from 'zod';
22
+ import type { CommercetoolsConfiguration } from '../schema/configuration.schema';
23
+ import type { z } from 'zod';
17
24
  import { CommercetoolsClient } from '../core/client';
18
- import type { Cart as CTCart } from '@commercetools/platform-sdk';
25
+ import type {
26
+ Cart as CTCart,
27
+ MyCartUpdateAction,
28
+ } from '@commercetools/platform-sdk';
19
29
  import { traced } from '@reactionary/otel';
20
-
30
+ import type {
31
+ CommercetoolsCartIdentifier} from '../schema/commercetools.schema';
32
+ import {
33
+ CommercetoolsCartIdentifierSchema,
34
+ CommercetoolsOrderIdentifierSchema,
35
+ } from '../schema/commercetools.schema';
21
36
 
22
37
  export class CommercetoolsCartProvider<
23
38
  T extends Cart = Cart
@@ -30,160 +45,420 @@ export class CommercetoolsCartProvider<
30
45
  cache: Cache
31
46
  ) {
32
47
  super(schema, cache);
33
-
34
48
  this.config = config;
35
49
  }
36
50
 
37
51
  @traced()
38
52
  public override async getById(
39
53
  payload: CartQueryById,
40
- session: Session
54
+ reqCtx: RequestContext
41
55
  ): Promise<T> {
42
- if (!payload.cart.key) {
43
- const result = this.newModel();
44
- result.meta = {
45
- cache: { hit: false, key: 'empty' },
46
- placeholder: true
47
- };
48
- return this.assert(result);
49
- }
56
+ try {
57
+ const client = await this.getClient(reqCtx);
50
58
 
51
- const client = this.getClient(session);
52
- const remote = await client
53
- .withId({ ID: payload.cart.key })
54
- .get()
55
- .execute();
59
+ const ctId = payload.cart as CommercetoolsCartIdentifier;
60
+
61
+ const remote = await client.carts.withId({ ID: ctId.key }).get().execute();
56
62
 
57
- return this.parseSingle(remote.body, session);
63
+ return this.parseSingle(remote.body, reqCtx);
64
+ } catch (e) {
65
+ return this.createEmptyCart();
66
+ }
58
67
  }
59
68
 
60
69
  @traced()
61
70
  public override async add(
62
71
  payload: CartMutationItemAdd,
63
- session: Session
72
+ reqCtx: RequestContext
73
+ ): Promise<T> {
74
+ const client = await this.getClient(reqCtx);
75
+
76
+ let cartIdentifier = payload.cart;
77
+ if (!cartIdentifier.key) {
78
+ cartIdentifier = await this.createCart(reqCtx);
79
+ }
80
+
81
+ return this.applyActions(
82
+ cartIdentifier,
83
+ [
84
+ {
85
+ action: 'addLineItem',
86
+ quantity: payload.quantity,
87
+ sku: payload.sku.key,
88
+ },
89
+ {
90
+ action: 'recalculate',
91
+ },
92
+ ],
93
+ reqCtx
94
+ );
95
+ }
96
+
97
+ @traced()
98
+ public override async remove(
99
+ payload: CartMutationItemRemove,
100
+ reqCtx: RequestContext
101
+ ): Promise<T> {
102
+ return this.applyActions(
103
+ payload.cart,
104
+ [
105
+ {
106
+ action: 'removeLineItem',
107
+ lineItemId: payload.item.key,
108
+ },
109
+ {
110
+ action: 'recalculate',
111
+ },
112
+ ],
113
+ reqCtx
114
+ );
115
+ }
116
+
117
+ @traced()
118
+ public override async changeQuantity(
119
+ payload: CartMutationItemQuantityChange,
120
+ reqCtx: RequestContext
64
121
  ): Promise<T> {
65
- const client = this.getClient(session);
66
-
67
- let id = payload.cart.key;
68
- let version = 0;
69
-
70
- if (!id) {
71
- const remoteCart = await client
72
- .post({
73
- body: {
74
- currency: session.languageContext.currencyCode || 'USD',
75
- country: session.languageContext.countryCode || 'US',
76
- locale: session.languageContext.locale,
122
+ if (payload.quantity === 0) {
123
+ // Changing quantity to 0 is not allowed. Use the remove call instead. This is done to avoid accidental removal of item.
124
+ // Calls with quantity 0 will just be ignored.
125
+ return this.getById({ cart: payload.cart }, reqCtx);
126
+ }
127
+
128
+ return this.applyActions(
129
+ payload.cart,
130
+ [
131
+ {
132
+ action: 'changeLineItemQuantity',
133
+ lineItemId: payload.item.key,
134
+ quantity: payload.quantity,
135
+ },
136
+ {
137
+ action: 'recalculate',
138
+ },
139
+ ],
140
+ reqCtx
141
+ );
142
+ }
143
+
144
+ @traced()
145
+ public override async getActiveCartId(
146
+ reqCtx: RequestContext
147
+ ): Promise<CartIdentifier> {
148
+ const client = await this.getClient(reqCtx);
149
+ try {
150
+ const carts = await client.activeCart
151
+ .get()
152
+ .execute();
153
+
154
+ return CommercetoolsCartIdentifierSchema.parse({
155
+ key: carts.body.id,
156
+ version: carts.body.version || 0
157
+ });
158
+ } catch (e: any) {
159
+ return CommercetoolsCartIdentifierSchema.parse({
160
+ key: '',
161
+ version: 0
162
+ });
163
+ }
164
+ }
165
+
166
+ @traced()
167
+ public override async deleteCart(
168
+ payload: CartMutationDeleteCart,
169
+ reqCtx: RequestContext
170
+ ): Promise<T> {
171
+ const client = await this.getClient(reqCtx);
172
+ if (payload.cart.key) {
173
+ const ctId = payload.cart as CommercetoolsCartIdentifier;
174
+
175
+ await client.carts
176
+ .withId({ ID: ctId.key })
177
+ .delete({
178
+ queryArgs: {
179
+ version: ctId.version,
180
+ dataErasure: false,
77
181
  },
78
182
  })
79
183
  .execute();
184
+ }
80
185
 
81
- id = remoteCart.body.id;
82
- version = remoteCart.body.version;
83
- } else {
84
- const existing = await client.withId({ ID: payload.cart.key }).get().execute();
85
- version = existing.body.version;
186
+ const activeCartId = await this.getActiveCartId(reqCtx);
187
+ return this.getById({ cart: activeCartId }, reqCtx);
188
+ }
189
+
190
+ @traced()
191
+ public override async setShippingInfo(
192
+ payload: CartMutationSetShippingInfo,
193
+ reqCtx: RequestContext
194
+ ): Promise<T> {
195
+ const client = await this.getClient(reqCtx);
196
+ const ctId = payload.cart as CommercetoolsCartIdentifier;
197
+
198
+ const actions: MyCartUpdateAction[] = new Array<MyCartUpdateAction>();
199
+ if (payload.shippingMethod) {
200
+ actions.push({
201
+ action: 'setShippingMethod',
202
+ shippingMethod: {
203
+ typeId: 'shipping-method',
204
+ id: payload.shippingMethod.key,
205
+ },
206
+ });
86
207
  }
87
208
 
88
- const remoteAdd = await client
89
- .withId({ ID: id })
209
+ if (payload.shippingAddress) {
210
+ actions.push({
211
+ action: 'setShippingAddress',
212
+ address: {
213
+ country: payload.shippingAddress.countryCode || reqCtx.taxJurisdiction.countryCode || 'US',
214
+ firstName: payload.shippingAddress.firstName,
215
+ lastName: payload.shippingAddress.lastName,
216
+ city: payload.shippingAddress.city,
217
+ postalCode: payload.shippingAddress.postalCode,
218
+ streetName: payload.shippingAddress.streetAddress,
219
+ streetNumber: payload.shippingAddress.streetNumber,
220
+ },
221
+ });
222
+ }
223
+
224
+ return this.applyActions(payload.cart, actions, reqCtx);
225
+ }
226
+
227
+ @traced()
228
+ public override setBillingAddress(
229
+ payload: CartMutationSetBillingAddress,
230
+ reqCtx: RequestContext
231
+ ): Promise<T> {
232
+ return this.applyActions(
233
+ payload.cart,
234
+ [
235
+ {
236
+ action: 'setBillingAddress',
237
+ address: {
238
+ email: payload.notificationEmailAddress,
239
+ mobile: payload.notificationPhoneNumber,
240
+ country: payload.billingAddress.countryCode || reqCtx.taxJurisdiction.countryCode || 'US',
241
+ firstName: payload.billingAddress.firstName,
242
+ lastName: payload.billingAddress.lastName,
243
+ city: payload.billingAddress.city,
244
+ postalCode: payload.billingAddress.postalCode,
245
+ streetName: payload.billingAddress.streetAddress,
246
+ streetNumber: payload.billingAddress.streetNumber,
247
+ },
248
+ },
249
+ {
250
+ action: 'setCustomerEmail',
251
+ email: payload.notificationEmailAddress,
252
+ },
253
+ {
254
+ action: 'setCountry',
255
+ country: payload.billingAddress.countryCode || reqCtx.taxJurisdiction.countryCode || 'US',
256
+ },
257
+ ],
258
+ reqCtx
259
+ );
260
+ }
261
+
262
+ @traced()
263
+ public override applyCouponCode(
264
+ payload: CartMutationApplyCoupon,
265
+ reqCtx: RequestContext
266
+ ): Promise<T> {
267
+ return this.applyActions(
268
+ payload.cart,
269
+ [
270
+ {
271
+ action: 'addDiscountCode',
272
+ code: payload.couponCode,
273
+ },
274
+ {
275
+ action: 'recalculate',
276
+ },
277
+ ],
278
+ reqCtx
279
+ );
280
+ }
281
+
282
+ @traced()
283
+ public override removeCouponCode(
284
+ payload: CartMutationRemoveCoupon,
285
+ reqCtx: RequestContext
286
+ ): Promise<T> {
287
+ return this.applyActions(
288
+ payload.cart,
289
+ [
290
+ {
291
+ action: 'removeDiscountCode',
292
+ discountCode: {
293
+ id: payload.couponCode,
294
+ typeId: 'discount-code',
295
+ },
296
+ },
297
+ {
298
+ action: 'recalculate',
299
+ },
300
+ ],
301
+ reqCtx
302
+ );
303
+ }
304
+
305
+ @traced()
306
+ public override async checkout(
307
+ payload: CartMutationCheckout,
308
+ reqCtx: RequestContext
309
+ ): Promise<OrderIdentifier> {
310
+ // In Commercetools, checkout is done by creating an order from the cart.
311
+
312
+ const client = await this.getClient(reqCtx);
313
+ const ctId = payload.cart as CommercetoolsCartIdentifier;
314
+
315
+ const orderResponse = await client.orders
90
316
  .post({
91
317
  body: {
92
- version: version,
93
- actions: [
94
- {
95
- action: 'addLineItem',
96
- quantity: payload.quantity,
97
- productId: payload.product.key,
98
- },
99
- ],
100
- },
318
+ version: ctId.version,
319
+ id: ctId.key,
320
+ }
101
321
  })
102
322
  .execute();
103
-
104
- return this.parseSingle(remoteAdd.body, session);
323
+ return CommercetoolsOrderIdentifierSchema.parse({
324
+ key: orderResponse.body.id,
325
+ version: orderResponse.body.version || 0,
326
+ });
105
327
  }
106
328
 
107
329
  @traced()
108
- public override async remove(
109
- payload: CartMutationItemRemove,
110
- session: Session
330
+ public override async changeCurrency(
331
+ payload: CartMutationChangeCurrency,
332
+ reqCtx: RequestContext
111
333
  ): Promise<T> {
112
- const client = this.getClient(session);
334
+ // ok, to do this we have to actually build a new cart, copy over all the items, and then delete the old cart.
335
+ // because Commercetools does not support changing currency of an existing cart.
336
+
337
+ // This is obviously not ideal, but it is what it is.
113
338
 
114
- const existing = await client
339
+ const client = await this.getClient(reqCtx);
340
+ const currentCart = await client.carts
115
341
  .withId({ ID: payload.cart.key })
116
342
  .get()
117
343
  .execute();
118
-
119
- const remote = await client
120
- .withId({ ID: payload.cart.key })
344
+ const newCart = await client.carts
121
345
  .post({
122
346
  body: {
123
- version: existing.body.version,
124
- actions: [
125
- {
126
- action: 'removeLineItem',
127
- lineItemId: payload.item.key,
128
- },
129
- ],
347
+ currency: payload.newCurrency,
348
+ locale: reqCtx.languageContext.locale,
130
349
  },
131
350
  })
132
351
  .execute();
133
352
 
134
- return this.parseSingle(remote.body, session);
135
- }
353
+ const newCartId = CommercetoolsCartIdentifierSchema.parse({
354
+ key: newCart.body.id,
355
+ version: newCart.body.version || 0,
356
+ });
136
357
 
137
- @traced()
138
- public override async changeQuantity(
139
- payload: CartMutationItemQuantityChange,
140
- session: Session
141
- ): Promise<T> {
142
- const client = this.getClient(session);
358
+ const cartItemAdds: MyCartUpdateAction[] = currentCart.body.lineItems.map(
359
+ (item) => ({
360
+ action: 'addLineItem',
361
+ sku: item.variant.sku || '',
362
+ quantity: item.quantity,
363
+ })
364
+ );
365
+
366
+ const response = await this.applyActions(
367
+ newCartId,
368
+ [
369
+ ...cartItemAdds,
370
+ {
371
+ action: 'recalculate',
372
+ },
373
+ ],
374
+ reqCtx
375
+ );
143
376
 
144
- const existing = await client
377
+ // now delete the old cart.
378
+ await client.carts
145
379
  .withId({ ID: payload.cart.key })
146
- .get()
380
+ .delete({
381
+ queryArgs: {
382
+ version: currentCart.body.version || 0,
383
+ dataErasure: false,
384
+ },
385
+ })
147
386
  .execute();
148
387
 
149
- const remote = await client
150
- .withId({ ID: payload.cart.key })
388
+ return response;
389
+ }
390
+
391
+ protected async createCart(reqCtx: RequestContext): Promise<CartIdentifier> {
392
+ const client = await this.getClient(reqCtx);
393
+ const response = await client.carts
151
394
  .post({
152
395
  body: {
153
- version: existing.body.version,
154
- actions: [
155
- {
156
- action: 'changeLineItemQuantity',
157
- lineItemId: payload.item.key,
158
- quantity: payload.quantity,
159
- },
160
- ],
396
+ currency: reqCtx.languageContext.currencyCode || 'USD',
397
+ country: reqCtx.taxJurisdiction.countryCode || 'US',
398
+ locale: reqCtx.languageContext.locale,
161
399
  },
162
400
  })
163
401
  .execute();
164
402
 
165
- return this.parseSingle(remote.body, session );
403
+ return CommercetoolsCartIdentifierSchema.parse({
404
+ key: response.body.id,
405
+ version: response.body.version || 0,
406
+ });
166
407
  }
167
408
 
168
- @traced()
169
- protected getClient(session: Session) {
170
- const client = new CommercetoolsClient(this.config).getClient(
171
- session.identity.token
172
- );
409
+ protected async applyActions(
410
+ cart: CartIdentifier,
411
+ actions: MyCartUpdateAction[],
412
+ reqCtx: RequestContext
413
+ ): Promise<T> {
414
+ const client = await this.getClient(reqCtx);
415
+ const ctId = cart as CommercetoolsCartIdentifier;
173
416
 
174
- const cartClient = client
175
- .withProjectKey({ projectKey: this.config.projectKey })
176
- .carts();
177
417
 
178
- return cartClient;
418
+
419
+ const response = await client.carts
420
+ .withId({ ID: ctId.key })
421
+ .post({
422
+ body: {
423
+ version: ctId.version,
424
+ actions,
425
+ },
426
+ })
427
+ .execute();
428
+
429
+ return this.parseSingle(response.body, reqCtx);
430
+
179
431
  }
180
432
 
433
+ /**
434
+ * Creates a new Commercetools client, optionally upgrading it from Anonymous mode to Guest mode.
435
+ * For now, any Query or Mutation will require an upgrade to Guest mode.
436
+ * In the future, maybe we can delay this upgrade until we actually need it.
437
+ *
438
+ * @param reqCtx
439
+ * @param anonymousCall
440
+ * @returns
441
+ */
181
442
  @traced()
182
- protected override parseSingle(remote: CTCart, session: Session): T {
183
- const result = this.newModel();
443
+ protected async getClient(reqCtx: RequestContext) {
444
+ const client = await new CommercetoolsClient(this.config).getClient(reqCtx);
445
+
446
+ const clientWithProject = client.withProjectKey({ projectKey: this.config.projectKey });
447
+ return {
448
+ carts: clientWithProject.me().carts(),
449
+ activeCart: clientWithProject.me().activeCart(),
450
+ orders: clientWithProject.me().orders(),
184
451
 
185
- result.identifier.key = remote.id;
452
+ }
453
+ }
454
+
455
+ protected override parseSingle(remote: CTCart, reqCtx: RequestContext): T {
456
+ const result = this.newModel();
186
457
 
458
+ result.identifier = CommercetoolsCartIdentifierSchema.parse({
459
+ key: remote.id,
460
+ version: remote.version || 0,
461
+ });
187
462
 
188
463
  result.name = remote.custom?.fields['name'] || '';
189
464
  result.description = remote.custom?.fields['description'] || '';
@@ -192,42 +467,44 @@ export class CommercetoolsCartProvider<
192
467
  const shippingTotal = remote.shippingInfo?.price.centAmount || 0;
193
468
  const productTotal = grandTotal - shippingTotal;
194
469
  const taxTotal = remote.taxedPrice?.totalTax?.centAmount || 0;
195
- const discountTotal = remote.discountOnTotalPrice?.discountedAmount.centAmount || 0;
470
+ const discountTotal =
471
+ remote.discountOnTotalPrice?.discountedAmount.centAmount || 0;
196
472
  const surchargeTotal = 0;
197
473
  const currency = remote.totalPrice.currencyCode as Currency;
198
474
 
199
475
  result.price = {
200
476
  totalTax: {
201
477
  value: taxTotal / 100,
202
- currency
478
+ currency,
203
479
  },
204
480
  totalDiscount: {
205
- value: discountTotal/ 100,
206
- currency
481
+ value: discountTotal / 100,
482
+ currency,
207
483
  },
208
484
  totalSurcharge: {
209
485
  value: surchargeTotal / 100,
210
- currency
486
+ currency,
211
487
  },
212
488
  totalShipping: {
213
489
  value: shippingTotal / 100,
214
490
  currency: remote.shippingInfo?.price.currencyCode as Currency,
215
491
  },
216
492
  totalProductPrice: {
217
- value: productTotal / 100,
218
- currency
493
+ value: productTotal / 100,
494
+ currency,
219
495
  },
220
496
  grandTotal: {
221
497
  value: grandTotal / 100,
222
- currency
223
- }
224
- }
498
+ currency,
499
+ },
500
+ };
225
501
 
226
502
  for (const remoteItem of remote.lineItems) {
227
503
  const item = CartItemSchema.parse({});
228
504
 
229
505
  item.identifier.key = remoteItem.id;
230
506
  item.product.key = remoteItem.productId;
507
+ item.sku.key = remoteItem.variant.sku || '';
231
508
  item.quantity = remoteItem.quantity;
232
509
 
233
510
  const unitPrice = remoteItem.price.value.centAmount;
@@ -235,36 +512,36 @@ export class CommercetoolsCartProvider<
235
512
  const totalDiscount = remoteItem.price.discounted?.value.centAmount || 0;
236
513
  const unitDiscount = totalDiscount / remoteItem.quantity;
237
514
 
238
-
239
515
  item.price = {
240
516
  unitPrice: {
241
517
  value: unitPrice / 100,
242
- currency
518
+ currency,
243
519
  },
244
520
  unitDiscount: {
245
- value: (unitDiscount / 100),
246
- currency
521
+ value: unitDiscount / 100,
522
+ currency,
247
523
  },
248
524
  totalPrice: {
249
525
  value: (totalPrice || 0) / 100,
250
- currency
526
+ currency,
251
527
  },
252
528
  totalDiscount: {
253
529
  value: totalDiscount / 100,
254
- currency
530
+ currency,
255
531
  },
256
- }
532
+ };
257
533
 
258
534
  result.items.push(item);
259
535
  }
260
536
 
261
537
  result.meta = {
262
- cache: { hit: false, key: this.generateCacheKeySingle(result.identifier, session) },
263
- placeholder: false
538
+ cache: {
539
+ hit: false,
540
+ key: this.generateCacheKeySingle(result.identifier, reqCtx),
541
+ },
542
+ placeholder: false,
264
543
  };
265
544
 
266
545
  return this.assert(result);
267
546
  }
268
-
269
-
270
547
  }