@faststore/core 4.3.0-dev.7 → 4.3.0-dev.8

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.
@@ -1,9 +1,9 @@
1
1
 
2
- > @faststore/core@4.3.0-dev.6 generate /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@4.3.0-dev.7 generate /home/runner/work/faststore/faststore/packages/core
3
3
  > pnpm run gen-types && pnpm run cache-graphql
4
4
 
5
5
 
6
- > @faststore/core@4.3.0-dev.6 gen-types /home/runner/work/faststore/faststore/packages/core
6
+ > @faststore/core@4.3.0-dev.7 gen-types /home/runner/work/faststore/faststore/packages/core
7
7
  > node ../cli/bin/run generate-types .
8
8
 
9
9
  [STARTED] Parse Configuration
@@ -19,7 +19,7 @@
19
19
  [COMPLETED] Generate to /home/runner/work/faststore/faststore/packages/core/@generated/
20
20
  [COMPLETED] Generate outputs
21
21
 
22
- > @faststore/core@4.3.0-dev.6 cache-graphql /home/runner/work/faststore/faststore/packages/core
22
+ > @faststore/core@4.3.0-dev.7 cache-graphql /home/runner/work/faststore/faststore/packages/core
23
23
  > node ../cli/bin/run cache-graphql --config=./discovery.config.default.js --queries=./@generated/persisted-documents.json
24
24
 
25
25
  [Info] - Config file location: /home/runner/work/faststore/faststore/packages/core/discovery.config.default.js
@@ -1,12 +1,12 @@
1
1
 
2
- > @faststore/core@4.3.0-dev.6 test /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@4.3.0-dev.7 test /home/runner/work/faststore/faststore/packages/core
3
3
  > vitest run
4
4
 
5
5
 
6
6
   RUN  v4.0.7 /home/runner/work/faststore/faststore/packages/core
7
7
 
8
- ✓  browser  test/sdk/session/getInitialSession.browser.test.ts (6 tests) 36ms
9
- ✓  browser  test/sdk/session/installLocaleCorrector.browser.test.ts (7 tests) 54ms
8
+ ✓  browser  test/sdk/session/getInitialSession.browser.test.ts (6 tests) 18ms
9
+ ✓  browser  test/sdk/session/installLocaleCorrector.browser.test.ts (7 tests) 76ms
10
10
  stderr | test/sdk/localization/store-url.browser.test.ts
11
11
  Error in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
12
12
  at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:119:27)
@@ -14,11 +14,245 @@
14
14
  at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:353:23)
15
15
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
16
16
 
