@faststore/core 3.96.0-dev.17 → 3.96.0-dev.19

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 (62) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +54 -54
  3. package/.next/cache/.tsbuildinfo +1 -1
  4. package/.next/cache/config.json +3 -3
  5. package/.next/cache/webpack/client-production/0.pack +0 -0
  6. package/.next/cache/webpack/client-production/index.pack +0 -0
  7. package/.next/cache/webpack/server-production/0.pack +0 -0
  8. package/.next/cache/webpack/server-production/index.pack +0 -0
  9. package/.next/prerender-manifest.js +1 -1
  10. package/.next/prerender-manifest.json +1 -1
  11. package/.next/react-loadable-manifest.json +2 -2
  12. package/.next/routes-manifest.json +1 -1
  13. package/.next/server/chunks/948.js +2 -2
  14. package/.next/server/chunks/9563.js +1 -1
  15. package/.next/server/functions-config-manifest.json +1 -1
  16. package/.next/server/middleware-build-manifest.js +1 -1
  17. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  18. package/.next/server/pages/api/fs/logout.js +1 -0
  19. package/.next/server/pages/api/fs/logout.js.nft.json +1 -0
  20. package/.next/server/pages/api/graphql.js +1 -1
  21. package/.next/server/pages/en-US/404.html +1 -1
  22. package/.next/server/pages/en-US/500.html +1 -1
  23. package/.next/server/pages/en-US/checkout.html +1 -1
  24. package/.next/server/pages/en-US/login.html +1 -1
  25. package/.next/server/pages/en-US/s.html +1 -1
  26. package/.next/server/pages/en-US.html +1 -1
  27. package/.next/server/pages-manifest.json +1 -1
  28. package/.next/static/chunks/{2500.b188ad84b5a0a521.js → 2500.d6beb5af6ee00a9e.js} +1 -1
  29. package/.next/static/chunks/4803.9822f0b7e469b933.js +1 -0
  30. package/.next/static/chunks/{7191-e43007cdde83bc1f.js → 7191-5ede6e7ef625ea77.js} +1 -1
  31. package/.next/static/chunks/9173-ab3c4d9d8f978c4b.js +1 -0
  32. package/.next/static/chunks/pages/{404-f04d51a89ab8e8c8.js → 404-4b3f1e22c77f849a.js} +1 -1
  33. package/.next/static/chunks/pages/{500-b3cd1219951eb7d1.js → 500-bb2de0c11524b2b8.js} +1 -1
  34. package/.next/static/chunks/pages/{[...slug]-28b3f75a1b2b22b8.js → [...slug]-3579b3b8b8309552.js} +1 -1
  35. package/.next/static/chunks/pages/[slug]/{p-f3b7653e4bd1ba57.js → p-b9320679eebf6f5c.js} +1 -1
  36. package/.next/static/chunks/pages/{_app-38f75642a57fe506.js → _app-35b56c71ba4f9a54.js} +1 -1
  37. package/.next/static/chunks/pages/{checkout-9a253c6c2498d41f.js → checkout-dc07d72b3514c83d.js} +1 -1
  38. package/.next/static/chunks/pages/{index-f522924c892c46dd.js → index-1f8bf0fb351b90f4.js} +1 -1
  39. package/.next/static/chunks/pages/{login-1d364797aaa9da36.js → login-e97ef92769456bf6.js} +1 -1
  40. package/.next/static/chunks/pages/pvt/account/{403-2105ed93b3e3e58e.js → 403-91597100f8956385.js} +1 -1
  41. package/.next/static/chunks/pages/pvt/account/{404-2e555481b1a4f63b.js → 404-c68124bed7cb7c48.js} +1 -1
  42. package/.next/static/chunks/pages/pvt/account/orders/{[id]-2bd9adec59ae1ed3.js → [id]-dc662a778c5b8876.js} +1 -1
  43. package/.next/static/chunks/pages/pvt/account/{orders-4d66173a6e6282a1.js → orders-12a215899ae6f3eb.js} +1 -1
  44. package/.next/static/chunks/pages/pvt/account/{profile-1799ddf1749086aa.js → profile-b6cdbf02d4682544.js} +1 -1
  45. package/.next/static/chunks/pages/pvt/account/{security-f2734d61da9099db.js → security-e6289a40e745d3c4.js} +1 -1
  46. package/.next/static/chunks/pages/pvt/account/{user-details-c8636b99b6725815.js → user-details-fba1822e52e7de26.js} +1 -1
  47. package/.next/static/chunks/pages/{s-603fab8b09726274.js → s-41cffb20de1d2617.js} +1 -1
  48. package/.next/static/chunks/{webpack-3cd689c2fd3d4dd1.js → webpack-7a3373ab044e72a1.js} +1 -1
  49. package/.next/static/uv4I-g8aFXcaBykLttQUs/_buildManifest.js +1 -0
  50. package/.next/trace +139 -138
  51. package/.turbo/turbo-build.log +25 -24
  52. package/.turbo/turbo-test.log +9 -7
  53. package/CHANGELOG.md +10 -0
  54. package/package.json +7 -7
  55. package/src/components/account/MyAccountDrawer/OrganizationDrawer/OrganizationDrawer.tsx +104 -4
  56. package/src/pages/api/fs/logout.ts +76 -0
  57. package/src/utils/clearCookies.ts +79 -0
  58. package/test/utils/clearCookies.test.ts +232 -0
  59. package/.next/static/Yo88n9O6FrhtIc3GGfGv9/_buildManifest.js +0 -1
  60. package/.next/static/chunks/4803.18fbf77cd924d443.js +0 -1
  61. package/.next/static/chunks/9173-2ed920b87ee6640e.js +0 -1
  62. /package/.next/static/{Yo88n9O6FrhtIc3GGfGv9 → uv4I-g8aFXcaBykLttQUs}/_ssgManifest.js +0 -0
