@faststore/api 2.0.82-alpha.0 → 2.0.97-alpha.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.
@@ -26,7 +26,7 @@ export declare const VtexCommerce: ({ account, environment }: Options, ctx: Cont
26
26
  pagetype: (slug: string) => Promise<PortalPagetype>;
27
27
  };
28
28
  products: {
29
- crossselling: ({ type, productId, groupByProduct }: {
29
+ crossselling: ({ type, productId, groupByProduct, }: {
30
30
  type: ValueOf<typeof FACET_CROSS_SELLING_MAP>;
31
31
  productId: string;
32
32
  groupByProduct?: boolean | undefined;
@@ -35,7 +35,7 @@ export declare const VtexCommerce: ({ account, environment }: Options, ctx: Cont
35
35
  };
36
36
  checkout: {
37
37
  simulation: (args: SimulationArgs, { salesChannel }?: SimulationOptions) => Promise<Simulation>;
38
- shippingData: ({ id, body }: {
38
+ shippingData: ({ id, body, }: {
39
39
  id: string;
40
40
  body: unknown;
41
41
  }) => Promise<OrderForm>;
@@ -61,6 +61,7 @@ export declare const VtexCommerce: ({ account, environment }: Options, ctx: Cont
61
61
  address: ({ postalCode, country, }: AddressInput) => Promise<Address>;
62
62
  };
63
63
  session: (search: string) => Promise<Session>;
64
+ getSessionOrder: () => Promise<Session>;
64
65
  subscribeToNewsletter: (data: {
65
66
  name: string;
66
67
  email: string;
@@ -5,6 +5,7 @@ export interface Session {
5
5
  export interface Namespaces {
6
6
  profile?: Profile;
7
7
  store?: Store;
8
+ checkout?: Checkout;
8
9
  }
9
10
  export interface Value {
10
11
  value: string;
@@ -22,3 +23,6 @@ export interface Profile {
22
23
  firstName?: Value;
23
24
  lastName?: Value;
24
25
  }
26
+ export interface Checkout {
27
+ orderFormId?: Value;
28
+ }
@@ -20,7 +20,7 @@ export declare const getClients: (options: Options, ctx: Context) => {
20
20
  pagetype: (slug: string) => Promise<import("./commerce/types/Portal").PortalPagetype>;
21
21
  };
22
22
  products: {
23
- crossselling: ({ type, productId, groupByProduct }: {
23
+ crossselling: ({ type, productId, groupByProduct, }: {
24
24
  type: "whoboughtalsobought" | "whosawalsosaw" | "similars" | "whosawalsobought" | "accessories" | "suggestions";
25
25
  productId: string;
26
26
  groupByProduct?: boolean | undefined;
@@ -29,7 +29,7 @@ export declare const getClients: (options: Options, ctx: Context) => {
29
29
  };
30
30
  checkout: {
31
31
  simulation: (args: import("./commerce/types/Simulation").SimulationArgs, { salesChannel }?: import("./commerce/types/Simulation").SimulationOptions) => Promise<import("./commerce/types/Simulation").Simulation>;
32
- shippingData: ({ id, body }: {
32
+ shippingData: ({ id, body, }: {
33
33
  id: string;
34
34
  body: unknown;
35
35
  }) => Promise<import("./commerce/types/OrderForm").OrderForm>;
@@ -55,6 +55,7 @@ export declare const getClients: (options: Options, ctx: Context) => {
55
55
  address: ({ postalCode, country, }: import("./commerce/types/Address").AddressInput) => Promise<import("./commerce/types/Address").Address>;
56
56
  };
57
57
  session: (search: string) => Promise<import("./commerce/types/Session").Session>;
58
+ getSessionOrder: () => Promise<import("./commerce/types/Session").Session>;
58
59
  subscribeToNewsletter: (data: {
59
60
  name: string;
60
61
  email: string;
@@ -1,5 +1,5 @@
1
- import type { MutationValidateCartArgs } from '../../../__generated__/schema';
2
1
  import type { Context } from '..';
2
+ import type { MutationValidateCartArgs } from '../../../__generated__/schema';
3
3
  /**
4
4
  * This resolver implements the optimistic cart behavior. The main idea in here
5
5
  * is that we receive a cart from the UI (as query params) and we validate it with
@@ -0,0 +1 @@
1
+ export declare const getCookie: (name: string, cookie: string) => string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/api",
3
- "version": "2.0.82-alpha.0",
3
+ "version": "2.0.97-alpha.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -30,8 +30,8 @@
30
30
  "p-limit": "^3.1.0"
31
31
  },
32
32
  "devDependencies": {
33
- "@faststore/eslint-config": "^2.0.79-alpha.0",
34
- "@faststore/shared": "^2.0.79-alpha.0",
33
+ "@faststore/eslint-config": "^2.0.91-alpha.0",
34
+ "@faststore/shared": "^2.0.91-alpha.0",
35
35
  "@graphql-codegen/cli": "2.2.0",
36
36
  "@graphql-codegen/typescript": "2.2.2",
37
37
  "@types/express": "^4.17.16",
@@ -49,5 +49,5 @@
49
49
  "peerDependencies": {
50
50
  "graphql": "^15.6.0"
51
51
  },
52
- "gitHead": "40eca92e54949023e403bd79e4ddd18d773ed3a2"
52
+ "gitHead": "03f34ada5ba718995e69b12c465a96b9f01aebe2"
53
53
  }
@@ -15,6 +15,7 @@ import type {
15
15
  } from './types/Simulation'
16
16
  import type { Session } from './types/Session'
17
17
  import type { Channel } from '../../utils/channel'
18
+ import { getCookie } from '../../utils/getCookies'
18
19
  import type { SalesChannel } from './types/SalesChannel'
19
20
  import { MasterDataResponse } from './types/Newsletter'
20
21
  import type { Address, AddressInput } from './types/Address'
@@ -51,20 +52,22 @@ export const VtexCommerce = (
51
52
  fetchAPI(`${base}/api/catalog_system/pub/portal/pagetype/${slug}`),
52
53
  },
53
54
  products: {
54
- crossselling: (
55
- { type, productId, groupByProduct = true }: {
56
- type: ValueOf<typeof FACET_CROSS_SELLING_MAP>;
57
- productId: string;
58
- groupByProduct?: boolean;
59
- },
60
- ): Promise<PortalProduct[]> => {
55
+ crossselling: ({
56
+ type,
57
+ productId,
58
+ groupByProduct = true,
59
+ }: {
60
+ type: ValueOf<typeof FACET_CROSS_SELLING_MAP>
61
+ productId: string
62
+ groupByProduct?: boolean
63
+ }): Promise<PortalProduct[]> => {
61
64
  const params = new URLSearchParams({
62
65
  sc: ctx.storage.channel.salesChannel,
63
66
  groupByProduct: groupByProduct.toString(),
64
67
  })
65
68
 
66
69
  return fetchAPI(
67
- `${base}/api/catalog_system/pub/products/crossselling/${type}/${productId}?${params}`,
70
+ `${base}/api/catalog_system/pub/products/crossselling/${type}/${productId}?${params}`
68
71
  )
69
72
  },
70
73
  },
@@ -86,16 +89,20 @@ export const VtexCommerce = (
86
89
  }
87
90
  )
88
91
  },
89
- shippingData: (
90
- { id, body }: { id: string; body: unknown },
91
- ): Promise<OrderForm> => {
92
+ shippingData: ({
93
+ id,
94
+ body,
95
+ }: {
96
+ id: string
97
+ body: unknown
98
+ }): Promise<OrderForm> => {
92
99
  return fetchAPI(
93
100
  `${base}/api/checkout/pub/orderForm/${id}/attachments/shippingData`,
94
101
  {
95
102
  ...BASE_INIT,
96
103
  body: JSON.stringify(body),
97
- },
98
- );
104
+ }
105
+ )
99
106
  },
100
107
  orderForm: ({
101
108
  id,
@@ -164,7 +171,7 @@ export const VtexCommerce = (
164
171
  ...BASE_INIT,
165
172
  body: JSON.stringify({ value }),
166
173
  method: 'PUT',
167
- },
174
+ }
168
175
  )
169
176
  },
170
177
  region: async ({
@@ -194,14 +201,34 @@ export const VtexCommerce = (
194
201
  'items',
195
202
  'profile.id,profile.email,profile.firstName,profile.lastName,store.channel,store.countryCode,store.cultureInfo,store.currencyCode,store.currencySymbol'
196
203
  )
197
-
198
- return fetchAPI(`${base}/api/sessions?${params.toString()}`, {
199
- method: 'POST',
204
+ if (getCookie('vtex_session', ctx.headers.cookie)) {
205
+ // cookie set
206
+ return fetchAPI(`${base}/api/sessions?${params.toString()}`, {
207
+ method: 'GET',
208
+ headers: {
209
+ 'content-type': 'application/json',
210
+ cookie: ctx.headers.cookie,
211
+ },
212
+ })
213
+ } else {
214
+ // cookie unset -> create session
215
+ return fetchAPI(`${base}/api/sessions?${params.toString()}`, {
216
+ method: 'POST',
217
+ headers: {
218
+ 'content-type': 'application/json',
219
+ cookie: ctx.headers.cookie,
220
+ },
221
+ body: '{}',
222
+ })
223
+ }
224
+ },
225
+ getSessionOrder: (): Promise<Session> => {
226
+ return fetchAPI(`${base}/api/sessions?items=checkout.orderFormId`, {
227
+ method: 'GET',
200
228
  headers: {
201
229
  'content-type': 'application/json',
202
230
  cookie: ctx.headers.cookie,
203
231
  },
204
- body: '{}',
205
232
  })
206
233
  },
207
234
  subscribeToNewsletter: (data: {
@@ -6,6 +6,7 @@ export interface Session {
6
6
  export interface Namespaces {
7
7
  profile?: Profile
8
8
  store?: Store
9
+ checkout?: Checkout
9
10
  }
10
11
 
11
12
  export interface Value {
@@ -26,3 +27,7 @@ export interface Profile {
26
27
  firstName?: Value
27
28
  lastName?: Value
28
29
  }
30
+
31
+ export interface Checkout {
32
+ orderFormId?: Value
33
+ }
@@ -1,27 +1,26 @@
1
1
  import deepEquals from 'fast-deep-equal'
2
2
 
3
+ import { mutateChannelContext, mutateLocaleContext } from '../utils/contex'
4
+ import { getCookie } from '../utils/getCookies'
3
5
  import { md5 } from '../utils/md5'
4
6
  import {
5
7
  attachmentToPropertyValue,
6
8
  getPropertyId,
7
- VALUE_REFERENCES,
9
+ VALUE_REFERENCES
8
10
  } from '../utils/propertyValue'
9
- import { mutateChannelContext, mutateLocaleContext } from '../utils/contex'
10
11
 
12
+ import type { Context } from '..'
11
13
  import type {
12
- IStoreSession,
13
14
  IStoreOffer,
14
15
  IStoreOrder,
15
- IStorePropertyValue,
16
- Maybe,
17
- MutationValidateCartArgs,
16
+ IStorePropertyValue, IStoreSession, Maybe,
17
+ MutationValidateCartArgs
18
18
  } from '../../../__generated__/schema'
19
19
  import type {
20
20
  OrderForm,
21
21
  OrderFormInputItem,
22
- OrderFormItem,
22
+ OrderFormItem
23
23
  } from '../clients/commerce/types/OrderForm'
24
- import type { Context } from '..'
25
24
 
26
25
  type Indexed<T> = T & { index?: number }
27
26
 
@@ -200,6 +199,20 @@ const isOrderFormStale = (form: OrderForm) => {
200
199
  return newEtag !== oldEtag
201
200
  }
202
201
 
202
+ async function getOrderNumberFromSession(
203
+ headers: Record<string, string> = {},
204
+ commerce: Context['clients']['commerce']
205
+ ) {
206
+
207
+ const cookieSession = getCookie('vtex_session', headers.cookie)
208
+
209
+ if (cookieSession) {
210
+ const { namespaces } = await commerce.getSessionOrder()
211
+ return namespaces.checkout?.orderFormId?.value
212
+ }
213
+ return ;
214
+ }
215
+
203
216
  // Returns the regionalized orderForm
204
217
  const getOrderForm = async (
205
218
  id: string,
@@ -253,11 +266,11 @@ export const validateCart = async (
253
266
  { cart: { order }, session }: MutationValidateCartArgs,
254
267
  ctx: Context
255
268
  ) => {
256
- const { enableOrderFormSync } = ctx.storage.flags
257
- const { orderNumber, acceptedOffer, shouldSplitItem } = order
269
+ const { orderNumber: orderNumberFromCart, acceptedOffer, shouldSplitItem } = order
258
270
  const {
259
271
  clients: { commerce },
260
272
  loaders: { skuLoader },
273
+ headers,
261
274
  } = ctx
262
275
 
263
276
  const channel = session?.channel
@@ -271,22 +284,26 @@ export const validateCart = async (
271
284
  mutateLocaleContext(ctx, locale)
272
285
  }
273
286
 
287
+ const orderNumberFromSession = await getOrderNumberFromSession(
288
+ headers,
289
+ commerce
290
+ )
291
+
292
+ const orderNumber = orderNumberFromSession ?? orderNumberFromCart ?? ''
293
+
274
294
  // Step1: Get OrderForm from VTEX Commerce
275
295
  const orderForm = await getOrderForm(orderNumber, session, ctx)
276
296
 
277
297
  // Step1.5: Check if another system changed the orderForm with this orderNumber
278
298
  // If so, this means the user interacted with this cart elsewhere and expects
279
299
  // to see this new cart state instead of what's stored on the user's browser.
280
- if (enableOrderFormSync === true) {
281
- const isStale = isOrderFormStale(orderForm)
282
-
283
- if (isStale === true && orderNumber) {
284
- const newOrderForm = await setOrderFormEtag(orderForm, commerce).then(
285
- joinItems
300
+ const isStale = isOrderFormStale(orderForm)
301
+
302
+ if (isStale && orderNumber) {
303
+ const newOrderForm = await setOrderFormEtag(orderForm, commerce).then(
304
+ joinItems
286
305
  )
287
-
288
- return orderFormToCart(newOrderForm, skuLoader)
289
- }
306
+ return orderFormToCart(newOrderForm, skuLoader)
290
307
  }
291
308
 
292
309
  // Step2: Process items from both browser and checkout so they have the same shape
@@ -350,7 +367,7 @@ export const validateCart = async (
350
367
  })
351
368
  // update orderForm etag so we know last time we touched this orderForm
352
369
  .then((form) =>
353
- enableOrderFormSync ? setOrderFormEtag(form, commerce) : form
370
+ setOrderFormEtag(form, commerce)
354
371
  )
355
372
  .then(joinItems)
356
373
 
@@ -0,0 +1,8 @@
1
+ export const getCookie = (name: string, cookie: string): string => {
2
+ const value = `; ${cookie}`
3
+ const parts = value.split(`; ${name}=`)
4
+ if (parts.length === 2) {
5
+ return parts?.pop()?.split(';').shift() ?? ''
6
+ }
7
+ return ''
8
+ }