@faststore/core 4.5.0-dev.0 → 4.5.0-dev.2

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 (61) hide show
  1. package/.turbo/turbo-generate.log +4 -4
  2. package/.turbo/turbo-test.log +135 -63
  3. package/@generated/cached-operations.json +2 -0
  4. package/@generated/gql.ts +18 -0
  5. package/@generated/graphql.ts +68 -0
  6. package/@generated/persisted-documents.json +3 -0
  7. package/@generated/schema.graphql +41 -0
  8. package/CHANGELOG.md +24 -0
  9. package/cms/faststore/components/cms_component__recommendationshelf.jsonc +86 -0
  10. package/cms/faststore/schema.json +89 -0
  11. package/discovery.config.default.js +3 -0
  12. package/discovery.config.js +10 -1
  13. package/discovery.config.local.example.js +62 -0
  14. package/package.json +6 -6
  15. package/public/icons.svg +4 -0
  16. package/src/Layout.tsx +6 -0
  17. package/src/components/account/Drawer/OrganizationDrawer/ContractSwitcher/ContractSwitcher.tsx +376 -0
  18. package/src/components/account/Drawer/OrganizationDrawer/ContractSwitcher/index.ts +2 -0
  19. package/src/components/account/Drawer/OrganizationDrawer/OrganizationDrawer.tsx +51 -26
  20. package/src/components/account/Drawer/OrganizationDrawer/OrganizationDrawerFooter.tsx +55 -0
  21. package/src/components/account/Drawer/OrganizationDrawer/OrganizationDrawerHeader.tsx +45 -5
  22. package/src/components/account/Drawer/OrganizationDrawer/index.ts +5 -0
  23. package/src/components/account/Drawer/OrganizationDrawer/section.module.scss +452 -54
  24. package/src/components/cms/global/Components.ts +10 -0
  25. package/src/components/sections/ProductGallery/ProductGallery.tsx +1 -1
  26. package/src/components/sections/RecommendationShelf/RecommendationShelf.tsx +223 -0
  27. package/src/components/sections/RecommendationShelf/RecommendationShelf.types.ts +111 -0
  28. package/src/components/sections/RecommendationShelf/index.ts +1 -0
  29. package/src/components/sections/RecommendationShelf/section.module.scss +49 -0
  30. package/src/components/sections/RecommendationShelf/useRecommendationUserId.ts +49 -0
  31. package/src/components/sections/RecommendationShelf/useRecommendations.ts +55 -0
  32. package/src/components/sections/RecommendationShelf/vrn.ts +55 -0
  33. package/src/pages/[slug]/p.tsx +45 -0
  34. package/src/sdk/account/changeContractToken.ts +119 -0
  35. package/src/sdk/account/clearPersistedSessionState.ts +26 -0
  36. package/src/sdk/account/refreshToken.ts +21 -8
  37. package/src/sdk/account/useAvailableContracts.ts +49 -0
  38. package/src/sdk/account/useSwitchContract.ts +60 -0
  39. package/src/sdk/analytics/hooks/useStartRecommendationSession.ts +96 -0
  40. package/src/sdk/analytics/utils.ts +9 -0
  41. package/src/utils/retry.ts +69 -0
  42. package/test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx +235 -0
  43. package/test/components/RecommendationShelf/useRecommendationUserId.test.ts +69 -0
  44. package/test/components/RecommendationShelf/useRecommendations.test.ts +52 -0
  45. package/test/components/RecommendationShelf/vrn.test.ts +56 -0
  46. package/test/components/account/ContractSwitcher.browser.test.tsx +236 -0
  47. package/test/components/account/OrganizationDrawer.browser.test.tsx +197 -0
  48. package/test/components/account/OrganizationDrawerFooter.browser.test.tsx +54 -0
  49. package/test/components/account/OrganizationDrawerHeader.browser.test.tsx +55 -0
  50. package/test/components/account/doLogout.browser.test.ts +102 -0
  51. package/test/sdk/account/changeContractToken.browser.test.ts +157 -0
  52. package/test/sdk/account/clearPersistedSessionState.browser.test.ts +41 -0
  53. package/test/sdk/account/clearPersistedSessionState.test.ts +20 -0
  54. package/test/sdk/account/refreshToken.browser.test.ts +34 -0
  55. package/test/sdk/account/refreshToken.test.ts +87 -0
  56. package/test/sdk/account/useAvailableContracts.browser.test.ts +124 -0
  57. package/test/sdk/account/useSwitchContract.browser.test.ts +111 -0
  58. package/test/sdk/analytics/useStartRecommendationSession.test.ts +69 -0
  59. package/test/sdk/analytics/utils.test.ts +23 -0
  60. package/test/server/index.test.ts +3 -0
  61. package/test/utils/retry.test.ts +59 -0