@@ -1,23 +1,23 @@
1
1
 
2
- > @faststore/core@3.96.0-dev.16 prebuild /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@3.96.0-dev.18 prebuild /home/runner/work/faststore/faststore/packages/core
3
3
  > na run partytown && na run generate
4
4
 
5
5
 
6
- > @faststore/core@3.96.0-dev.16 partytown /home/runner/work/faststore/faststore/packages/core
6
+ > @faststore/core@3.96.0-dev.18 partytown /home/runner/work/faststore/faststore/packages/core
7
7
  > partytown copylib ./public/~partytown
8
8
 
9
9
  Partytown lib copied to: /home/runner/work/faststore/faststore/packages/core/public/~partytown
10
10
 
11
- > @faststore/core@3.96.0-dev.16 generate /home/runner/work/faststore/faststore/packages/core
11
+ > @faststore/core@3.96.0-dev.18 generate /home/runner/work/faststore/faststore/packages/core
12
12
  > na run generate:schema && na run generate:codegen && na run format:generated
13
13
 
14
14
 
15
- > @faststore/core@3.96.0-dev.16 generate:schema /home/runner/work/faststore/faststore/packages/core
15
+ > @faststore/core@3.96.0-dev.18 generate:schema /home/runner/work/faststore/faststore/packages/core
16
16
  > tsx src/server/generator/generateGraphQLSchemaFile.ts
17
17
 
18
18
  Schema GraphQL file generated successfully
19
19
 
20
- > @faststore/core@3.96.0-dev.16 generate:codegen /home/runner/work/faststore/faststore/packages/core
20
+ > @faststore/core@3.96.0-dev.18 generate:codegen /home/runner/work/faststore/faststore/packages/core
21
21
  > graphql-codegen
22
22
 
23
23
  [STARTED] Parse Configuration
@@ -37,11 +37,11 @@ Running lifecycle hook "afterStart" scripts...
37
37
  [CLI] Loading Documents
38
38
  [CLI] Generating output
39
39
 
40
- > @faststore/core@3.96.0-dev.16 format:generated /home/runner/work/faststore/faststore/packages/core
40
+ > @faststore/core@3.96.0-dev.18 format:generated /home/runner/work/faststore/faststore/packages/core
41
41
  > prettier --write "@generated/**/*.{ts,js,tsx,jsx,json}" --loglevel error
42
42
 
43
43
 
44
- > @faststore/core@3.96.0-dev.16 build /home/runner/work/faststore/faststore/packages/core
44
+ > @faststore/core@3.96.0-dev.18 build /home/runner/work/faststore/faststore/packages/core
45
45
  > next build
