@faststore/core 4.3.0-dev.6 → 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.5 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.5 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.5 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.5 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/installLocaleCorrector.browser.test.ts (7 tests) 48ms
9
- ✓  browser  test/sdk/session/getInitialSession.browser.test.ts (6 tests) 29ms
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,15 +14,248 @@
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
- ✓  node  test/utils/localization/bindingPaths.test.ts (71 tests) 78ms
18
- ✓  browser  test/sdk/localization/store-url.browser.test.ts (3 tests) 18ms
19
- ✓  node  test/utils/match-url.test.ts (10 tests) 33ms
20
- ✓  browser  test/utils/isLocalHost.browser.test.ts (3 tests) 12ms
21
- ✓  node  test/sdk/localization/bindingSelector.test.ts (18 tests) 39ms
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
 
25
- ✓  node  test/utils/cookieCacheBusting.test.ts (10 tests) 55ms
26
259
  stderr | test/components/search/SearchInputComponent.test.tsx > SearchInput (OES integration) > renders without crashing
27
260
  Warning: React does not recognize the `visibleDropdown` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `visibledropdown` instead. If you accidentally passed it from a parent component, remove it from the DOM element.
28
261
  at div
@@ -83,12 +316,17 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
83
316
  at Suspense
84
317
  at Wrapper (/home/runner/work/faststore/faststore/packages/core/test/components/search/SearchInputComponent.test.tsx:106:20)
85
318
 
86
- ✓  node  test/components/search/SearchInputComponent.test.tsx (6 tests) 407ms
87
- ✓  node  test/sdk/search/useSearchHistory.test.ts (13 tests) 200ms
88
- ✓  node  test/sdk/localization/useBindingSelector.test.tsx (12 tests) 53ms
89
- ✓  node  test/utils/multipleTemplates.test.ts (8 tests) 30ms
90
- ✓  node  test/utils/clearCookies.test.ts (20 tests) 98ms
91
- ✓  node  test/sdk/orderEntry/useOrderEntryOperation.test.ts (8 tests) 118ms
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
325
+ stderr | test/sdk/account/useSetPassword.test.ts > useSetPassword > maps wrongcredentials error responses to the existing message
326
+ Set password request failed: Bad Request
327
+
328
+ ✓  node  test/sdk/account/useSetPassword.test.ts (6 tests) 113ms
329
+ ✓  node  test/sdk/orderEntry/useOrderEntryOperation.test.ts (8 tests) 84ms
92
330
  stderr | test/pages/api/graphql.test.ts > /api/graphql error status propagation > propagates the upstream 400 from a wrapped BadRequestError instead of 500
93
331
  Graphql execution returned with error: [
94
332
  {
@@ -135,26 +373,29 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
135
373
  { message: 'bad', status: 400, type: 'BadRequestError' }
136
374
  ]
137
375
 
138
- ✓  node  test/pages/api/graphql.test.ts (10 tests) 58ms
139
- ✓  node  test/sdk/orderEntry/useOrderEntryUpload.test.ts (8 tests) 48ms
140
- ✓  node  test/sdk/orderEntry/useOrderEntry.test.ts (8 tests) 33ms
141
- ✓  node  test/sdk/orderEntry/useOrderFormItems.test.ts (7 tests) 49ms
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
142
382
  ✓  node  test/server/cms/global.test.ts (3 tests) 4ms
143
- ✓  node  test/server/content/service.test.ts (5 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
144
387
  ✓  node  test/sdk/localization/store-url.test.ts (1 test) 4ms
145
- ✓  node  test/server/index.test.ts (7 tests) 990ms
146
- ✓ should handle options and execute  520ms
147
- ✓  node  test/utils/getRequestHostname.test.ts (12 tests) 6ms
148
- ✓  node  test/pages/api/preview.test.ts (2 tests) 7ms
149
388
  ✓  node  test/sdk/auth/useAuth.test.ts (5 tests) 32ms
150
389
  ✓  node  test/utils/validateSessionRefreshToken.test.ts (6 tests) 5ms
390
+ ✓  node  test/pages/api/preview.test.ts (2 tests) 10ms
151
391
  ✓  node  test/components/search/SearchInput.test.ts (6 tests) 8ms
152
- ✓  node  test/server/cms/index.test.ts (2 tests) 4ms
153
- ✓  node  test/utils/isLocalHost.test.ts (7 tests) 7ms
392
+ ✓  node  test/utils/unlockResponse.test.ts (11 tests) 5ms
393
+ ✓  node  test/utils/isLocalHost.test.ts (7 tests) 5ms
394
+ ✓  node  test/server/cms/index.test.ts (2 tests) 6ms
154
395
  ✓  node  test/components/auth/ProfileChallenge.test.tsx (3 tests) 26ms
155
396
 
156
-  Test Files  30 passed (30)
157
-  Tests  287 passed (287)
158
-  Start at  15:21:20
159
-  Duration  21.59s (transform 6.15s, setup 0ms, collect 18.64s, tests 2.50s, environment 28.13s, prepare 992ms)
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)
160
401
 
package/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
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
+
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)
13
+
14
+ ### Bug Fixes
15
+
16
+ - **core:** use authenticator route for setpassword ([#3380](https://github.com/vtex/faststore/issues/3380)) ([a155269](https://github.com/vtex/faststore/commit/a155269678d8a0584a98008b1384bf146f6da1cb))
17
+
6
18
  # [4.3.0-dev.6](https://github.com/vtex/faststore/compare/v4.3.0-dev.5...v4.3.0-dev.6) (2026-06-17)
7
19
 
8
20
  ### Bug Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "4.3.0-dev.6",
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.6",
74
- "@faststore/lighthouse": "4.3.0-dev.6",
75
- "@faststore/sdk": "4.3.0-dev.6",
76
- "@faststore/ui": "4.3.0-dev.6",
77
- "@faststore/diagnostics": "4.3.0-dev.6"
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
+ }