17
- ✓  browser  test/sdk/localization/store-url.browser.test.ts (3 tests) 11ms
18
- ✓  node  test/utils/localization/bindingPaths.test.ts (71 tests) 123ms
19
- ✓  node  test/utils/match-url.test.ts (10 tests) 21ms
20
- ✓  browser  test/utils/isLocalHost.browser.test.ts (3 tests) 15ms
21
- ✓  node  test/sdk/localization/bindingSelector.test.ts (18 tests) 20ms
17
+ stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > posts the password and redirects to the requested return path
18
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
19
+
20
+ When testing, code that causes React state updates should be wrapped into act(...):
21
+
22
+ act(() => {
23
+ /* fire events that update state */
24
+ });
25
+ /* assert on the output */
26
+
27
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
28
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
29
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
30
+
31
+ When testing, code that causes React state updates should be wrapped into act(...):
32
+
33
+ act(() => {
34
+ /* fire events that update state */
35
+ });
36
+ /* assert on the output */
37
+
38
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
39
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
40
+
41
+ stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > posts the password and redirects to the requested return path
42
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
43
+
44
+ When testing, code that causes React state updates should be wrapped into act(...):
45
+
46
+ act(() => {
47
+ /* fire events that update state */
48
+ });
49
+ /* assert on the output */
50
+
51
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
52
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
53
+
54
+ ✓  browser  test/utils/isLocalHost.browser.test.ts (3 tests) 14ms
55
+ stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > defaults returnTo to root and shows API validation errors
56
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
57
+
58
+ When testing, code that causes React state updates should be wrapped into act(...):
59
+
60
+ act(() => {
61
+ /* fire events that update state */
62
+ });
63
+ /* assert on the output */
64
+
65
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
66
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
67
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
68
+
69
+ When testing, code that causes React state updates should be wrapped into act(...):
70
+
71
+ act(() => {
72
+ /* fire events that update state */
73
+ });
74
+ /* assert on the output */
75
+
76
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
77
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
78
+
79
+ stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > defaults returnTo to root and shows API validation errors
80
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
81
+
82
+ When testing, code that causes React state updates should be wrapped into act(...):
83
+
84
+ act(() => {
85
+ /* fire events that update state */
86
+ });
87
+ /* assert on the output */
88
+
89
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
90
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
91
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
92
+
93
+ When testing, code that causes React state updates should be wrapped into act(...):
94
+
95
+ act(() => {
96
+ /* fire events that update state */
97
+ });
98
+ /* assert on the output */
99
+
100
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
101
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
102
+
103
+ stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > uses the fallback invalid-password message when API omits an error
104
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
105
+
106
+ When testing, code that causes React state updates should be wrapped into act(...):
107
+
108
+ act(() => {
109
+ /* fire events that update state */
110
+ });
111
+ /* assert on the output */
112
+
113
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
114
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
115
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
116
+
117
+ When testing, code that causes React state updates should be wrapped into act(...):
118
+
119
+ act(() => {
120
+ /* fire events that update state */
121
+ });
122
+ /* assert on the output */
123
+
124
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
125
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
126
+
127
+ stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > uses the fallback invalid-password message when API omits an error
128
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
129
+
130
+ When testing, code that causes React state updates should be wrapped into act(...):
131
+
132
+ act(() => {
133
+ /* fire events that update state */
134
+ });
135
+ /* assert on the output */
136
+
137
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
138
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
139
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
140
+
141
+ When testing, code that causes React state updates should be wrapped into act(...):
142
+
143
+ act(() => {
144
+ /* fire events that update state */
145
+ });
146
+ /* assert on the output */
147
+
148
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
149
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
150
+
151
+ stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > shows service unavailable when the response is not a login payload
152
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
153
+
154
+ When testing, code that causes React state updates should be wrapped into act(...):
155
+
156
+ act(() => {
157
+ /* fire events that update state */
158
+ });
159
+ /* assert on the output */
160
+
161
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
162
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
163
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
164
+
165
+ When testing, code that causes React state updates should be wrapped into act(...):
166
+
167
+ act(() => {
168
+ /* fire events that update state */
169
+ });
170
+ /* assert on the output */
171
+
172
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
173
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
174
+
175
+ stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > shows service unavailable when the response is not a login payload
176
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
177
+
178
+ When testing, code that causes React state updates should be wrapped into act(...):
179
+
180
+ act(() => {
181
+ /* fire events that update state */
182
+ });
183
+ /* assert on the output */
184
+
185
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
186
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
187
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
188
+
189
+ When testing, code that causes React state updates should be wrapped into act(...):
190
+
191
+ act(() => {
192
+ /* fire events that update state */
193
+ });
194
+ /* assert on the output */
195
+
196
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
197
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
198
+
199
+ stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > shows service unavailable when the login request fails
200
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
201
+
202
+ When testing, code that causes React state updates should be wrapped into act(...):
203
+
204
+ act(() => {
205
+ /* fire events that update state */
206
+ });
207
+ /* assert on the output */
208
+
209
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
210
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
211
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
212
+
213
+ When testing, code that causes React state updates should be wrapped into act(...):
214
+
215
+ act(() => {
216
+ /* fire events that update state */
217
+ });
218
+ /* assert on the output */
219
+
220
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
221
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
222
+
223
+ stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > shows service unavailable when the login request fails
224
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
225
+
226
+ When testing, code that causes React state updates should be wrapped into act(...):
227
+
228
+ act(() => {
229
+ /* fire events that update state */
230
+ });
231
+ /* assert on the output */
232
+
233
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
234
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
235
+ Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
236
+
237
+ When testing, code that causes React state updates should be wrapped into act(...):
238
+
239
+ act(() => {
240
+ /* fire events that update state */
241
+ });
242
+ /* assert on the output */
243
+
244
+ This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
245
+ at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
246
+
247
+ ✓  browser  test/pages/password-protection.browser.test.tsx (6 tests) 1695ms
248
+ ✓ renders the password protection form  805ms
249
+ ✓  browser  test/sdk/localization/store-url.browser.test.ts (3 tests) 17ms
250
+ ✓  node  test/utils/localization/bindingPaths.test.ts (71 tests) 125ms
251
+ ✓  node  test/server/password-protection-service.test.ts (22 tests) 117ms
252
+ ✓  node  test/utils/match-url.test.ts (10 tests) 36ms
253
+ ✓  node  test/sdk/localization/bindingSelector.test.ts (18 tests) 28ms
254
+ ✓  node  test/pages/api/unlock.test.ts (15 tests) 856ms
255
+ ✓ returns 405 for non-POST requests  613ms
22
256
  stderr | test/components/search/SearchInputComponent.test.tsx