46
46
 
47
47
  ⚠ No build cache found. Please configure build caching for faster rebuilds. Read more: https://nextjs.org/docs/messages/no-cache
@@ -58,7 +58,7 @@ Browserslist: caniuse-lite is outdated. Please run:
58
58
  Creating an optimized production build ...
59
59
  Disabled SWC as replacement for Babel because of custom Babel configuration ".babelrc.js" https://nextjs.org/docs/messages/swc-disabled
60
60
  Using external babel configuration from /home/runner/work/faststore/faststore/packages/core/.babelrc.js
61
- Browserslist: browsers data (caniuse-lite) is 11 months old. Please run:
61
+ Browserslist: browsers data (caniuse-lite) is 12 months old. Please run:
62
62
  npx update-browserslist-db@latest
63
63
  Why you should do it regularly: https://github.com/browserslist/update-db#readme
64
64
  <w> [webpack.cache.PackFileCacheStrategy] Skipped not serializable cache item 'Compilation/modules|/home/runner/work/faststore/faststore/node_modules/.pnpm/next@13.5.11_@babel+core@7.26.7_@opentelemetry+api@1.4.1_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.83.4/node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[7].oneOf[9].use[1]!/home/runner/work/faststore/faststore/node_modules/.pnpm/next@13.5.11_@babel+core@7.26.7_@opentelemetry+api@1.4.1_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.83.4/node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[7].oneOf[9].use[2]!/home/runner/work/faststore/faststore/node_modules/.pnpm/next@13.5.11_@babel+core@7.26.7_@opentelemetry+api@1.4.1_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.83.4/node_modules/next/dist/build/webpack/loaders/resolve-url-loader/index.js??ruleSet[1].rules[7].oneOf[9].use[3]!/home/runner/work/faststore/faststore/node_modules/.pnpm/next@13.5.11_@babel+core@7.26.7_@opentelemetry+api@1.4.1_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.83.4/node_modules/next/dist/compiled/sass-loader/cjs.js??ruleSet[1].rules[7].oneOf[9].use[4]!/home/runner/work/faststore/faststore/packages/core/src/components/common/Toast/section.module.scss': No serializer registered for Warning
@@ -80,50 +80,51 @@ Import trace for requested module:
80
80
  Collecting page data ...
81
81
  Generating static pages (0/6) ...
82
82
 
83
83
  Generating static pages (1/6)
84
-
85
84
  Generating static pages (2/6)
86
85
  Warning: Dynamic Content not found for the page: home. Refer to the Dynamic Content documentation at https://developers.vtex.com/docs/guides/faststore/dynamic-content-overview for mapping the page and the corresponding data-fetching function.
86
+
87
87
  Generating static pages (2/6)
88
88
 
89
89
  Generating static pages (4/6)
90
90
 
91
91
  ✓ Generating static pages (6/6)
92
92
  Finalizing page optimization ...
93
93
  Collecting build traces ...
94
94
 
95
95
  Route (pages) Size First Load JS
96
- ┌ ● / 7.4 kB 147 kB
96
+ ┌ ● / 7.39 kB 147 kB
97
97
  ├ └ css/02259c549b2179f2.css 3.1 kB
98
98
  ├ /_app 0 B 108 kB
99
- ├ ● /[...slug] 2.55 kB 157 kB
100
- ├ ● /[slug]/p 98.1 kB 237 kB
99
+ ├ ● /[...slug] 2.55 kB 158 kB
100
+ ├ ● /[slug]/p 98.1 kB 238 kB
101
101
  ├ └ css/a6a4ebbe01adbbad.css 22.2 kB
102
- ├ ○ /404 1.58 kB 141 kB
103
- ├ ● /500 1.57 kB 141 kB
102
+ ├ ○ /404 1.57 kB 142 kB
103
+ ├ ● /500 1.57 kB 142 kB
104
+ ├ λ /api/fs/logout 0 B 108 kB
104
105
  ├ λ /api/graphql 0 B 108 kB
105
106
  ├ λ /api/health/live 0 B 108 kB
106
107
  ├ λ /api/health/ready 0 B 108 kB
107
108
  ├ λ /api/preview 0 B 108 kB