@@ -673,6 +673,8 @@ type Mutation {
673
673
  Returns an operationId to poll for the operation status.
674
674
  """
675
675
  startOrderEntryOperation(data: IOrderEntryOperation!): StoreOrderEntryOperationResult @auth
676
+ """Starts an anonymous personalization session for the current shopper."""
677
+ startRecommendationSession: Boolean!
676
678
  }
677
679
 
678
680
  """
@@ -969,6 +971,15 @@ type Query {
969
971
  """Returns information about the user validation."""
970
972
  validateUser: ValidateUserData @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
971
973
  """
974
+ Lists the commercial contracts associated with the given Organization Unit,
975
+ resolved to human-readable corporate names. Governed: only contracts associated
976
+ with the authenticated buyer's Organization Unit are returned.
977
+ """
978
+ availableContracts(
979
+ """The Organization Unit identifier whose contracts will be listed."""
980
+ orgUnitId: String!
981
+ ): [StoreContract!]! @auth @cacheControl(scope: "private", sMaxAge: 0)
982
+ """
972
983
  Returns whether the current authenticated user belongs to a B2B organization unit.
973
984
  """
974
985
  isOrganizationMember: Boolean! @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
@@ -981,6 +992,20 @@ type Query {
981
992
  orderEntryOperation(operationId: String!): StoreOrderEntryOperationStatus @auth
982
993
  """Returns the items in an orderForm by its ID."""
983
994
  orderFormItems(orderFormId: String!): [StoreOrderFormCartItem!]! @auth
995
+ """Returns personalized product recommendations for a given campaign."""
996
+ recommendations(campaignVrn: String!, userId: String, products: [String!]): RecommendationResponse! @cacheControl(scope: "private", sMaxAge: 120, staleWhileRevalidate: 3600)
997
+ }
998
+
999
+ type RecommendationCampaign {
1000
+ id: String!
1001
+ title: String
1002
+ type: String!
1003
+ }
1004
+
1005
+ type RecommendationResponse {
1006
+ products: [StoreProduct!]!
1007
+ correlationId: String!
1008
+ campaign: RecommendationCampaign!
984
1009
  }
985
1010
 
986
1011
  type SKUSpecificationField {
@@ -1301,6 +1326,22 @@ enum StoreCollectionType {
1301
1326
  Collection
1302
1327
  }
1303
1328
 
1329
+ """A commercial contract available to a buyer's Organization Unit."""
1330
+ type StoreContract {
1331
+ """
1332
+ Contract identifier (the contract/scope ID associated with the Organization Unit).
1333
+ """
1334
+ id: ID!
1335
+ """
1336
+ Human-readable corporate name of the contract (resolved from MasterData).
1337
+ """
1338
+ corporateName: String!
1339
+ """
1340
+ Indicates whether this contract is the one currently active in the session.
1341
+ """
1342
+ isActive: Boolean!
1343
+ }
1344
+
1304
1345
  """Currency information."""
1305
1346
  type StoreCurrency {
1306
1347
  """Currency code (e.g: USD)."""
package/CHANGELOG.md CHANGED
@@ -3,6 +3,30 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [4.5.0-dev.2](https://github.com/vtex/faststore/compare/v4.5.0-dev.1...v4.5.0-dev.2) (2026-07-20)
7
+
8
+ **Note:** Version bump only for package @faststore/core
9
+
10
+ # [4.5.0-dev.1](https://github.com/vtex/faststore/compare/v4.5.0-dev.0...v4.5.0-dev.1) (2026-07-14)
11
+
12
+ ### Bug Fixes
13
+
14
+ - **api:** add storeCookies option to fetchAPI for recommendations ([0e36d26](https://github.com/vtex/faststore/commit/0e36d269600ad9d219e8899ad58d6f81b18f70cb))
15
+ - **api:** expose recommendation and personalization operations ([961112a](https://github.com/vtex/faststore/commit/961112a8d2434e9fa961e7b6805850d90165d70f))
16
+ - **core:** add recommendation/personalization GraphQL typeDefs ([5f3999b](https://github.com/vtex/faststore/commit/5f3999b3a045d6ca7218cbc9eadee00021a4231c))
17
+ - **core:** harden RecommendationShelf per review feedback ([e369181](https://github.com/vtex/faststore/commit/e36918123b0f14d9628d7ef71238ac714c99a7fc))
18
+ - **ProductGallery:** cast context to PLPContext for SEO title retrieval ([c674edc](https://github.com/vtex/faststore/commit/c674edccb35fabd5432185a4b85290f8447b7af6))
19
+
20
+ ### Features
21
+
22
+ - **api, core:** implement server-side validation for recommendations and enable opt-in feature ([060d0a0](https://github.com/vtex/faststore/commit/060d0a0a151faa8494d1ae781f18baad5505b149))
23
+ - **api, core:** return StoreProduct from recommendations for consistent interface ([1ea6afa](https://github.com/vtex/faststore/commit/1ea6afacbc768c1395b3b46e735bac6a0cfed73e))
24
+ - **core:** add RecommendationShelf component for personalized product recommendations ([3214947](https://github.com/vtex/faststore/commit/3214947496a3ca28282af1b8a07a8f0567be01e2))
25
+ - **core:** add RecommendationShelf section with personalization tracking ([6c426a8](https://github.com/vtex/faststore/commit/6c426a80bd3e408eac989b00d4b10d45b74f2967))
26
+ - **core:** B2B contract switcher in the account drawer ([#3390](https://github.com/vtex/faststore/issues/3390)) ([380396a](https://github.com/vtex/faststore/commit/380396a7405f7bdb472b1219274d84807c61e153)), closes [#3354](https://github.com/vtex/faststore/issues/3354)
27
+ - **core:** enhance RecommendationShelf with configurable items context and carousel settings ([7b4e2d2](https://github.com/vtex/faststore/commit/7b4e2d274d8acb07b74f6a29c34e806eff311b1f))
28
+ - **core:** make RecommendationShelf carousel and product card configurable ([402816e](https://github.com/vtex/faststore/commit/402816e0dda8529ea081d9dcfd50626d889bf4f8))
29
+
6
30
  # [4.5.0-dev.0](https://github.com/vtex/faststore/compare/v4.4.1-dev.0...v4.5.0-dev.0) (2026-07-03)
7
31
 
8
32
  ### Features
@@ -0,0 +1,86 @@
1
+ {
2
+ "$extends": ["#/$defs/base-component"],
3
+ "$componentKey": "RecommendationShelf",
4
+ "$componentTitle": "Recommendation Shelf",
5
+ "title": "Recommendation Shelf",
6
+ "description": "Display a carousel of personalized product recommendations from a VTEX Recommendations campaign.",
7
+ "type": "object",
8
+ "required": ["campaignVrn"],
9
+ "properties": {
10
+ "title": {
11
+ "title": "Title",
12
+ "description": "Override the shelf title. If not set, the campaign title will be used.",
13
+ "type": "string"
14
+ },
15
+ "campaignVrn": {
16
+ "title": "Campaign VRN",
17
+ "description": "Recommendation campaign VRN (e.g. vrn:recommendations:my-account:rec-persona-v2:abc123).",
18
+ "type": "string",
19
+ "pattern": "^vrn:recommendations:[^:]+:(rec-cross-v2|rec-similar-v2|rec-persona-v2|rec-last-v2|rec-top-items-v2|rec-search-v2|rec-next-v2|rec-visual-v2):[^:]+$"
20
+ },
21
+ "itemsContext": {
22
+ "title": "Items context",
23
+ "description": "Source of the products used as context for the recommendation request. 'Product page' uses the product currently being viewed; 'Cart' uses the items currently in the cart (useful for cross-sell shelves on the cart page). Only affects context-based campaigns such as cross-sell, similar items, visual similarity and next interaction.",
24
+ "type": "string",
25
+ "default": "PDP",
26
+ "enum": ["PDP", "CART"],
27
+ "enumNames": ["Product page", "Cart"]
28
+ },
29
+ "carouselConfiguration": {
30
+ "title": "Carousel Configuration",
31
+ "type": "object",
32
+ "properties": {
33
+ "itemsPerPageDesktop": {
34
+ "title": "Items per page (desktop)",
35
+ "description": "Number of products shown per page on desktop viewports.",
36
+ "type": "number",
37
+ "default": 4
38
+ },
39
+ "itemsPerPageMobile": {
40
+ "title": "Items per page (mobile)",
41
+ "description": "Number of products shown per page on mobile and tablet viewports.",
42
+ "type": "number",
43
+ "default": 2
44
+ },
45
+ "variant": {
46
+ "title": "Carousel track variant",
47
+ "description": "How the carousel navigates between items.",
48
+ "type": "string",
49
+ "default": "scroll",
50
+ "enum": ["slide", "scroll"],
51
+ "enumNames": ["Slide", "Scroll"]
52
+ },
53
+ "infiniteMode": {
54
+ "title": "Infinite navigation?",
55
+ "description": "Only applies to the 'slide' variant.",
56
+ "type": "boolean",
57
+ "default": false
58
+ },
59
+ "controls": {
60
+ "title": "Navigation controls",
61
+ "description": "Which navigation elements should be visible.",
62
+ "type": "string",
63
+ "default": "complete",
64
+ "enum": ["complete", "navigationArrows", "paginationBullets"],
65
+ "enumNames": ["Arrows and bullets", "Arrows only", "Bullets only"]
66
+ }
67
+ }
68
+ },
69
+ "productCardConfiguration": {
70
+ "title": "Product Card Configuration",
71
+ "type": "object",
72
+ "properties": {
73
+ "showDiscountBadge": {
74
+ "title": "Show discount badge?",
75
+ "type": "boolean",
76
+ "default": true
77
+ },
78
+ "bordered": {
79
+ "title": "Cards should be bordered?",
80
+ "type": "boolean",
81
+ "default": true
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }
@@ -113,6 +113,9 @@
113
113
  },
114
114
  {
115
115
  "$ref": "#/components/ShoppingAssistant"
116
+ },
117
+ {
118
+ "$ref": "#/components/RecommendationShelf"
116
119
  }
117
120
  ]
118
121
  }
@@ -4425,6 +4428,92 @@
4425
4428
  "writeOnly": false,
4426
4429
  "deprecated": false,
4427
4430
  "$abstract": false
4431
+ },
4432
+ "RecommendationShelf": {
4433
+ "$extends": ["#/$defs/base-component"],
4434
+ "$componentKey": "RecommendationShelf",
4435
+ "$componentTitle": "Recommendation Shelf",
4436
+ "title": "Recommendation Shelf",
4437
+ "description": "Display a carousel of personalized product recommendations from a VTEX Recommendations campaign.",
4438
+ "type": "object",
4439
+ "required": ["campaignVrn"],
4440
+ "properties": {
4441
+ "title": {
4442
+ "title": "Title",
4443
+ "description": "Override the shelf title. If not set, the campaign title will be used.",
4444
+ "type": "string"
4445
+ },
4446
+ "campaignVrn": {
4447
+ "title": "Campaign VRN",
4448
+ "description": "Recommendation campaign VRN (e.g. vrn:recommendations:my-account:rec-persona-v2:abc123).",
4449
+ "type": "string",
4450
+ "pattern": "^vrn:recommendations:[^:]+:(rec-cross-v2|rec-similar-v2|rec-persona-v2|rec-last-v2|rec-top-items-v2|rec-search-v2|rec-next-v2|rec-visual-v2):[^:]+$"
4451
+ },
4452
+ "itemsContext": {
4453
+ "title": "Items context",
4454
+ "description": "Source of the products used as context for the recommendation request. 'Product page' uses the product currently being viewed; 'Cart' uses the items currently in the cart (useful for cross-sell shelves on the cart page). Only affects context-based campaigns such as cross-sell, similar items, visual similarity and next interaction.",
4455
+ "type": "string",
4456
+ "default": "PDP",
4457
+ "enum": ["PDP", "CART"],
4458
+ "enumNames": ["Product page", "Cart"]
4459
+ },
4460
+ "carouselConfiguration": {
4461
+ "title": "Carousel Configuration",
4462
+ "type": "object",
4463
+ "properties": {
4464
+ "itemsPerPageDesktop": {
4465
+ "title": "Items per page (desktop)",
4466
+ "description": "Number of products shown per page on desktop viewports.",
4467
+ "type": "number",
4468
+ "default": 4
4469
+ },
4470
+ "itemsPerPageMobile": {
4471
+ "title": "Items per page (mobile)",
4472
+ "description": "Number of products shown per page on mobile and tablet viewports.",
4473
+ "type": "number",
4474
+ "default": 2
4475
+ },
4476
+ "variant": {
4477
+ "title": "Carousel track variant",
4478
+ "description": "How the carousel navigates between items.",
4479
+ "type": "string",
4480
+ "default": "scroll",
4481
+ "enum": ["slide", "scroll"],
4482
+ "enumNames": ["Slide", "Scroll"]
4483
+ },
4484
+ "infiniteMode": {
4485
+ "title": "Infinite navigation?",
4486
+ "description": "Only applies to the 'slide' variant.",
4487
+ "type": "boolean",
4488
+ "default": false
4489
+ },
4490
+ "controls": {
4491
+ "title": "Navigation controls",
4492
+ "description": "Which navigation elements should be visible.",
4493
+ "type": "string",
4494
+ "default": "complete",
4495
+ "enum": ["complete", "navigationArrows", "paginationBullets"],
4496
+ "enumNames": ["Arrows and bullets", "Arrows only", "Bullets only"]
4497
+ }
4498
+ }
4499
+ },
4500
+ "productCardConfiguration": {
4501
+ "title": "Product Card Configuration",
4502
+ "type": "object",
4503
+ "properties": {
4504
+ "showDiscountBadge": {
4505
+ "title": "Show discount badge?",
4506
+ "type": "boolean",
4507
+ "default": true
4508
+ },
4509
+ "bordered": {
4510
+ "title": "Cards should be bordered?",
4511
+ "type": "boolean",
4512
+ "default": true
4513
+ }
4514
+ }
4515
+ }
4516
+ }
4428
4517
  }
4429
4518
  }
4430
4519
  }
@@ -201,6 +201,9 @@ module.exports = {
201
201
  },
202
202
  refreshToken: false,
203
203
  scrollRestoration: false,
204
+ // Opt-in flag for VTEX Recommendations. When disabled (default), the store
205
+ // never starts a personalization session nor calls the Recommendations API.
206
+ enableRecommendations: false,
204
207
  /** Package names to transpile (e.g. ['@vtex/components']). Use a non-empty list to enable Next.js transpilation. */
205
208
  transpilePackages: [],
206
209
  },
@@ -6,6 +6,15 @@ const deepmerge = require('deepmerge')
6
6
  /**
7
7
  * @type {typeof defaultConfig & Record<string, any>}
8
8
  * */
9
- const finalConfig = deepmerge(defaultConfig, starterConfig)
9
+ let finalConfig = deepmerge(defaultConfig, starterConfig)
10
+
11
+ try {
12
+ finalConfig = deepmerge(finalConfig, require('./discovery.config.local'))
13
+ } catch (error) {
14
+ if (error?.code !== 'MODULE_NOT_FOUND') {
15
+ throw error
16
+ }
17
+ // Optional local overrides (packages/core/discovery.config.local.js).
18
+ }
10
19
 
11
20
  module.exports = finalConfig
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Example local overrides for B2B contract switcher development.
3
+ *
4
+ * Copy to discovery.config.local.js (gitignored) before running locally.
5
+ * Run from `packages/core`:
6
+ *
7
+ * cp discovery.config.local.example.js discovery.config.local.js
8
+ *
9
+ * Or from the repo root:
10
+ *
11
+ * cp packages/core/discovery.config.local.example.js packages/core/discovery.config.local.js
12
+ */
13
+ module.exports = {
14
+ plugins: ['@vtex/faststore-plugin-buyer-portal'],
15
+
16
+ api: {
17
+ storeId: 'b2bfaststoredev',
18
+ hideUnavailableItems: true,
19
+ },
20
+
21
+ storeUrl: 'https://b2bfaststore.vtexfaststore.com',
22
+ secureSubdomain: 'https://b2bfaststore.vtexfaststore.com',
23
+ checkoutUrl:
24
+ process.env.NODE_ENV === 'development'
25
+ ? 'http://localhost:3000/checkout/cart'
26
+ : 'https://b2bfaststore.vtexfaststore.com/checkout',
27
+ loginUrl: 'https://b2bfaststore.vtexfaststore.com/api/io/login',
28
+ accountUrl: 'https://b2bfaststore.vtexfaststore.com/api/io/account',
29
+
30
+ experimental: {
31
+ enableFaststoreMyAccount: true,
32
+ refreshToken: true,
33
+ },
34
+
35
+ vtexHeadlessCms: {
36
+ webhookUrls: [
37
+ 'https://b2bfaststoredev.myvtex.com/cms-releases/webhook-releases',
38
+ ],
39
+ },
40
+ }
41
+
42
+ // Dev-only: proxy VTEX Identity routes (WebOps handles this in production).
43
+ const { storeId } = module.exports.api
44
+
45
+ module.exports.rewrites = async () => {
46
+ if (process.env.NODE_ENV !== 'development') {
47
+ return { beforeFiles: [] }
48
+ }
49
+
50
+ return {
51
+ beforeFiles: [
52
+ {
53
+ source: '/api/authenticator/:path*',
54
+ destination: `https://${storeId}.myvtex.com/api/authenticator/:path*`,
55
+ },
56
+ {
57
+ source: '/api/vtexid/:path*',
58
+ destination: `https://${storeId}.myvtex.com/api/vtexid/:path*`,
59
+ },
60
+ ],
61
+ }
62
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "4.5.0-dev.0",
3
+ "version": "4.5.0-dev.2",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -71,11 +71,11 @@
71
71
  "style-loader": "^3.3.1",
72
72
  "swr": "^2.2.5",
73
73
  "use-sync-external-store": "^1.6.0",
74
- "@faststore/api": "4.5.0-dev.0",
75
- "@faststore/diagnostics": "4.5.0-dev.0",
76
- "@faststore/lighthouse": "4.5.0-dev.0",
77
- "@faststore/sdk": "4.5.0-dev.0",
78
- "@faststore/ui": "4.5.0-dev.0"
74
+ "@faststore/api": "4.5.0-dev.2",
75
+ "@faststore/lighthouse": "4.5.0-dev.2",
76
+ "@faststore/diagnostics": "4.5.0-dev.2",
77
+ "@faststore/sdk": "4.5.0-dev.2",
78
+ "@faststore/ui": "4.5.0-dev.2"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@cypress/code-coverage": "^3.12.1",
package/public/icons.svg CHANGED
@@ -73,6 +73,8 @@
73
73
 
74
74
  <symbol id="FadersHorizontal" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"></rect><line x1="135.99902" y1="171.99304" x2="39.99902" y2="171.99317" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></line><line x1="215.99902" y1="171.99317" x2="167.99902" y2="171.99304" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></line><line x1="71.99902" y1="83.99304" x2="39.99902" y2="83.99246" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></line><line x1="215.99902" y1="83.99246" x2="103.99902" y2="83.99304" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></line><line x1="103.99902" y1="59.99304" x2="103.99902" y2="107.99304" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></line><line x1="167.99902" y1="195.99304" x2="167.99902" y2="147.99304" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></line></symbol>
75
75
 
76
+ <symbol id="FolderOpen" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"></rect><path d="M32,96V72a8,8,0,0,1,8-8H93.33a8,8,0,0,1,4.8,1.6L128,88H216a8,8,0,0,1,8,8" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M40,200H216a16,16,0,0,0,15.7-13L248,96H32L16,187a16,16,0,0,0,15.7,13Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path></symbol>
77
+
76
78
  <symbol id="Gift" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"></rect><rect x="32" y="80" width="192" height="48" rx="7.99999" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" fill="none"></rect><path d="M208,128v72a8,8,0,0,1-8,8H56a8,8,0,0,1-8-8V128" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><line x1="128" y1="80" x2="128" y2="208" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></line><path d="M173.25483,68.68629C161.94113,80,128,80,128,80s0-33.94113,11.31371-45.25483a24,24,0,0,1,33.94112,33.94112Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M82.74517,68.68629C94.05887,80,128,80,128,80s0-33.94113-11.31371-45.25483A24,24,0,0,0,82.74517,68.68629Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path></symbol>
77
79
 
78
80
  <symbol id="Globe" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 256 256"><path d="M128 24a104 104 0 1 0 104 104A104.12 104.12 0 0 0 128 24Zm88 104a87.61 87.61 0 0 1-3.33 24h-38.51a157.44 157.44 0 0 0 0-48h38.51a87.61 87.61 0 0 1 3.33 24Zm-114 40h52a115.11 115.11 0 0 1-26 45 115.27 115.27 0 0 1-26-45Zm-3.9-16a140.84 140.84 0 0 1 0-48h59.88a140.84 140.84 0 0 1 0 48ZM40 128a87.61 87.61 0 0 1 3.33-24h38.51a157.44 157.44 0 0 0 0 48H43.33A87.61 87.61 0 0 1 40 128Zm114-40h-52a115.11 115.11 0 0 1 26-45 115.27 115.27 0 0 1 26 45Zm52.33 0h-35.62a135.28 135.28 0 0 0-22.3-45.6A88.29 88.29 0 0 1 206.37 88Zm-98.74-45.6A135.28 135.28 0 0 0 85.29 88H49.63a88.29 88.29 0 0 1 57.96-45.6ZM49.63 168h35.66a135.28 135.28 0 0 0 22.3 45.6A88.29 88.29 0 0 1 49.63 168Zm98.78 45.6a135.28 135.28 0 0 0 22.3-45.6h35.66a88.29 88.29 0 0 1-57.96 45.6Z"/></symbol>
@@ -109,6 +111,8 @@
109
111
 
110
112
  <symbol id="SealWarning" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 256 256"><path d="M225.86,102.82c-3.77-3.94-7.67-8-9.14-11.57-1.36-3.27-1.44-8.69-1.52-13.94-.15-9.76-.31-20.82-8-28.51s-18.75-7.85-28.51-8c-5.25-.08-10.67-.16-13.94-1.52-3.56-1.47-7.63-5.37-11.57-9.14C146.28,23.51,138.44,16,128,16s-18.27,7.51-25.18,14.14c-3.94,3.77-8,7.67-11.57,9.14C88,40.64,82.56,40.72,77.31,40.8c-9.76.15-20.82.31-28.51,8S41,67.55,40.8,77.31c-.08,5.25-.16,10.67-1.52,13.94-1.47,3.56-5.37,7.63-9.14,11.57C23.51,109.72,16,117.56,16,128s7.51,18.27,14.14,25.18c3.77,3.94,7.67,8,9.14,11.57,1.36,3.27,1.44,8.69,1.52,13.94.15,9.76.31,20.82,8,28.51s18.75,7.85,28.51,8c5.25.08,10.67.16,13.94,1.52,3.56,1.47,7.63,5.37,11.57,9.14C109.72,232.49,117.56,240,128,240s18.27-7.51,25.18-14.14c3.94-3.77,8-7.67,11.57-9.14,3.27-1.36,8.69-1.44,13.94-1.52,9.76-.15,20.82-.31,28.51-8s7.85-18.75,8-28.51c.08-5.25.16-10.67,1.52-13.94,1.47-3.56,5.37-7.63,9.14-11.57C232.49,146.28,240,138.44,240,128S232.49,109.73,225.86,102.82Zm-11.55,39.29c-4.79,5-9.75,10.17-12.38,16.52-2.52,6.1-2.63,13.07-2.73,19.82-.1,7-.21,14.33-3.32,17.43s-10.39,3.22-17.43,3.32c-6.75.1-13.72.21-19.82,2.73-6.35,2.63-11.52,7.59-16.52,12.38S132,224,128,224s-9.15-4.92-14.11-9.69-10.17-9.75-16.52-12.38c-6.1-2.52-13.07-2.63-19.82-2.73-7-.1-14.33-.21-17.43-3.32s-3.22-10.39-3.32-17.43c-.1-6.75-.21-13.72-2.73-19.82-2.63-6.35-7.59-11.52-12.38-16.52S32,132,32,128s4.92-9.15,9.69-14.11,9.75-10.17,12.38-16.52c2.52-6.1,2.63-13.07,2.73-19.82.1-7,.21-14.33,3.32-17.43S70.51,56.9,77.55,56.8c6.75-.1,13.72-.21,19.82-2.73,6.35-2.63,11.52-7.59,16.52-12.38S124,32,128,32s9.15,4.92,14.11,9.69,10.17,9.75,16.52,12.38c6.1,2.52,13.07,2.63,19.82,2.73,7,.1,14.33.21,17.43,3.32s3.22,10.39,3.32,17.43c.1,6.75.21,13.72,2.73,19.82,2.63,6.35,7.59,11.52,12.38,16.52S224,124,224,128,219.08,137.15,214.31,142.11ZM120,136V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z"></path></symbol>
111
113
 
114
+ <symbol id="SignOut" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"></rect><path d="M112,216H48a16,16,0,0,1-16-16V56A16,16,0,0,1,48,40h64" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><polyline points="168 176 216 128 168 80" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></polyline><line x1="104" y1="128" x2="216" y2="128" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></line></symbol>
115
+
112
116
  <symbol id="ShieldCheck" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"></rect><path d="M40,114.66667V56a8,8,0,0,1,8-8H208a8,8,0,0,1,8,8v58.66667c0,84.01533-71.306,111.85016-85.5438,116.57058a7.54755,7.54755,0,0,1-4.9124,0C111.306,226.51683,40,198.682,40,114.66667Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><polyline points="172 104 113.333 160 84 132" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></polyline></symbol>
113
117
 
114
118
  <symbol id="ShoppingCart" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"></rect><path d="M184,184H69.81818L41.92162,30.56892A8,8,0,0,0,34.05066,24H16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><circle cx="80" cy="204" r="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></circle><circle cx="184" cy="204" r="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></circle><path d="M62.54543,144H188.10132a16,16,0,0,0,15.74192-13.13783L216,64H48" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path></symbol>
package/src/Layout.tsx CHANGED
@@ -1,10 +1,16 @@
1
1
  import { isValidElement, type PropsWithChildren } from 'react'
2
2
 
3
3
  import { usePageViewEvent } from './sdk/analytics/hooks/usePageViewEvent'
4
+ import { useStartRecommendationSession } from './sdk/analytics/hooks/useStartRecommendationSession'
4
5
 
5
6
  function Layout({ children }: PropsWithChildren) {
6
7
  const props = isValidElement(children) ? children.props : undefined
7
8
  usePageViewEvent(props)
9
+ // Implemented here because the personalization session must be initiated once
10
+ // per browser session on each page. Gated behind the
11
+ // `experimental.enableRecommendations` flag: stores that don't opt into
12
+ // Recommendations never start a session nor call the Recommendations API.
13
+ useStartRecommendationSession()
8
14
 
9
15
  return <>{children}</>
10
16
  }