23
257
  Warning: forwardRef render functions accept exactly two parameters: props and ref. Did you forget to use the ref parameter?
24
258
 
@@ -82,17 +316,17 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
82
316
  at Suspense
83
317
  at Wrapper (/home/runner/work/faststore/faststore/packages/core/test/components/search/SearchInputComponent.test.tsx:106:20)
84
318
 
85
- ✓  node  test/components/search/SearchInputComponent.test.tsx (6 tests) 372ms
86
- ✓  node  test/utils/cookieCacheBusting.test.ts (10 tests) 50ms
87
- ✓  node  test/sdk/search/useSearchHistory.test.ts (13 tests) 244ms
88
- ✓  node  test/sdk/localization/useBindingSelector.test.tsx (12 tests) 71ms
89
- ✓  node  test/utils/clearCookies.test.ts (20 tests) 98ms
90
- ✓  node  test/utils/multipleTemplates.test.ts (8 tests) 37ms
319
+ ✓  node  test/components/search/SearchInputComponent.test.tsx (6 tests) 242ms
320
+ ✓  node  test/sdk/localization/useBindingSelector.test.tsx (12 tests) 25ms
321
+ ✓  node  test/sdk/search/useSearchHistory.test.ts (13 tests) 185ms
322
+ ✓  node  test/utils/cookieCacheBusting.test.ts (10 tests) 53ms
323
+ ✓  node  test/utils/clearCookies.test.ts (20 tests) 148ms
324
+ ✓  node  test/utils/multipleTemplates.test.ts (8 tests) 31ms
91
325
  stderr | test/sdk/account/useSetPassword.test.ts > useSetPassword > maps wrongcredentials error responses to the existing message
92
326
  Set password request failed: Bad Request
93
327
 
94
- ✓  node  test/sdk/account/useSetPassword.test.ts (6 tests) 247ms
95
- ✓  node  test/sdk/orderEntry/useOrderEntryOperation.test.ts (8 tests) 89ms
328
+ ✓  node  test/sdk/account/useSetPassword.test.ts (6 tests) 113ms
329
+ ✓  node  test/sdk/orderEntry/useOrderEntryOperation.test.ts (8 tests) 84ms
96
330
  stderr | test/pages/api/graphql.test.ts > /api/graphql error status propagation > propagates the upstream 400 from a wrapped BadRequestError instead of 500