108
- ├ ● /checkout 750 B 140 kB
109
- ├ ● /login 1.7 kB 141 kB
109
+ ├ ● /checkout 749 B 141 kB
110
+ ├ ● /login 1.7 kB 142 kB
110
111
  ├ λ /pvt/account 247 B 108 kB
111
112
  ├ ● /pvt/account/[...unknown] 287 B 109 kB
112
- ├ λ /pvt/account/403 2.98 kB 142 kB
113
+ ├ λ /pvt/account/403 2.98 kB 143 kB
113
114
  ├ └ css/0fae3d432331aae9.css 4.68 kB
114
115
  ├ λ /pvt/account/404 2.18 kB 142 kB
115
116
  ├ └ css/0fc6b2ff69142c6a.css 4.74 kB
116
- ├ λ /pvt/account/orders 9.79 kB 149 kB
117
+ ├ λ /pvt/account/orders 9.78 kB 150 kB
117
118
  ├ └ css/40a294d0a24ad01d.css 14.1 kB
118
- ├ λ /pvt/account/orders/[id] 12.1 kB 151 kB
119
+ ├ λ /pvt/account/orders/[id] 12.1 kB 152 kB
119
120
  ├ └ css/5eecefd2c6deeee4.css 13.3 kB
120
- ├ λ /pvt/account/profile 1.99 kB 141 kB
121
+ ├ λ /pvt/account/profile 1.98 kB 142 kB
121
122
  ├ └ css/47f1b4e8de15d314.css 4.42 kB
122
- ├ λ /pvt/account/security 3.96 kB 143 kB
123
+ ├ λ /pvt/account/security 3.96 kB 144 kB
123
124
  ├ └ css/973dd40d4773e8cd.css 5.74 kB
124
- ├ λ /pvt/account/user-details 1.91 kB 141 kB
125
+ ├ λ /pvt/account/user-details 1.91 kB 142 kB
125
126
  ├ └ css/05c399956ff24b77.css 4.54 kB
126
127
  └ ● /s 3.36 kB 158 kB
127
128
  + First Load JS shared by all 112 kB
128
129
  ├ chunks/framework-d514426edf885c68.js 45.4 kB
129
130
  ├ chunks/main-ec03882c4375091d.js 33.2 kB
130
- ├ chunks/pages/_app-38f75642a57fe506.js 25.8 kB
131
- ├ chunks/webpack-3cd689c2fd3d4dd1.js 3.85 kB
131
+ ├ chunks/pages/_app-35b56c71ba4f9a54.js 25.8 kB
132
+ ├ chunks/webpack-7a3373ab044e72a1.js 3.85 kB
132
133
  └ css/0f070d03aacd9cc5.css 3.57 kB
133
134
 
134
135
  λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
@@ -1,15 +1,17 @@
1
1
 
2
- > @faststore/core@3.96.0-dev.16 test /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@3.96.0-dev.18 test /home/runner/work/faststore/faststore/packages/core
3
3
  > jest
4
4
 
5
- PASS test/utils/multipleTemplates.test.ts (22.199 s)
5
+ PASS test/utils/multipleTemplates.test.ts (28.172 s)
6
+ PASS test/utils/clearCookies.test.ts (26.854 s)
6
7
  PASS test/server/cms/global.test.ts
7
- PASS test/utils/cookieCacheBusting.test.ts (21.581 s)
8
+ PASS test/utils/cookieCacheBusting.test.ts
8
9
  PASS test/server/cms/index.test.ts
9
- PASS test/server/index.test.ts (25.466 s)
10
+ PASS test/server/index.test.ts (31.932 s)
11
+ A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --detectOpenHandles to find leaks. Active timers can also cause this, ensure that .unref() was called on them.
10
12
 
11
- Test Suites: 5 passed, 5 total
12
- Tests: 27 passed, 27 total
13
+ Test Suites: 6 passed, 6 total
14
+ Tests: 47 passed, 47 total
13
15
  Snapshots: 0 total
14
- Time: 26.467 s
16
+ Time: 33.242 s
15
17
  Ran all test suites.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,16 @@
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
+ # [3.96.0-dev.19](https://github.com/vtex/faststore/compare/v3.96.0-dev.18...v3.96.0-dev.19) (2026-01-08)
7
+
8
+ ### Features
9
+
10
+ - logout clear storage ([#3163](https://github.com/vtex/faststore/issues/3163)) ([1fbacc3](https://github.com/vtex/faststore/commit/1fbacc3b3e32b4f83a2f56c1f97eb0f8ff843f61))
11
+
12
+ # 3.96.0-dev.18 (2025-12-24)
13
+
14
+ **Note:** Version bump only for package @faststore/core
15
+
6
16
  # 3.96.0-dev.17 (2025-12-23)
7
17
 
8
18
  **Note:** Version bump only for package @faststore/core
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "3.96.0-dev.17",
3
+ "version": "3.96.0-dev.19",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -51,11 +51,11 @@
51
51
  "@envelop/graphql-jit": "^8.0.3",
52
52
  "@envelop/parser-cache": "^6.0.2",
53
53
  "@envelop/validation-cache": "^6.0.2",
54
- "@faststore/api": "3.96.0-dev.17",
55
- "@faststore/graphql-utils": "^3.96.0-dev.17",
56
- "@faststore/lighthouse": "3.96.0-dev.17",
57
- "@faststore/sdk": "3.96.0-dev.17",
58
- "@faststore/ui": "3.96.0-dev.17",
54
+ "@faststore/api": "3.96.0-dev.18",
55
+ "@faststore/graphql-utils": "^3.96.0-dev.18",
56
+ "@faststore/lighthouse": "3.96.0-dev.18",
57
+ "@faststore/sdk": "3.96.0-dev.18",
58
+ "@faststore/ui": "3.96.0-dev.18",
59
59
  "@graphql-codegen/cli": "5.0.2",
60
60
  "@graphql-codegen/client-preset": "4.2.6",
61
61
  "@graphql-codegen/typescript": "4.0.7",
@@ -123,5 +123,5 @@
123
123
  "ts-jest": "29.1.1",
124
124
  "typescript": "5.3.2"
125
125
  },
126
- "gitHead": "303ea1a81126ab23f136c241a18f00c681c574d8"
126
+ "gitHead": "f0c386389af326e23b23cc9813f0821585df9723"
127
127
  }
@@ -1,6 +1,12 @@
1
1
  import { SlideOver, useFadeEffect } from '@faststore/ui'
2
2
 
3
3
  import { useSession } from 'src/sdk/session'
4
+ import {
5
+ expireCookieClient,
6
+ getCookieDomains,
7
+ getCookiePaths,
8
+ getVtexCookieNames,
9
+ } from 'src/utils/clearCookies'
4
10
  import storeConfig from '../../../../../discovery.config'
5
11
  import { ProfileSummary } from '../ProfileSummary/ProfileSummary'
6
12
  import { OrganizationDrawerBody } from './OrganizationDrawerBody'
@@ -13,11 +19,105 @@ type OrganizationDrawerProps = {
13
19
  isRepresentative: boolean
14
20
  }
15
21
 