97
331
  Graphql execution returned with error: [
98
332
  {
@@ -139,27 +373,29 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
139
373
  { message: 'bad', status: 400, type: 'BadRequestError' }
140
374
  ]
141
375
 
142
- ✓  node  test/pages/api/graphql.test.ts (10 tests) 59ms
143
- ✓  node  test/sdk/orderEntry/useOrderEntryUpload.test.ts (8 tests) 81ms
144
- ✓  node  test/sdk/orderEntry/useOrderEntry.test.ts (8 tests) 62ms
145
- ✓  node  test/sdk/orderEntry/useOrderFormItems.test.ts (7 tests) 41ms
146
- ✓  node  test/server/cms/global.test.ts (3 tests) 5ms
147
- ✓  node  test/server/index.test.ts (7 tests) 862ms
148
- ✓ should exist with its plugins  303ms
149
- ✓ should handle options and execute  311ms
150
- ✓  node  test/server/content/service.test.ts (5 tests) 6ms
151
- ✓  node  test/sdk/localization/store-url.test.ts (1 test) 5ms
152
- ✓  node  test/utils/getRequestHostname.test.ts (12 tests) 7ms
153
- ✓  node  test/pages/api/preview.test.ts (2 tests) 10ms
154
- ✓  node  test/sdk/auth/useAuth.test.ts (5 tests) 33ms
376
+ ✓  node  test/pages/api/graphql.test.ts (10 tests) 24ms
377
+ ✓  node  test/sdk/orderEntry/useOrderEntryUpload.test.ts (8 tests) 49ms
378
+ ✓  node  test/sdk/orderEntry/useOrderEntry.test.ts (8 tests) 48ms
379
+ ✓  node  test/sdk/orderEntry/useOrderFormItems.test.ts (7 tests) 39ms
380
+ ✓  node  test/proxy.test.ts (4 tests) 63ms
381
+ ✓  node  test/server/webops-api.test.ts (9 tests) 31ms
382
+ ✓  node  test/server/cms/global.test.ts (3 tests) 4ms
383
+ ✓  node  test/server/index.test.ts (7 tests) 1124ms
384
+ ✓ should handle options and execute  599ms
385
+ ✓  node  test/server/content/service.test.ts (5 tests) 5ms
386
+ ✓  node  test/utils/getRequestHostname.test.ts (12 tests) 5ms
387
+ ✓  node  test/sdk/localization/store-url.test.ts (1 test) 4ms
388
+ ✓  node  test/sdk/auth/useAuth.test.ts (5 tests) 32ms
155
389
  ✓  node  test/utils/validateSessionRefreshToken.test.ts (6 tests) 5ms
390
+ ✓  node  test/pages/api/preview.test.ts (2 tests) 10ms
156
391
  ✓  node  test/components/search/SearchInput.test.ts (6 tests) 8ms
157
- ✓  node  test/utils/isLocalHost.test.ts (7 tests) 6ms
392
+ ✓  node  test/utils/unlockResponse.test.ts (11 tests) 5ms
393
+ ✓  node  test/utils/isLocalHost.test.ts (7 tests) 5ms
158
394
  ✓  node  test/server/cms/index.test.ts (2 tests) 6ms
159
- ✓  node  test/components/auth/ProfileChallenge.test.tsx (3 tests) 27ms
395
+ ✓  node  test/components/auth/ProfileChallenge.test.tsx (3 tests) 26ms
160
396
 
161
-  Test Files  31 passed (31)
162
-  Tests  293 passed (293)
163
-  Start at  16:58:10
164
-  Duration  24.02s (transform 5.83s, setup 0ms, collect 19.89s, tests 2.71s, environment 32.71s, prepare 998ms)
397
+  Test Files  37 passed (37)
398
+  Tests  360 passed (360)
399
+  Start at  21:17:04
400
+  Duration  24.45s (transform 6.16s, setup 0ms, collect 17.83s, tests 5.36s, environment 32.81s, prepare 1.08s)
165
401
 
package/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
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.3.0-dev.8](https://github.com/vtex/faststore/compare/v4.3.0-dev.7...v4.3.0-dev.8) (2026-06-17)
7
+
8
+ ### Features
9
+
10
+ - Password Protection (v4) ([#3276](https://github.com/vtex/faststore/issues/3276)) ([575f162](https://github.com/vtex/faststore/commit/575f162f6ec6fda9d3134ab61f673a897dcc2f56))
11
+
6
12
  # [4.3.0-dev.7](https://github.com/vtex/faststore/compare/v4.3.0-dev.6...v4.3.0-dev.7) (2026-06-17)
7
13
 
8
14
  ### Bug Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "4.3.0-dev.7",
3
+ "version": "4.3.0-dev.8",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -58,6 +58,7 @@
58
58
  "fs-extra": "^10.1.0",
59
59
  "idb-keyval": "^5.1.3",
60
60
  "isomorphic-unfetch": "^3.1.0",
61
+ "jose": "^6.2.3",
61
62
  "lexical": "^0.34.0",
62
63
  "next": "^16.2.6",
63
64
  "next-seo": "^6.6.0",
@@ -70,17 +71,19 @@
70
71
  "style-loader": "^3.3.1",
71
72
  "swr": "^2.2.5",
72
73
  "use-sync-external-store": "^1.6.0",
73
- "@faststore/api": "4.3.0-dev.7",
74
- "@faststore/diagnostics": "4.3.0-dev.7",
75
- "@faststore/lighthouse": "4.3.0-dev.7",
76
- "@faststore/ui": "4.3.0-dev.7",
77
- "@faststore/sdk": "4.3.0-dev.7"
74
+ "@faststore/api": "4.3.0-dev.8",
75
+ "@faststore/diagnostics": "4.3.0-dev.8",
76
+ "@faststore/sdk": "4.3.0-dev.8",
77
+ "@faststore/ui": "4.3.0-dev.8",
78
+ "@faststore/lighthouse": "4.3.0-dev.8"
78
79
  },
79
80
  "devDependencies": {
80
81
  "@cypress/code-coverage": "^3.12.1",
81
82
  "@envelop/testing": "^10",
82
83
  "@testing-library/cypress": "^10.0.1",
84
+ "@testing-library/jest-dom": "6.9.1",
83
85
  "@testing-library/react": "14.3.1",
86
+ "@testing-library/user-event": "14.5.2",
84
87
  "@types/cookie": "^0.6.0",
85
88
  "@types/fs-extra": "^9.0.13",
86
89
  "@types/node": "20.19.13",
@@ -0,0 +1,123 @@
1
+ import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
2
+
3
+ import storeConfig from 'discovery.config'
4
+
5
+ import type { UnlockResponse } from 'src/utils/unlockResponse'
6
+ import {
7
+ sessionUrl,
8
+ passwordProtectionTimeouts,
9
+ } from 'src/server/password-protection/webops-api'
10
+ import {
11
+ COOKIE_NAME,
12
+ TOKEN_TTL_SECONDS,
13
+ } from 'src/server/password-protection-service'
14
+
15
+ interface WebOpsSessionPayload {
16
+ valid: boolean
17
+ token?: string
18
+ }
19
+
20
+ const isSafeReturnToPath = (value: string): boolean => {
21
+ return value.startsWith('/') && !value.startsWith('//')
22
+ }
23
+
24
+ const isWebOpsSessionPayload = (
25
+ data: unknown
26
+ ): data is WebOpsSessionPayload => {
27
+ if (typeof data !== 'object' || data === null || Array.isArray(data)) {
28
+ return false
29
+ }
30
+
31
+ const payload = data as Record<string, unknown>
32
+
33
+ return (
34
+ typeof payload.valid === 'boolean' &&
35
+ (payload.token === undefined || typeof payload.token === 'string')
36
+ )
37
+ }
38
+
39
+ const handler: NextApiHandler<UnlockResponse> = async (
40
+ request: NextApiRequest,
41
+ response: NextApiResponse<UnlockResponse>
42
+ ) => {
43
+ if (request.method !== 'POST') {
44
+ response.status(405).end()
45
+ return
46
+ }
47
+
48
+ const storeId = storeConfig.api.storeId
49
+
50
+ try {
51
+ const { password } = request.body ?? {}
52
+
53
+ if (!password || typeof password !== 'string') {
54
+ response.status(400).json({
55
+ success: false,
56
+ error: 'Password is required',
57
+ })
58
+ return
59
+ }
60
+
61
+ const webopsResponse = await fetch(sessionUrl(), {
62
+ method: 'POST',
63
+ headers: { 'Content-Type': 'application/json' },
64
+ body: JSON.stringify({ storeId, password }),
65
+ signal: AbortSignal.timeout(passwordProtectionTimeouts.defaultMs),
66
+ })
67
+
68
+ if (!webopsResponse.ok) {
69
+ if (webopsResponse.status === 401 || webopsResponse.status === 403) {
70
+ response.status(401).json({
71
+ success: false,
72
+ error: 'Invalid password',
73
+ })
74
+ return
75
+ }
76
+
77
+ response.status(503).json({
78
+ success: false,
79
+ error: 'Service temporarily unavailable',
80
+ })
81
+ return
82
+ }
83
+
84
+ const data: unknown = await webopsResponse.json()
85
+
86
+ if (!isWebOpsSessionPayload(data)) {
87
+ response.status(500).json({
88
+ success: false,
89
+ error: 'Internal server error',
90
+ })
91
+ return
92
+ }
93
+
94
+ if (data.valid && data.token) {
95
+ const returnTo =
96
+ typeof request.query.returnTo === 'string'
97
+ ? request.query.returnTo
98
+ : '/'
99
+ const sanitizedReturnTo = isSafeReturnToPath(returnTo) ? returnTo : '/'
100
+
101
+ response.setHeader('Set-Cookie', [
102
+ `${COOKIE_NAME}=${data.token}; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=${TOKEN_TTL_SECONDS}`,
103
+ ])
104
+
105
+ response.status(200).json({
106
+ success: true,
107
+ redirectUrl: sanitizedReturnTo,
108
+ })
109
+ } else {
110
+ response.status(401).json({
111
+ success: false,
112
+ error: 'Invalid password',
113
+ })
114
+ }
115
+ } catch {
116
+ response.status(503).json({
117
+ success: false,
118
+ error: 'Service temporarily unavailable',
119
+ })
120
+ }
121
+ }
122
+
123
+ export default handler
@@ -0,0 +1,93 @@
1
+ import { Button, InputField } from '@faststore/ui'
2
+ import Head from 'next/head'
3
+ import { useRouter } from 'next/router'
4
+ import { type FormEvent, useState } from 'react'
5
+
6
+ import { isUnlockResponse } from '../../utils/unlockResponse'
7
+ import styles from './password-protection.module.scss'
8
+
9
+ export default function PasswordProtectionLogin() {
10
+ const router = useRouter()
11
+ const returnTo =
12
+ typeof router.query.returnTo === 'string' ? router.query.returnTo : '/'
13
+
14
+ const [password, setPassword] = useState('')
15
+ const [error, setError] = useState('')
16
+ const [loading, setLoading] = useState(false)
17
+
18
+ const handleSubmit = async (e: FormEvent) => {
19
+ e.preventDefault()
20
+ setLoading(true)
21
+ setError('')
22
+
23
+ try {
24
+ const url = new URL(
25
+ '/api/fs/password-protection/unlock',
26
+ globalThis.location.origin
27
+ )
28
+ url.searchParams.set('returnTo', returnTo)
29
+
30
+ const response = await fetch(url.toString(), {
31
+ method: 'POST',
32
+ headers: { 'Content-Type': 'application/json' },
33
+ body: JSON.stringify({ password }),
34
+ })
35
+
36
+ const data: unknown = await response.json()
37
+
38
+ if (!isUnlockResponse(data)) {
39
+ setError('Service temporarily unavailable')
40
+ return
41
+ }
42
+
43
+ if (data.success && data.redirectUrl) {
44
+ globalThis.location.href = data.redirectUrl
45
+ } else {
46
+ setError(data.error ?? 'Invalid password')
47
+ }
48
+ } catch {
49
+ setError('Service temporarily unavailable')
50
+ } finally {
51
+ setLoading(false)
52
+ }
53
+ }
54
+
55
+ return (
56
+ <div className={styles.fsPasswordProtection}>
57
+ <Head>
58
+ <meta name="robots" content="noindex,nofollow" />
59
+ </Head>
60
+ <div className={styles.page}>
61
+ <h1 className={styles.title}>This store is password protected</h1>
62
+
63
+ <h2 className={styles.subtitle}>
64
+ Enter the password to access the store
65
+ </h2>
66
+
67
+ <form className={styles.form} onSubmit={handleSubmit}>
68
+ <InputField
69
+ id="password-protection-input"
70
+ label="Password"
71
+ type="password"
72
+ value={password}
73
+ onChange={(e) => setPassword(e.target.value)}
74
+ placeholder="Enter password"
75
+ autoComplete="current-password"
76
+ required
77
+ disabled={loading}
78
+ error={error || undefined}
79
+ />
80
+ <Button
81
+ type="submit"
82
+ variant="primary"
83
+ size="small"
84
+ disabled={loading}
85
+ loading={loading}
86
+ >
87
+ Unlock
88
+ </Button>
89
+ </form>
90
+ </div>
91
+ </div>
92
+ )
93
+ }