16
- export const doLogout = () => {
22
+ const clearBrowserStorageForCurrentDomain = async () => {
23
+ if (typeof window === 'undefined' || !storeConfig) return
24
+
25
+ // Clear Faststore-specific sessionStorage keys
26
+ try {
27
+ const sessionStorageKeys = [
28
+ 'faststore_session_ready',
29
+ 'faststore_auth_cookie_value',
30
+ 'faststore_cache_bust_last_value',
31
+ ]
32
+
33
+ for (const key of sessionStorageKeys) {
34
+ try {
35
+ window.sessionStorage?.removeItem(key)
36
+ } catch {}
37
+ }
38
+
39
+ // Remove all keys starting with __fs_gallery_page_ (used for PLP pagination)
40
+ try {
41
+ const keysToRemove: string[] = []
42
+ for (let i = 0; i < window.sessionStorage.length; i++) {
43
+ const key = window.sessionStorage.key(i)
44
+ if (key && key.startsWith('__fs_gallery_page_')) {
45
+ keysToRemove.push(key)
46
+ }
47
+ }
48
+ for (const key of keysToRemove) {
49
+ try {
50
+ window.sessionStorage.removeItem(key)
51
+ } catch {}
52
+ }
53
+ } catch {}
54
+ } catch {}
55
+
56
+ // Clear all cookies containing 'vtex' in the name (case-insensitive)
57
+ try {
58
+ const hostname = window.location.hostname
59
+ const secure = window.location.protocol === 'https:'
60
+
61
+ // Extract all cookie names from document.cookie
62
+ const allCookieNames = document.cookie
63
+ .split(';')
64
+ .map((c) => c.trim())
65
+ .filter(Boolean)
66
+ .map((c) => c.split('=')[0])
67
+ .filter(Boolean)
68
+
69
+ const vtexCookieNames = getVtexCookieNames(allCookieNames)
70
+ const paths = getCookiePaths(window.location.pathname || '/')
71
+ const domains = getCookieDomains(hostname)
72
+
73
+ for (const name of vtexCookieNames) {
74
+ for (const path of paths) {
75
+ for (const domain of domains) {
76
+ try {
77
+ expireCookieClient({ name, path, domain, secure })
78
+ } catch {}
79
+ }
80
+ }
81
+ }
82
+ } catch {}
83
+
84
+ // Clear IndexedDB (keyval-store)
85
+ try {
86
+ if (!('indexedDB' in window)) return
87
+
88
+ const idb = window.indexedDB
89
+ if (!idb) return
90
+
91
+ await new Promise<void>((resolve) => {
92
+ const req = idb.deleteDatabase('keyval-store')
93
+ req.onsuccess = () => resolve()
94
+ req.onerror = () => resolve()
95
+ req.onblocked = () => resolve()
96
+ })
97
+ } catch {}
98
+ }
99
+
100
+ export const doLogout = async (_event?: unknown) => {
17
101
  if (!storeConfig) return
18
- window.location.assign(
19
- `${storeConfig.secureSubdomain}/api/vtexid/pub/logout?scope=${storeConfig.api.storeId}&returnUrl=${storeConfig.storeUrl}`
20
- )
102
+
103
+ try {
104
+ // Clear client-side storage (sessionStorage, localStorage, IndexedDB, non-HttpOnly cookies)
105
+ await clearBrowserStorageForCurrentDomain()
106
+
107
+ // Clear HttpOnly cookies via API endpoint (server-side)
108
+ try {
109
+ await fetch('/api/fs/logout', {
110
+ method: 'POST',
111
+ credentials: 'include',
112
+ })
113
+ } catch {
114
+ // Continue even if API call fails
115
+ }
116
+ } finally {
117
+ window.location.assign(
118
+ `${storeConfig.secureSubdomain}/api/vtexid/pub/logout?scope=${storeConfig.api.storeId}&returnUrl=${storeConfig.storeUrl}`
119
+ )
120
+ }
21
121
  }
22
122
 
23
123
  export const OrganizationDrawer = ({
@@ -0,0 +1,76 @@
1
+ import { parse } from 'cookie'
2
+ import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
3
+
4
+ import discoveryConfig from 'discovery.config'
5
+ import {
6
+ expireCookieServer,
7
+ getCookieDomains,
8
+ getVtexCookieNames,
9
+ } from 'src/utils/clearCookies'
10
+
11
+ const ADDITIONAL_COOKIES = ['CheckoutOrderFormOwnership'] as const
12
+
13
+ /**
14
+ * Clears all cookies containing 'vtex' in the name (case-insensitive) + ADDITIONAL_COOKIES
15
+ * This endpoint handles HttpOnly cookies that cannot be cleared via JavaScript
16
+ */
17
+ const handler: NextApiHandler = async (
18
+ request: NextApiRequest,
19
+ response: NextApiResponse
20
+ ) => {
21
+ if (request.method !== 'POST') {
22
+ response.status(405).end()
23
+ return
24
+ }
25
+
26
+ try {
27
+ const hostname = request.headers.host?.split(':')[0] ?? ''
28
+ const cookies = parse(request.headers.cookie ?? '')
29
+ const domains = getCookieDomains(hostname)
30
+ const clearedCookies: string[] = []
31
+
32
+ const vtexCookieNames = getVtexCookieNames(Object.keys(cookies))
33
+
34
+ // Clear vid_rt cookie with specific path (only if refreshToken is enabled)
35
+ if (discoveryConfig.experimental?.refreshToken && cookies.vid_rt) {
36
+ for (const domain of domains) {
37
+ const clearedCookie = expireCookieServer({
38
+ name: 'vid_rt',
39
+ path: '/api/vtexid/refreshtoken/webstore',
40
+ domain,
41
+ })
42
+ clearedCookies.push(clearedCookie)
43
+ }
44
+ }
45
+
46
+ // Clear other cookies with path /
47
+ const otherCookieNames = [
48
+ ...vtexCookieNames,
49
+ ...ADDITIONAL_COOKIES.filter((name) => cookies[name]),
50
+ ]
51
+
52
+ for (const cookieName of otherCookieNames) {
53
+ for (const domain of domains) {
54
+ const clearedCookie = expireCookieServer({
55
+ name: cookieName,
56
+ path: '/',
57
+ domain,
58
+ })
59
+ clearedCookies.push(clearedCookie)
60
+ }
61
+ }
62
+
63
+ if (clearedCookies.length > 0) {
64
+ response.setHeader('set-cookie', clearedCookies)
65
+ }
66
+
67
+ response.status(200).json({ success: true })
68
+ } catch (error) {
69
+ console.error('Error clearing cookies:', error)
70
+ response
71
+ .status(500)
72
+ .json({ success: false, error: 'Failed to clear cookies' })
73
+ }
74
+ }
75
+
76
+ export default handler
@@ -0,0 +1,79 @@
1
+ type ExpireCookieClientParams = {
2
+ name: string
3
+ path: string
4
+ domain?: string
5
+ secure?: boolean
6
+ }
7
+
8
+ type ExpireCookieServerParams = {
9
+ name: string
10
+ path: string
11
+ domain?: string
12
+ }
13
+
14
+ /**
15
+ * Client-side: Expires a cookie by setting it to expire in the past
16
+ */
17
+ export const expireCookieClient = ({
18
+ name,
19
+ path,
20
+ domain,
21
+ secure = false,
22
+ }: ExpireCookieClientParams): void => {
23
+ const domainAttr = domain ? `; domain=${domain}` : ''
24
+ const secureAttr = secure ? '; secure' : ''
25
+ document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; max-age=0; path=${path}${domainAttr}; samesite=lax${secureAttr}`
26
+ }
27
+
28
+ /**
29
+ * Server-side: Generates a Set-Cookie header string to expire a cookie
30
+ */
31
+ export const expireCookieServer = ({
32
+ name,
33
+ path,
34
+ domain,
35
+ }: ExpireCookieServerParams): string => {
36
+ const domainAttr = domain ? `; domain=${domain}` : ''
37
+ return `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; max-age=0; path=${path}${domainAttr}; samesite=lax; httponly`
38
+ }
39
+
40
+ /**
41
+ * Utility functions for clearing cookies
42
+ * Shared logic between client-side and server-side cookie clearing
43
+ */
44
+
45
+ /**
46
+ * Generates domain variations for cookie clearing
47
+ * Tries multiple domain combinations to ensure cookies are cleared regardless of how they were set
48
+ */
49
+ export const getCookieDomains = (
50
+ hostname: string
51
+ ): Array<string | undefined> => [
52
+ undefined, // host-only cookie
53
+ hostname,
54
+ hostname.startsWith('.') ? hostname : `.${hostname}`,
55
+ ]
56
+
57
+ /**
58
+ * Filters cookie names that contain 'vtex' (case-insensitive)
59
+ */
60
+ export const getVtexCookieNames = (cookieNames: string[]): string[] => {
61
+ return cookieNames.filter((name) => name.toLowerCase().includes('vtex'))
62
+ }
63
+
64
+ /**
65
+ * Generates paths to try when clearing cookies
66
+ * Includes root path and all parent paths from current pathname
67
+ */
68
+ export const getCookiePaths = (pathname: string): string[] => {
69
+ const paths: string[] = ['/']
70
+ const pathParts = pathname.split('/').filter(Boolean)
71
+
72
+ let current = ''
73
+ for (const part of pathParts) {
74
+ current += `/${part}`
75
+ if (!paths.includes(current)) paths.push(current)
76
+ }
77
+
78
+ return paths
79
+ }