@faststore/core 4.5.1 → 4.6.0-dev.1
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.
- package/.turbo/turbo-generate.log +3 -3
- package/.turbo/turbo-test.log +135 -87
- package/CHANGELOG.md +39 -1
- package/README.md +1 -1
- package/cypress/integration/seo.test.js +35 -5
- package/discovery.config.default.js +1 -2
- package/next-seo.config.ts +3 -0
- package/next.config.js +21 -5
- package/package.json +8 -8
- package/src/instrumentation.ts +15 -7
- package/src/pages/api/graphql.ts +37 -11
- package/src/server/index.ts +38 -10
- package/src/server/options.ts +3 -22
- package/test/instrumentation.test.ts +27 -0
- package/test/pages/api/graphql.test.ts +40 -2
- package/test/server/rootSpan.test.ts +90 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@4.
|
|
2
|
+
> @faststore/core@4.6.0-dev.0 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.
|
|
6
|
+
> @faststore/core@4.6.0-dev.0 gen-types /home/runner/work/faststore/faststore/packages/core
|
|
7
7
|
> node ../cli/bin/run generate-types .
|
|
8
8
|
|
|
9
9
|
[33m[STARTED][39m Parse Configuration
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
[32m[COMPLETED][39m Generate to /home/runner/work/faststore/faststore/packages/core/@generated/
|
|
20
20
|
[32m[COMPLETED][39m Generate outputs
|
|
21
21
|
|
|
22
|
-
> @faststore/core@4.
|
|
22
|
+
> @faststore/core@4.6.0-dev.0 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
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@4.
|
|
2
|
+
> @faststore/core@4.6.0-dev.0 test /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> vitest run
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
[1m[46m RUN [49m[22m [36mv4.0.
|
|
6
|
+
[1m[46m RUN [49m[22m [36mv4.0.18 [39m[90m/home/runner/work/faststore/faststore/packages/core[39m
|
|
7
7
|
|
|
8
8
|
Not implemented: navigation to another Document
|
|
9
9
|
Not implemented: navigation to another Document
|
|
@@ -19,7 +19,7 @@ Not implemented: navigation to another Document
|
|
|
19
19
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:17) {
|
|
20
20
|
[cause]: TypeError: Invalid URL
|
|
21
21
|
[90m at new URL (node:internal/url:828:25)[39m
|
|
22
|
-
at new URL$1 (file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/vitest@4.0.
|
|
22
|
+
at new URL$1 (file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/vitest@4.0.18_@opentelemetry+api@1.9.0_@types+node@20.19.13_jiti@2.6.1_jsdom@27.4.0_sas_13be941c57d55f08f06eeaf1c180ddfe/node_modules/[4mvitest[24m/dist/chunks/index.CyBMJtT7.js:556:9)
|
|
23
23
|
[90m at new Request (node:internal/deps/undici/undici:10971:25)[39m
|
|
24
24
|
[90m at fetch (node:internal/deps/undici/undici:11891:25)[39m
|
|
25
25
|
[90m at fetch (node:internal/deps/undici/undici:16414:10)[39m
|
|
@@ -36,16 +36,18 @@ Not implemented: navigation to another Document
|
|
|
36
36
|
Browserslist: browsers data (caniuse-lite) is 6 months old. Please run:
|
|
37
37
|
npx update-browserslist-db@latest
|
|
38
38
|
Why you should do it regularly: https://github.com/browserslist/update-db#readme
|
|
39
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/ui/useScrollRestoration.browser.test.ts [2m([22m[2m43 tests[22m[2m)[22m[33m
|
|
39
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/ui/useScrollRestoration.browser.test.ts [2m([22m[2m43 tests[22m[2m)[22m[33m 1055[2mms[22m[39m
|
|
40
40
|
[90mstderr[2m | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx[2m > [22m[2mRecommendationShelf[2m > [22m[2mrenders nothing when there is an error
|
|
41
41
|
[22m[39mError fetching recommendations [90mundefined[39m boom for campaign vrn:recommendations:acc:rec-top-items-v2:campaign-1
|
|
42
42
|
|
|
43
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
44
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/ContractSwitcher.browser.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[33m
|
|
45
|
-
[33m[2m✓[22m[39m shows an error state when the list fails to load [33m
|
|
46
|
-
[33m[2m✓[22m[39m requires selecting a contract before Confirm is enabled, then switches (REQ-03) [33m
|
|
47
|
-
|
|
48
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
43
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 209[2mms[22m[39m
|
|
44
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/ContractSwitcher.browser.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[33m 2760[2mms[22m[39m
|
|
45
|
+
[33m[2m✓[22m[39m shows an error state when the list fails to load [33m 743[2mms[22m[39m
|
|
46
|
+
[33m[2m✓[22m[39m requires selecting a contract before Confirm is enabled, then switches (REQ-03) [33m 391[2mms[22m[39m
|
|
47
|
+
[33m[2m✓[22m[39m does not reload when the switch returns false [33m 308[2mms[22m[39m
|
|
48
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 63[2mms[22m[39m
|
|
49
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/ui/ProductGallery/GalleryPageHeightLock.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 252[2mms[22m[39m
|
|
50
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/getInitialSession.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 26[2mms[22m[39m
|
|
49
51
|
[90mstderr[2m | test/pages/password-protection.browser.test.tsx[2m > [22m[2mPasswordProtectionLogin[2m > [22m[2mposts the password and redirects to the requested return path
|
|
50
52
|
[22m[39mWarning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
|
|
51
53
|
|
|
@@ -275,13 +277,11 @@ act(() => {
|
|
|
275
277
|
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
|
|
276
278
|
at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
|
|
277
279
|
|
|
278
|
-
[32m✓[39m [30m[46m browser [49m[39m test/pages/password-protection.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m
|
|
279
|
-
[33m[2m✓[22m[39m renders the password protection form [33m
|
|
280
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
[33m[2m✓[22m[39m opens the contract switcher and returns to the menu on back [33m 452[2mms[22m[39m
|
|
284
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/changeContractToken.browser.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 55[2mms[22m[39m
|
|
280
|
+
[32m✓[39m [30m[46m browser [49m[39m test/pages/password-protection.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 1700[2mms[22m[39m
|
|
281
|
+
[33m[2m✓[22m[39m renders the password protection form [33m 845[2mms[22m[39m
|
|
282
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawer.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 1546[2mms[22m[39m
|
|
283
|
+
[33m[2m✓[22m[39m renders the menu view with contract details and manage footer [33m 853[2mms[22m[39m
|
|
284
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/changeContractToken.browser.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 112[2mms[22m[39m
|
|
285
285
|
[90mstderr[2m | test/sdk/localization/store-url.browser.test.ts
|
|
286
286
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
287
287
|
at validateCart [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/index.ts:121:27[90m)[39m
|
|
@@ -289,10 +289,10 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
289
289
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
290
290
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
291
291
|
|
|
292
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/localization/store-url.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
293
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useAvailableContracts.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
294
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/templates/SearchPage/SearchWrapper.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
295
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useSwitchContract.browser.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
292
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/localization/store-url.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 10[2mms[22m[39m
|
|
293
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useAvailableContracts.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 41[2mms[22m[39m
|
|
294
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/templates/SearchPage/SearchWrapper.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 38[2mms[22m[39m
|
|
295
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useSwitchContract.browser.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 43[2mms[22m[39m
|
|
296
296
|
[90mstderr[2m | test/components/account/doLogout.browser.test.ts
|
|
297
297
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
298
298
|
at validateCart [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/index.ts:121:27[90m)[39m
|
|
@@ -300,8 +300,8 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
300
300
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
301
301
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
302
302
|
|
|
303
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/doLogout.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
304
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerHeader.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
303
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/doLogout.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 18[2mms[22m[39m
|
|
304
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerHeader.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 295[2mms[22m[39m
|
|
305
305
|
[90mstderr[2m | test/sdk/account/clearPersistedSessionState.browser.test.ts
|
|
306
306
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
307
307
|
at validateCart [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/index.ts:121:27[90m)[39m
|
|
@@ -309,13 +309,11 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
309
309
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
310
310
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
311
311
|
|
|
312
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/clearPersistedSessionState.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
313
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerFooter.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
314
|
-
[32m✓[39m [30m[46m browser [49m[39m test/utils/isLocalHost.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
315
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
316
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/bindingPaths.test.ts [2m([22m[2m71 tests[22m[2m)[22m[32m
|
|
317
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/skeletons/ProductGridSkeleton.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 38[2mms[22m[39m
|
|
318
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/password-protection-service.test.ts [2m([22m[2m22 tests[22m[2m)[22m[32m 30[2mms[22m[39m
|
|
312
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/clearPersistedSessionState.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
313
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerFooter.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 255[2mms[22m[39m
|
|
314
|
+
[32m✓[39m [30m[46m browser [49m[39m test/utils/isLocalHost.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
315
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
316
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/bindingPaths.test.ts [2m([22m[2m71 tests[22m[2m)[22m[32m 29[2mms[22m[39m
|
|
319
317
|
[90mstderr[2m | test/sdk/account/refreshToken.browser.test.ts
|
|
320
318
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
321
319
|
at validateCart [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/index.ts:121:27[90m)[39m
|
|
@@ -323,11 +321,13 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
323
321
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
|
|
324
322
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
325
323
|
|
|
324
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/refreshToken.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
325
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/skeletons/ProductGridSkeleton.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 48[2mms[22m[39m
|
|
326
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/password-protection-service.test.ts [2m([22m[2m22 tests[22m[2m)[22m[32m 38[2mms[22m[39m
|
|
326
327
|
[32m✓[39m [30m[43m node [49m[39m test/utils/match-url.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 10[2mms[22m[39m
|
|
327
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/refreshToken.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
328
328
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/useBindingSelector.test.tsx [2m([22m[2m22 tests[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
329
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/unlock.test.ts [2m([22m[2m15 tests[22m[2m)[22m[32m
|
|
330
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/bindingSelector.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m
|
|
329
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/unlock.test.ts [2m([22m[2m15 tests[22m[2m)[22m[32m 284[2mms[22m[39m
|
|
330
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/bindingSelector.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
331
331
|
[90mstderr[2m | test/components/search/SearchInputComponent.test.tsx
|
|
332
332
|
[22m[39mWarning: forwardRef render functions accept exactly two parameters: props and ref. Did you forget to use the ref parameter?
|
|
333
333
|
|
|
@@ -391,24 +391,11 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
391
391
|
at Suspense
|
|
392
392
|
at Wrapper (/home/runner/work/faststore/faststore/packages/core/test/components/search/SearchInputComponent.test.tsx:106:20)
|
|
393
393
|
|
|
394
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInputComponent.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
395
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/cookieCacheBusting.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
396
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/search/useSearchHistory.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m
|
|
397
|
-
[32m✓[39m [30m[43m node [49m[39m test/experimental/myAccountCmsServerSideProps.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
398
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/clearCookies.test.ts [2m([22m[2m20 tests[22m[2m)[22m[32m
|
|
399
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotesTable.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[33m 419[2mms[22m[39m
|
|
400
|
-
[90mstderr[2m | test/sdk/account/useSetPassword.test.ts[2m > [22m[2museSetPassword[2m > [22m[2mmaps wrongcredentials error responses to the existing message
|
|
401
|
-
[22m[39mSet password request failed: Bad Request
|
|
402
|
-
|
|
403
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/useSetPassword.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 34[2mms[22m[39m
|
|
404
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/quoteFilters.test.ts [2m([22m[2m23 tests[22m[2m)[22m[32m 24[2mms[22m[39m
|
|
405
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/multipleTemplates.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
406
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/localizeRedirectDestination.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
407
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotes.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 804[2mms[22m[39m
|
|
408
|
-
[33m[2m✓[22m[39m navigates with the search term on blur [33m 359[2mms[22m[39m
|
|
409
|
-
[33m[2m✓[22m[39m navigates without a label param when the search is cleared [33m 358[2mms[22m[39m
|
|
410
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryOperation.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 42[2mms[22m[39m
|
|
411
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryUpload.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 56[2mms[22m[39m
|
|
394
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInputComponent.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 63[2mms[22m[39m
|
|
395
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/cookieCacheBusting.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
396
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/search/useSearchHistory.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m 63[2mms[22m[39m
|
|
397
|
+
[32m✓[39m [30m[43m node [49m[39m test/experimental/myAccountCmsServerSideProps.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
398
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/clearCookies.test.ts [2m([22m[2m20 tests[22m[2m)[22m[32m 23[2mms[22m[39m
|
|
412
399
|
[90mstderr[2m | test/pages/api/graphql.test.ts[2m > [22m[2m/api/graphql error status propagation[2m > [22m[2mpropagates the upstream 400 from a wrapped BadRequestError instead of 500
|
|
413
400
|
[22m[39mGraphql execution returned with error: [
|
|
414
401
|
{
|
|
@@ -455,47 +442,108 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
455
442
|
{ message: [32m'bad'[39m, status: [33m400[39m, type: [32m'BadRequestError'[39m }
|
|
456
443
|
]
|
|
457
444
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
[
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
445
|
+
[90mstderr[2m | test/pages/api/graphql.test.ts[2m > [22m[2m/api/graphql request handling[2m > [22m[2mmaps BadRequestError thrown by execute to its status
|
|
446
|
+
[22m[39mSomething unexpected occurred querying Graphql endpoint:
|
|
447
|
+
_ [FastStoreError]: malformed
|
|
448
|
+
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:190:31
|
|
449
|
+
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:196:39
|
|
450
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1024:60
|
|
451
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:145:11
|
|
452
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:915:26
|
|
453
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1243:20
|
|
454
|
+
at new Promise (<anonymous>)
|
|
455
|
+
at runWithTimeout (file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1209:10)
|
|
456
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1653:37
|
|
457
|
+
at Traces.$ (file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/vitest@4.0.18_@opentelemetry+api@1.9.0_@types+node@20.19.13_jiti@2.6.1_jsdom@27.4.0_sas_13be941c57d55f08f06eeaf1c180ddfe/node_modules/[4mvitest[24m/dist/chunks/traces.CCmnQaNT.js:142:27) {
|
|
458
|
+
extensions: { status: [33m400[39m, type: [32m'BadRequestError'[39m }
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
[90mstderr[2m | test/pages/api/graphql.test.ts[2m > [22m[2m/api/graphql request handling[2m > [22m[2mmaps UnauthorizedError thrown by execute to its status
|
|
462
|
+
[22m[39mSomething unexpected occurred querying Graphql endpoint:
|
|
463
|
+
te [FastStoreError]: expired
|
|
464
|
+
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:191:33
|
|
465
|
+
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:196:39
|
|
466
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1024:60
|
|
467
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:145:11
|
|
468
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:915:26
|
|
469
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1243:20
|
|
470
|
+
at new Promise (<anonymous>)
|
|
471
|
+
at runWithTimeout (file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1209:10)
|
|
472
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1653:37
|
|
473
|
+
at Traces.$ (file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/vitest@4.0.18_@opentelemetry+api@1.9.0_@types+node@20.19.13_jiti@2.6.1_jsdom@27.4.0_sas_13be941c57d55f08f06eeaf1c180ddfe/node_modules/[4mvitest[24m/dist/chunks/traces.CCmnQaNT.js:142:27) {
|
|
474
|
+
extensions: { status: [33m401[39m, type: [32m'UnauthorizedError'[39m }
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
[90mstderr[2m | test/pages/api/graphql.test.ts[2m > [22m[2m/api/graphql request handling[2m > [22m[2mmaps an unexpected failure thrown by execute to its status
|
|
478
|
+
[22m[39mSomething unexpected occurred querying Graphql endpoint:
|
|
479
|
+
Error: socket hang up
|
|
480
|
+
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:192:37
|
|
481
|
+
at [90m/home/runner/work/faststore/faststore/packages/core/[39mtest/pages/api/graphql.test.ts:196:39
|
|
482
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1024:60
|
|
483
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:145:11
|
|
484
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:915:26
|
|
485
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1243:20
|
|
486
|
+
at new Promise (<anonymous>)
|
|
487
|
+
at runWithTimeout (file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1209:10)
|
|
488
|
+
at file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1653:37
|
|
489
|
+
at Traces.$ (file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/vitest@4.0.18_@opentelemetry+api@1.9.0_@types+node@20.19.13_jiti@2.6.1_jsdom@27.4.0_sas_13be941c57d55f08f06eeaf1c180ddfe/node_modules/[4mvitest[24m/dist/chunks/traces.CCmnQaNT.js:142:27)
|
|
490
|
+
|
|
491
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/graphql.test.ts [2m([22m[2m17 tests[22m[2m)[22m[32m 39[2mms[22m[39m
|
|
492
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotesTable.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[33m 424[2mms[22m[39m
|
|
493
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotes.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[33m 847[2mms[22m[39m
|
|
494
|
+
[33m[2m✓[22m[39m navigates with the search term on blur [33m 363[2mms[22m[39m
|
|
495
|
+
[33m[2m✓[22m[39m navigates without a label param when the search is cleared [33m 357[2mms[22m[39m
|
|
496
|
+
[90mstderr[2m | test/sdk/account/useSetPassword.test.ts[2m > [22m[2museSetPassword[2m > [22m[2mmaps wrongcredentials error responses to the existing message
|
|
497
|
+
[22m[39mSet password request failed: Bad Request
|
|
498
|
+
|
|
499
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/useSetPassword.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 32[2mms[22m[39m
|
|
500
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryOperation.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 41[2mms[22m[39m
|
|
501
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/multipleTemplates.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
502
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/quoteFilters.test.ts [2m([22m[2m23 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
|
503
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/localizeRedirectDestination.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
504
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryUpload.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 54[2mms[22m[39m
|
|
505
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesFilterSlider.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 198[2mms[22m[39m
|
|
506
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/useStartRecommendationSession.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 51[2mms[22m[39m
|
|
507
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/index.test.ts [2m([22m[2m7 tests[22m[2m)[22m[33m 809[2mms[22m[39m
|
|
508
|
+
[33m[2m✓[22m[39m should return a valid merged GraphQL schema [33m 315[2mms[22m[39m
|
|
509
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntry.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 42[2mms[22m[39m
|
|
510
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getMyAccountRoutes.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
511
|
+
[32m✓[39m [30m[43m node [49m[39m test/proxy.localization.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 49[2mms[22m[39m
|
|
466
512
|
[32m✓[39m [30m[43m node [49m[39m test/proxy.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 21[2mms[22m[39m
|
|
467
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
468
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/
|
|
469
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderFormItems.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m
|
|
470
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
471
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
472
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/
|
|
513
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/webops-api.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
514
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/content/service.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
515
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderFormItems.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 46[2mms[22m[39m
|
|
516
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesSelectedTags.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 112[2mms[22m[39m
|
|
517
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/refreshToken.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 9[2mms[22m[39m
|
|
518
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/cms/global.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
473
519
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/store-url.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
520
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/auth/useAuth.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 29[2mms[22m[39m
|
|
474
521
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/hasEnabledRecommendationShelf.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
475
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
476
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
477
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
478
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/validateSessionRefreshToken.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
479
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/preview.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
522
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesStatusSelector.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 143[2mms[22m[39m
|
|
523
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/getRequestHostname.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
524
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/preview.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
480
525
|
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInput.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
481
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
482
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/
|
|
483
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
484
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
485
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
526
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/validateSessionRefreshToken.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
527
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/rootSpan.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 39[2mms[22m[39m
|
|
528
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/RecommendationShelf/vrn.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
529
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/cms/index.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
530
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/retry.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 19[2mms[22m[39m
|
|
531
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/Layout.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 42[2mms[22m[39m
|
|
532
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/RecommendationShelf/useRecommendationUserId.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 183[2mms[22m[39m
|
|
486
533
|
[32m✓[39m [30m[43m node [49m[39m test/utils/unlockResponse.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
487
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/cms/myAccountDefaultSections.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
488
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/RecommendationShelf/useRecommendations.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
489
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/isLocalHost.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m
|
|
534
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/cms/myAccountDefaultSections.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
535
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/RecommendationShelf/useRecommendations.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
536
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/isLocalHost.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
537
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/OrganizationDrawerBody.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 42[2mms[22m[39m
|
|
490
538
|
[32m✓[39m [30m[43m node [49m[39m test/utils/userOrderStatus.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
491
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/account/OrganizationDrawerBody.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 49[2mms[22m[39m
|
|
492
539
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/utils.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
493
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
494
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
495
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
[2m
|
|
499
|
-
[2m
|
|
500
|
-
[2m
|
|
540
|
+
[32m✓[39m [30m[43m node [49m[39m test/instrumentation.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
541
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/auth/ProfileChallenge.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 33[2mms[22m[39m
|
|
542
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/clearPersistedSessionState.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
543
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuoteStatusBadge.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 25[2mms[22m[39m
|
|
544
|
+
|
|
545
|
+
[2m Test Files [22m [1m[32m79 passed[39m[22m[90m (79)[39m
|
|
546
|
+
[2m Tests [22m [1m[32m640 passed[39m[22m[90m (640)[39m
|
|
547
|
+
[2m Start at [22m 23:16:25
|
|
548
|
+
[2m Duration [22m 41.03s[2m (transform 8.89s, setup 0ms, import 34.03s, tests 12.55s, environment 53.93s)[22m
|
|
501
549
|
|
package/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
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
|
-
|
|
6
|
+
# [4.6.0-dev.1](https://github.com/vtex/faststore/compare/v4.6.0-dev.0...v4.6.0-dev.1) (2026-08-11)
|
|
7
|
+
|
|
8
|
+
## [4.5.1](https://github.com/vtex/faststore/compare/v4.5.1-dev.4...v4.5.1) (2026-08-11)
|
|
7
9
|
|
|
8
10
|
### Bug Fixes
|
|
9
11
|
|
|
@@ -21,6 +23,42 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
|
|
|
21
23
|
- **core:** type scroll restore paint timer for DOM/Node setTimeout ([940c903](https://github.com/vtex/faststore/commit/940c90376f8d2eb77665e73a6fb0ea53c9786c8e))
|
|
22
24
|
- **core:** use replaceAll for infinite-scroll session key ([4f52048](https://github.com/vtex/faststore/commit/4f520482a9ba9661782fcf25a286b8f2e6c6b922))
|
|
23
25
|
|
|
26
|
+
# [4.6.0-dev.0](https://github.com/vtex/faststore/compare/v4.5.1-dev.4...v4.6.0-dev.0) (2026-08-11)
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
- removing vtex/diagnostics-nodejs ([#3389](https://github.com/vtex/faststore/issues/3389)) ([74e2d50](https://github.com/vtex/faststore/commit/74e2d503a44903929b90af7701956536690d4e41))
|
|
31
|
+
|
|
32
|
+
## [4.5.1-dev.4](https://github.com/vtex/faststore/compare/v4.5.1-dev.3...v4.5.1-dev.4) (2026-08-10)
|
|
33
|
+
|
|
34
|
+
**Note:** Version bump only for package @faststore/core
|
|
35
|
+
|
|
36
|
+
## [4.5.1-dev.3](https://github.com/vtex/faststore/compare/v4.5.1-dev.2...v4.5.1-dev.3) (2026-08-10)
|
|
37
|
+
|
|
38
|
+
### Bug Fixes
|
|
39
|
+
|
|
40
|
+
- **core:** add twitter card meta tag to default next seo config ([720f3e6](https://github.com/vtex/faststore/commit/720f3e6d04ef523f2fcf0e146c3741b7e5af70fa))
|
|
41
|
+
- **core:** add twittermeta tags validaton for tests ([c8f5872](https://github.com/vtex/faststore/commit/c8f5872e42b69ddae5b2abfa0e8d3140e2bc7163))
|
|
42
|
+
- **core:** lint error ([d07460f](https://github.com/vtex/faststore/commit/d07460f890ba712c9aecbec25bda5de96bf3e4ef))
|
|
43
|
+
- **core:** remove duplicated twitter meta tag ([f388288](https://github.com/vtex/faststore/commit/f388288731ff75fceedba3cd7449ef1088b0b0c2))
|
|
44
|
+
- **metaTags:** add twitter meta tags to nextSeo ([9c2439b](https://github.com/vtex/faststore/commit/9c2439b4a668dd81b7bfe5bdc44df575725067ec))
|
|
45
|
+
|
|
46
|
+
## [4.5.1](https://github.com/vtex/faststore/compare/v4.5.1-dev.2...v4.5.1) (2026-08-11)
|
|
47
|
+
|
|
48
|
+
- **core:** address scroll restoration review feedback ([a5fe6a3](https://github.com/vtex/faststore/commit/a5fe6a35c54e6095f81c7995a815ce6ef3b4dd4e))
|
|
49
|
+
- **core:** align beforePopState callback with NextHistoryState ([10719e5](https://github.com/vtex/faststore/commit/10719e5eca199385d9fe18bdd6d7da290716a1d5))
|
|
50
|
+
- **core:** compare window to undefined directly for Sonar ([bf05a54](https://github.com/vtex/faststore/commit/bf05a54bb014d120b7bdc95ff7c01a4e9b35b485))
|
|
51
|
+
- **core:** harden scroll restore path matching and hydration-safe heights ([34efa6b](https://github.com/vtex/faststore/commit/34efa6bda7549895a4531277c2fe55bd6bbe98a7))
|
|
52
|
+
- **core:** hash gallery height keys to avoid truncation collisions ([9e98043](https://github.com/vtex/faststore/commit/9e980438d74e457fa33aa77900438339463a078c))
|
|
53
|
+
- **core:** prevent IS redirect hang and improve scroll restoration ([5f30778](https://github.com/vtex/faststore/commit/5f30778161eec2e4381b3fe971479dd7cbe53b08))
|
|
54
|
+
- **core:** reset infinite scroll on forward listing navigations ([249226a](https://github.com/vtex/faststore/commit/249226a3acbe4cb26d687cf962125b2593d5949e))
|
|
55
|
+
- **core:** resolve Sonar new-code smells for scroll restoration ([59b41ed](https://github.com/vtex/faststore/commit/59b41ed1d2a30ba693726b19895a0279eb1ba464))
|
|
56
|
+
- **core:** restore PLP infinite-scroll pages on back navigation ([92b2efa](https://github.com/vtex/faststore/commit/92b2efa1d4d0895a10b5a0e71a4d9bf37cae1686))
|
|
57
|
+
- **core:** resync gallery height lock when children change ([5058089](https://github.com/vtex/faststore/commit/50580898d97baf800b97c8a876f7967529859c61))
|
|
58
|
+
- **core:** satisfy Sonar on gallery height key hash ([3a6ce47](https://github.com/vtex/faststore/commit/3a6ce47485c26be75d6d76906df3af64c9e34fd6))
|
|
59
|
+
- **core:** type scroll restore paint timer for DOM/Node setTimeout ([940c903](https://github.com/vtex/faststore/commit/940c90376f8d2eb77665e73a6fb0ea53c9786c8e))
|
|
60
|
+
- **core:** use replaceAll for infinite-scroll session key ([4f52048](https://github.com/vtex/faststore/commit/4f520482a9ba9661782fcf25a286b8f2e6c6b922))
|
|
61
|
+
|
|
24
62
|
## [4.5.1-dev.2](https://github.com/vtex/faststore/compare/v4.5.1-dev.1...v4.5.1-dev.2) (2026-08-04)
|
|
25
63
|
|
|
26
64
|
**Note:** Version bump only for package @faststore/core
|
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ packages/core/
|
|
|
31
31
|
│ ├── server/ # Server-side utilities (CMS content fetching)
|
|
32
32
|
│ ├── customizations/ # Store-level overrides: styles, fonts, components, fragments
|
|
33
33
|
│ ├── styles/ # Global SCSS styles
|
|
34
|
-
│ └── instrumentation.ts # Next.js instrumentation hook (boots @faststore/diagnostics
|
|
34
|
+
│ └── instrumentation.ts # Next.js instrumentation hook (boots @faststore/diagnostics — see docs/observability.md)
|
|
35
35
|
├── cms/faststore/ # CMS configuration: sections.json, content-types.json, schemas
|
|
36
36
|
├── @generated/ # Auto-generated GraphQL types — do not edit
|
|
37
37
|
├── discovery.config.default.js # Committed base store configuration (platform, sales channel, locale)
|
|
@@ -47,7 +47,7 @@ describe('Home Page Seo', () => {
|
|
|
47
47
|
})
|
|
48
48
|
})
|
|
49
49
|
|
|
50
|
-
it('has OpenGraph tags', () => {
|
|
50
|
+
it('has OpenGraph and Twitter tags', () => {
|
|
51
51
|
cy.visit(pages.home, options)
|
|
52
52
|
cy.waitForHydration()
|
|
53
53
|
|
|
@@ -68,6 +68,12 @@ describe('Home Page Seo', () => {
|
|
|
68
68
|
.should(($el) => {
|
|
69
69
|
expect($el.attr('content')).to.be.a('string')
|
|
70
70
|
})
|
|
71
|
+
|
|
72
|
+
cy.get('meta[name="twitter:card"]')
|
|
73
|
+
.should('exist')
|
|
74
|
+
.should(($el) => {
|
|
75
|
+
expect($el.attr('content')).to.eq('summary_large_image')
|
|
76
|
+
})
|
|
71
77
|
})
|
|
72
78
|
})
|
|
73
79
|
|
|
@@ -117,7 +123,7 @@ describe('Product Page Seo', () => {
|
|
|
117
123
|
})
|
|
118
124
|
})
|
|
119
125
|
|
|
120
|
-
it('has OpenGraph tags', () => {
|
|
126
|
+
it('has OpenGraph and Twitter tags', () => {
|
|
121
127
|
cy.visit(pages.pdp, options)
|
|
122
128
|
cy.waitForHydration()
|
|
123
129
|
|
|
@@ -156,6 +162,12 @@ describe('Product Page Seo', () => {
|
|
|
156
162
|
.should(($el) => {
|
|
157
163
|
expect($el.attr('content')).to.be.a('string')
|
|
158
164
|
})
|
|
165
|
+
|
|
166
|
+
cy.get('meta[name="twitter:card"]')
|
|
167
|
+
.should('exist')
|
|
168
|
+
.should(($el) => {
|
|
169
|
+
expect($el.attr('content')).to.eq('summary_large_image')
|
|
170
|
+
})
|
|
159
171
|
})
|
|
160
172
|
})
|
|
161
173
|
|
|
@@ -201,7 +213,7 @@ describe('Collection Page Seo', () => {
|
|
|
201
213
|
})
|
|
202
214
|
})
|
|
203
215
|
|
|
204
|
-
it('has OpenGraph tags', () => {
|
|
216
|
+
it('has OpenGraph and Twitter tags', () => {
|
|
205
217
|
cy.visit(pages.collection, options)
|
|
206
218
|
cy.waitForHydration()
|
|
207
219
|
|
|
@@ -222,6 +234,12 @@ describe('Collection Page Seo', () => {
|
|
|
222
234
|
.should(($el) => {
|
|
223
235
|
expect($el.attr('content')).to.be.a('string')
|
|
224
236
|
})
|
|
237
|
+
|
|
238
|
+
cy.get('meta[name="twitter:card"]')
|
|
239
|
+
.should('exist')
|
|
240
|
+
.should(($el) => {
|
|
241
|
+
expect($el.attr('content')).to.eq('summary_large_image')
|
|
242
|
+
})
|
|
225
243
|
})
|
|
226
244
|
})
|
|
227
245
|
|
|
@@ -256,7 +274,7 @@ describe('Filtered Collection Page Seo', () => {
|
|
|
256
274
|
})
|
|
257
275
|
})
|
|
258
276
|
|
|
259
|
-
it('has OpenGraph tags', () => {
|
|
277
|
+
it('has OpenGraph and Twitter tags', () => {
|
|
260
278
|
cy.visit(pages.collection_filtered, options)
|
|
261
279
|
cy.waitForHydration()
|
|
262
280
|
|
|
@@ -277,6 +295,12 @@ describe('Filtered Collection Page Seo', () => {
|
|
|
277
295
|
.should(($el) => {
|
|
278
296
|
expect($el.attr('content')).to.be.a('string')
|
|
279
297
|
})
|
|
298
|
+
|
|
299
|
+
cy.get('meta[name="twitter:card"]')
|
|
300
|
+
.should('exist')
|
|
301
|
+
.should(($el) => {
|
|
302
|
+
expect($el.attr('content')).to.eq('summary_large_image')
|
|
303
|
+
})
|
|
280
304
|
})
|
|
281
305
|
})
|
|
282
306
|
|
|
@@ -295,7 +319,7 @@ describe('Search Page Seo', () => {
|
|
|
295
319
|
cy.get('link[rel="canonical"]').should('not.exist')
|
|
296
320
|
})
|
|
297
321
|
|
|
298
|
-
it('has OpenGraph tags', () => {
|
|
322
|
+
it('has OpenGraph and Twitter tags', () => {
|
|
299
323
|
cy.visit(pages.search, options)
|
|
300
324
|
cy.waitForHydration()
|
|
301
325
|
|
|
@@ -316,5 +340,11 @@ describe('Search Page Seo', () => {
|
|
|
316
340
|
.should(($el) => {
|
|
317
341
|
expect($el.attr('content')).to.be.a('string')
|
|
318
342
|
})
|
|
343
|
+
|
|
344
|
+
cy.get('meta[name="twitter:card"]')
|
|
345
|
+
.should('exist')
|
|
346
|
+
.should(($el) => {
|
|
347
|
+
expect($el.attr('content')).to.eq('summary_large_image')
|
|
348
|
+
})
|
|
319
349
|
})
|
|
320
350
|
})
|
|
@@ -166,8 +166,7 @@ module.exports = {
|
|
|
166
166
|
analytics: {
|
|
167
167
|
// https://developers.google.com/tag-platform/tag-manager/web#standard_web_page_installation,
|
|
168
168
|
gtmContainerId: 'GTM-PGHZ95N',
|
|
169
|
-
serviceName: 'faststore
|
|
170
|
-
otelEnabled: true,
|
|
169
|
+
serviceName: 'faststore',
|
|
171
170
|
},
|
|
172
171
|
|
|
173
172
|
cms: {
|
package/next-seo.config.ts
CHANGED
|
@@ -8,6 +8,9 @@ const config: DefaultSeoProps = {
|
|
|
8
8
|
norobots: storeConfig.experimental.noRobots,
|
|
9
9
|
dangerouslySetAllPagesToNoFollow: storeConfig.experimental.nofollow,
|
|
10
10
|
dangerouslySetAllPagesToNoIndex: storeConfig.experimental.noindex,
|
|
11
|
+
twitter: {
|
|
12
|
+
cardType: 'summary_large_image',
|
|
13
|
+
},
|
|
11
14
|
additionalMetaTags: [
|
|
12
15
|
{
|
|
13
16
|
name: 'generated-at',
|
package/next.config.js
CHANGED
|
@@ -14,7 +14,6 @@ const getRootFolder = () => {
|
|
|
14
14
|
console.log(`
|
|
15
15
|
Root folder at: ${getRootFolder()}
|
|
16
16
|
AccountID: ${storeConfig.api?.storeId ?? 'Unknown'}
|
|
17
|
-
Analytics Enabled: ${storeConfig.analytics?.otelEnabled ?? false}
|
|
18
17
|
`)
|
|
19
18
|
|
|
20
19
|
/**
|
|
@@ -22,8 +21,6 @@ console.log(`
|
|
|
22
21
|
* */
|
|
23
22
|
const nextConfig = {
|
|
24
23
|
/* config options here */
|
|
25
|
-
/* Replaces terser by swc for minifying. It's the default in NextJS 13 */
|
|
26
|
-
swcMinify: true,
|
|
27
24
|
...(Array.isArray(storeConfig.experimental?.transpilePackages) &&
|
|
28
25
|
storeConfig.experimental.transpilePackages.length > 0 && {
|
|
29
26
|
transpilePackages: storeConfig.experimental.transpilePackages,
|
|
@@ -55,9 +52,7 @@ const nextConfig = {
|
|
|
55
52
|
sassOptions: {
|
|
56
53
|
silenceDeprecations: ['if-function', 'legacy-js-api'],
|
|
57
54
|
},
|
|
58
|
-
// TODO: We won't need to enable this experimental feature when migrating to Next.js 13
|
|
59
55
|
experimental: {
|
|
60
|
-
instrumentationHook: true,
|
|
61
56
|
scrollRestoration: !storeConfig.experimental.scrollRestoration,
|
|
62
57
|
},
|
|
63
58
|
/*
|
|
@@ -68,6 +63,27 @@ const nextConfig = {
|
|
|
68
63
|
* */
|
|
69
64
|
outputFileTracingRoot: getRootFolder(),
|
|
70
65
|
webpack: (config, { isServer, dev }) => {
|
|
66
|
+
// `@opentelemetry/sdk-node` (pulled in by @faststore/diagnostics) does an
|
|
67
|
+
// optional `require('@opentelemetry/shim-opencensus')` guarded by a try/catch.
|
|
68
|
+
// The module is an optional peer that isn't installed, so webpack reports a
|
|
69
|
+
// "Module not found" error it can't see is intentional. Aliasing it to `false`
|
|
70
|
+
// resolves it to an empty module, matching the graceful degradation the SDK
|
|
71
|
+
// already expects at runtime (Turbopack handles this case on its own).
|
|
72
|
+
config.resolve.alias = {
|
|
73
|
+
...config.resolve.alias,
|
|
74
|
+
'@opentelemetry/shim-opencensus': false,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// `require-in-the-middle` (used by OpenTelemetry instrumentation) patches
|
|
78
|
+
// modules through a dynamic `require` that webpack can't statically analyze,
|
|
79
|
+
// emitting a benign "Critical dependency" warning. `serverExternalPackages`
|
|
80
|
+
// handles this for Turbopack, but the webpack builder still traces into it,
|
|
81
|
+
// so we silence the warning for this module specifically.
|
|
82
|
+
config.ignoreWarnings = [
|
|
83
|
+
...(config.ignoreWarnings ?? []),
|
|
84
|
+
{ module: /require-in-the-middle/ },
|
|
85
|
+
]
|
|
86
|
+
|
|
71
87
|
// https://github.com/vercel/next.js/discussions/11267#discussioncomment-2479112
|
|
72
88
|
// camel-case style names from css modules
|
|
73
89
|
config.module.rules
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0-dev.1",
|
|
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/
|
|
75
|
-
"@faststore/ui": "4.
|
|
76
|
-
"@faststore/
|
|
77
|
-
"@faststore/
|
|
78
|
-
"@faststore/
|
|
74
|
+
"@faststore/api": "4.6.0-dev.1",
|
|
75
|
+
"@faststore/ui": "4.6.0-dev.1",
|
|
76
|
+
"@faststore/lighthouse": "4.6.0-dev.1",
|
|
77
|
+
"@faststore/diagnostics": "4.6.0-dev.1",
|
|
78
|
+
"@faststore/sdk": "4.6.0-dev.1"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@cypress/code-coverage": "^3.12.1",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"@types/fs-extra": "^9.0.13",
|
|
89
89
|
"@types/node": "20.19.13",
|
|
90
90
|
"@vitejs/plugin-react": "^5.1.2",
|
|
91
|
-
"@vitest/coverage-v8": "4.0.
|
|
91
|
+
"@vitest/coverage-v8": "4.0.18",
|
|
92
92
|
"@vtex/prettier-config": "1.0.0",
|
|
93
93
|
"axe-core": "^4.8.1",
|
|
94
94
|
"cypress": "12.17.4",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"is-ci": "^3.0.0",
|
|
100
100
|
"jsdom": "^27.4.0",
|
|
101
101
|
"typescript": "5.9.3",
|
|
102
|
-
"vitest": "4.0.
|
|
102
|
+
"vitest": "4.0.18"
|
|
103
103
|
},
|
|
104
104
|
"peerDependencies": {
|
|
105
105
|
"graphql": "16.11.0",
|
package/src/instrumentation.ts
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
import config from '../discovery.config'
|
|
2
2
|
import pkgJSON from '../package.json'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Next.js instrumentation hook. This is the only place telemetry is booted, so
|
|
6
|
+
* the OTel SDK is registered before any request is served.
|
|
7
|
+
*/
|
|
4
8
|
export async function register() {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
// Disabled feature until release date
|
|
10
|
+
const instrumentationEnabled = false
|
|
11
|
+
|
|
12
|
+
// The runtime check must wrap the import instead of guarding with an early
|
|
13
|
+
// return: bundlers replace `process.env.NEXT_RUNTIME` with a literal, so only
|
|
14
|
+
// a positive branch gets dropped from the edge bundle. Left reachable, the
|
|
15
|
+
// OTel SDK pulls in Node builtins (`fs`, `zlib`, `stream`) that fail to resolve.
|
|
16
|
+
if (process.env.NEXT_RUNTIME === 'nodejs' && instrumentationEnabled) {
|
|
9
17
|
const { name, version } = pkgJSON
|
|
18
|
+
|
|
10
19
|
try {
|
|
11
20
|
const { getTelemetryClient } = await import('@faststore/diagnostics')
|
|
12
|
-
console.log('Instrumemtation.ts: Getting telemetry client')
|
|
13
21
|
|
|
14
|
-
return getTelemetryClient({
|
|
22
|
+
return await getTelemetryClient({
|
|
15
23
|
serviceName: config.analytics?.serviceName ?? name,
|
|
16
24
|
version,
|
|
17
25
|
account: config.api.storeId,
|
|
@@ -19,7 +27,7 @@ export async function register() {
|
|
|
19
27
|
packageName: name,
|
|
20
28
|
})
|
|
21
29
|
} catch (error) {
|
|
22
|
-
console.error('Failed to initialize OTEL Instrumentation')
|
|
30
|
+
console.error('Failed to initialize OTEL Instrumentation', error)
|
|
23
31
|
}
|
|
24
32
|
}
|
|
25
33
|
}
|
package/src/pages/api/graphql.ts
CHANGED
|
@@ -13,6 +13,9 @@ import { getRequestHostname } from 'src/utils/getRequestHostname'
|
|
|
13
13
|
import { isLocalHost } from 'src/utils/isLocalHost'
|
|
14
14
|
import { shouldForceRefreshTokenForValidateSession } from 'src/utils/validateSessionRefreshToken'
|
|
15
15
|
import { execute } from '../../server'
|
|
16
|
+
import { logger } from '@faststore/diagnostics'
|
|
17
|
+
|
|
18
|
+
const OTELLogger = logger('@faststore/core')
|
|
16
19
|
|
|
17
20
|
const DEFAULT_MAX_AGE = 5 * 60 // 5 minutes
|
|
18
21
|
const DEFAULT_STALE_WHILE_REVALIDATE = 60 * 60 // 1 hour
|
|
@@ -150,6 +153,12 @@ const hasVtexIdclientAutCookie = (request: NextApiRequest): boolean => {
|
|
|
150
153
|
const handler: NextApiHandler = async (request, response) => {
|
|
151
154
|
if (request.method !== 'POST' && request.method !== 'GET') {
|
|
152
155
|
response.status(405).end()
|
|
156
|
+
OTELLogger(
|
|
157
|
+
'info',
|
|
158
|
+
'Invalid request method: %s %s',
|
|
159
|
+
request.method,
|
|
160
|
+
request.url
|
|
161
|
+
)
|
|
153
162
|
|
|
154
163
|
return
|
|
155
164
|
}
|
|
@@ -158,6 +167,15 @@ const handler: NextApiHandler = async (request, response) => {
|
|
|
158
167
|
// value is used to cache bust the request if there is a VtexIdclientAutCookie
|
|
159
168
|
const { operation, variables, query, v: value } = parseRequest(request)
|
|
160
169
|
|
|
170
|
+
// Variables and the query body are deliberately not logged: they carry
|
|
171
|
+
// session and customer data.
|
|
172
|
+
OTELLogger(
|
|
173
|
+
'debug',
|
|
174
|
+
'operation: %s hash: %s',
|
|
175
|
+
operation?.__meta__?.operationName,
|
|
176
|
+
operation?.__meta__?.operationHash
|
|
177
|
+
)
|
|
178
|
+
|
|
161
179
|
const isLocal = isLocalHost(getRequestHostname(request.headers.host))
|
|
162
180
|
|
|
163
181
|
if (
|
|
@@ -209,18 +227,21 @@ const handler: NextApiHandler = async (request, response) => {
|
|
|
209
227
|
// upstream status) is nested in `originalError`. Recover it so the BFF
|
|
210
228
|
// propagates the real status instead of collapsing everything to 500.
|
|
211
229
|
const fastStoreError = errors.map(recoverFastStoreError).find(Boolean)
|
|
230
|
+
const reportedErrors = errors.map((graphqlError) => {
|
|
231
|
+
const fsError = recoverFastStoreError(graphqlError)
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
message: (graphqlError as { message?: string })?.message,
|
|
235
|
+
status: fsError?.extensions.status,
|
|
236
|
+
type: fsError?.extensions.type,
|
|
237
|
+
}
|
|
238
|
+
})
|
|
212
239
|
|
|
213
|
-
console.error(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
return {
|
|
219
|
-
message: (graphqlError as { message?: string })?.message,
|
|
220
|
-
status: fsError?.extensions.status,
|
|
221
|
-
type: fsError?.extensions.type,
|
|
222
|
-
}
|
|
223
|
-
})
|
|
240
|
+
console.error('Graphql execution returned with error: ', reportedErrors)
|
|
241
|
+
OTELLogger(
|
|
242
|
+
'error',
|
|
243
|
+
'Graphql execution returned with error: %o',
|
|
244
|
+
reportedErrors
|
|
224
245
|
)
|
|
225
246
|
|
|
226
247
|
const status = fastStoreError?.extensions.status ?? 500
|
|
@@ -304,6 +325,11 @@ const handler: NextApiHandler = async (request, response) => {
|
|
|
304
325
|
'Something unexpected occurred querying Graphql endpoint: \n',
|
|
305
326
|
err
|
|
306
327
|
)
|
|
328
|
+
OTELLogger(
|
|
329
|
+
'error',
|
|
330
|
+
'Something unexpected occurred querying Graphql endpoint: %o',
|
|
331
|
+
err
|
|
332
|
+
)
|
|
307
333
|
|
|
308
334
|
if (err instanceof BadRequestError) {
|
|
309
335
|
response.status(400).end()
|
package/src/server/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
GraphqlVtexSchema,
|
|
17
17
|
isFastStoreError,
|
|
18
18
|
} from '@faststore/api'
|
|
19
|
+
import { OTELAPI } from '@faststore/diagnostics'
|
|
19
20
|
import { loadFilesSync } from '@graphql-tools/load-files'
|
|
20
21
|
import { mergeTypeDefs } from '@graphql-tools/merge'
|
|
21
22
|
import { makeExecutableSchema } from '@graphql-tools/schema'
|
|
@@ -28,7 +29,7 @@ import thirdPartyResolvers from '../customizations/src/graphql/thirdParty/resolv
|
|
|
28
29
|
import vtexExtensionsResolvers from '../customizations/src/graphql/vtex/resolvers'
|
|
29
30
|
|
|
30
31
|
import type { Operation } from '../sdk/graphql/request'
|
|
31
|
-
import { apiOptions
|
|
32
|
+
import { apiOptions } from './options'
|
|
32
33
|
|
|
33
34
|
interface ExecuteOptions<V = Record<string, unknown>> {
|
|
34
35
|
operation: Operation
|
|
@@ -70,8 +71,7 @@ export function getFinalAPISchema() {
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
export const getEnvelop = async () => {
|
|
73
|
-
const
|
|
74
|
-
const apiContextFactory = await GraphqlVtexContextFactory(options)
|
|
74
|
+
const apiContextFactory = await GraphqlVtexContextFactory(apiOptions)
|
|
75
75
|
|
|
76
76
|
return envelop({
|
|
77
77
|
plugins: [
|
|
@@ -136,13 +136,17 @@ export const execute = async <V extends Maybe<{ [key: string]: unknown }>, D>(
|
|
|
136
136
|
contextValue.storage.locale = locale
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
const { data, errors } =
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
139
|
+
const { data, errors } = await withRootSpan(
|
|
140
|
+
`graphql ${operationName ?? 'operation'}`,
|
|
141
|
+
() =>
|
|
142
|
+
run({
|
|
143
|
+
schema,
|
|
144
|
+
document: parse(query),
|
|
145
|
+
variableValues: variables,
|
|
146
|
+
contextValue,
|
|
147
|
+
operationName,
|
|
148
|
+
}) as Promise<{ data: D; errors: unknown[] }>
|
|
149
|
+
)
|
|
146
150
|
|
|
147
151
|
return {
|
|
148
152
|
data,
|
|
@@ -153,3 +157,27 @@ export const execute = async <V extends Maybe<{ [key: string]: unknown }>, D>(
|
|
|
153
157
|
},
|
|
154
158
|
}
|
|
155
159
|
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Runs an operation inside a per-request root span, made the active context so
|
|
163
|
+
* the resolver spans emitted by `@faststore/api` parent to it. Resolves to a
|
|
164
|
+
* plain call when telemetry is disabled.
|
|
165
|
+
*/
|
|
166
|
+
async function withRootSpan<T>(name: string, run: () => Promise<T>) {
|
|
167
|
+
if (!apiOptions.OTEL_ENABLED) {
|
|
168
|
+
return run()
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const span = OTELAPI.trace.getTracer('@faststore/core').startSpan(name)
|
|
172
|
+
const otelContext = OTELAPI.trace.setSpan(OTELAPI.context.active(), span)
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
return await OTELAPI.context.with(otelContext, run)
|
|
176
|
+
} catch (error) {
|
|
177
|
+
span.setStatus({ code: OTELAPI.SpanStatusCode.ERROR })
|
|
178
|
+
span.recordException(error as Error)
|
|
179
|
+
throw error
|
|
180
|
+
} finally {
|
|
181
|
+
span.end()
|
|
182
|
+
}
|
|
183
|
+
}
|
package/src/server/options.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { APIOptions } from '@faststore/api'
|
|
2
|
-
import { getTraceClient } from '@faststore/diagnostics'
|
|
3
2
|
import storeConfig from '../../discovery.config'
|
|
4
3
|
import pkgJSON from '../../package.json'
|
|
5
4
|
|
|
6
|
-
const {
|
|
5
|
+
const { version } = pkgJSON
|
|
7
6
|
|
|
8
7
|
export const apiOptions: APIOptions = {
|
|
9
8
|
platform: storeConfig.platform as APIOptions['platform'],
|
|
@@ -23,25 +22,7 @@ export const apiOptions: APIOptions = {
|
|
|
23
22
|
storeConfig.api?.enableUnavailableItemsOnCart ?? false,
|
|
24
23
|
},
|
|
25
24
|
version,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
25
|
+
// feature flag default to false as it should not emit traces/logs yet
|
|
26
|
+
OTEL_ENABLED: false,
|
|
29
27
|
discoveryConfig: storeConfig,
|
|
30
28
|
}
|
|
31
|
-
|
|
32
|
-
export async function withTraceClient<T extends APIOptions = typeof apiOptions>(
|
|
33
|
-
apiOptions: T
|
|
34
|
-
): Promise<T> {
|
|
35
|
-
const OTEL = {}
|
|
36
|
-
getTraceClient(
|
|
37
|
-
apiOptions?.discoveryConfig?.analytics?.serviceName ?? name
|
|
38
|
-
)?.inject(OTEL)
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
...apiOptions,
|
|
42
|
-
OTEL: {
|
|
43
|
-
...OTEL,
|
|
44
|
-
enabled: storeConfig.analytics?.otelEnabled?.toString() === 'true',
|
|
45
|
-
},
|
|
46
|
-
} as T
|
|
47
|
-
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { register } from '../src/instrumentation'
|
|
4
|
+
|
|
5
|
+
const getTelemetryClient = vi.hoisted(() => vi.fn())
|
|
6
|
+
|
|
7
|
+
vi.mock('@faststore/diagnostics', () => ({ getTelemetryClient }))
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
vi.clearAllMocks()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
vi.unstubAllEnvs()
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
describe('register', () => {
|
|
18
|
+
it.each(['nodejs', 'edge', undefined])(
|
|
19
|
+
'does not boot telemetry on the %s runtime while the feature is off',
|
|
20
|
+
async (runtime) => {
|
|
21
|
+
vi.stubEnv('NEXT_RUNTIME', runtime)
|
|
22
|
+
|
|
23
|
+
await expect(register()).resolves.toBeUndefined()
|
|
24
|
+
expect(getTelemetryClient).not.toHaveBeenCalled()
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
})
|
|
@@ -29,9 +29,13 @@ const createResponse = () => {
|
|
|
29
29
|
return res as unknown as NextApiResponse & typeof res
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const createRequest = (
|
|
32
|
+
const createRequest = (
|
|
33
|
+
operationName = 'ClientShippingSimulationQuery',
|
|
34
|
+
method = 'GET'
|
|
35
|
+
) =>
|
|
33
36
|
({
|
|
34
|
-
method
|
|
37
|
+
method,
|
|
38
|
+
url: '/api/graphql',
|
|
35
39
|
headers: { host: 'localhost:3000' },
|
|
36
40
|
query: {
|
|
37
41
|
operationName,
|
|
@@ -165,3 +169,37 @@ describe('/api/graphql error status propagation', () => {
|
|
|
165
169
|
expect(res.status).toHaveBeenCalledWith(404)
|
|
166
170
|
})
|
|
167
171
|
})
|
|
172
|
+
|
|
173
|
+
describe('/api/graphql request handling', () => {
|
|
174
|
+
beforeEach(() => {
|
|
175
|
+
vi.clearAllMocks()
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it.each(['PUT', 'DELETE', 'PATCH', 'OPTIONS'])(
|
|
179
|
+
'rejects %s with 405 without reaching the GraphQL layer',
|
|
180
|
+
async (method) => {
|
|
181
|
+
const res = createResponse()
|
|
182
|
+
await handler(createRequest(undefined, method), res)
|
|
183
|
+
|
|
184
|
+
expect(res.status).toHaveBeenCalledWith(405)
|
|
185
|
+
expect(mockedExecute).not.toHaveBeenCalled()
|
|
186
|
+
}
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
it.each([
|
|
190
|
+
['BadRequestError', () => new BadRequestError('malformed'), 400],
|
|
191
|
+
['UnauthorizedError', () => new UnauthorizedError('expired'), 401],
|
|
192
|
+
['an unexpected failure', () => new Error('socket hang up'), 500],
|
|
193
|
+
])(
|
|
194
|
+
'maps %s thrown by execute to its status',
|
|
195
|
+
async (_name, makeError, status) => {
|
|
196
|
+
mockedExecute.mockRejectedValue(makeError())
|
|
197
|
+
|
|
198
|
+
const res = createResponse()
|
|
199
|
+
await handler(createRequest(), res)
|
|
200
|
+
|
|
201
|
+
expect(res.status).toHaveBeenCalledWith(status)
|
|
202
|
+
expect(res.end).toHaveBeenCalled()
|
|
203
|
+
}
|
|
204
|
+
)
|
|
205
|
+
})
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { OTELAPI } from '@faststore/diagnostics'
|
|
2
|
+
import {
|
|
3
|
+
afterAll,
|
|
4
|
+
afterEach,
|
|
5
|
+
beforeEach,
|
|
6
|
+
describe,
|
|
7
|
+
expect,
|
|
8
|
+
it,
|
|
9
|
+
vi,
|
|
10
|
+
} from 'vitest'
|
|
11
|
+
|
|
12
|
+
import { execute } from '../../src/server'
|
|
13
|
+
import { apiOptions } from '../../src/server/options'
|
|
14
|
+
|
|
15
|
+
const span = {
|
|
16
|
+
end: vi.fn(),
|
|
17
|
+
setStatus: vi.fn(),
|
|
18
|
+
recordException: vi.fn(),
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const startSpan = vi.fn(() => span)
|
|
22
|
+
|
|
23
|
+
const otelEnabledByDefault = apiOptions.OTEL_ENABLED
|
|
24
|
+
|
|
25
|
+
// `__typename` resolves inside GraphQL itself, so these run the whole envelop
|
|
26
|
+
// pipeline without reaching the VTEX platform.
|
|
27
|
+
const runOperation = (query: string, operationName?: string) =>
|
|
28
|
+
execute({
|
|
29
|
+
operation: { __meta__: { operationName, operationHash: 'not-persisted' } },
|
|
30
|
+
variables: {},
|
|
31
|
+
query,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
vi.clearAllMocks()
|
|
36
|
+
vi.spyOn(OTELAPI.trace, 'getTracer').mockReturnValue({ startSpan } as never)
|
|
37
|
+
apiOptions.OTEL_ENABLED = true
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
afterEach(() => {
|
|
41
|
+
vi.restoreAllMocks()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
afterAll(() => {
|
|
45
|
+
apiOptions.OTEL_ENABLED = otelEnabledByDefault
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
describe('execute root span', () => {
|
|
49
|
+
it('wraps the operation in a span named after it', async () => {
|
|
50
|
+
const { data } = await runOperation(
|
|
51
|
+
'query RootSpanQuery { __typename }',
|
|
52
|
+
'RootSpanQuery'
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
expect(data).toEqual({ __typename: 'Query' })
|
|
56
|
+
expect(startSpan).toHaveBeenCalledWith('graphql RootSpanQuery')
|
|
57
|
+
expect(span.end).toHaveBeenCalledTimes(1)
|
|
58
|
+
expect(span.setStatus).not.toHaveBeenCalled()
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('names the span generically when the operation is anonymous', async () => {
|
|
62
|
+
await runOperation('{ __typename }')
|
|
63
|
+
|
|
64
|
+
expect(startSpan).toHaveBeenCalledWith('graphql operation')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('marks the span as failed and ends it when the operation throws', async () => {
|
|
68
|
+
await expect(
|
|
69
|
+
runOperation('this is not graphql', 'BrokenQuery')
|
|
70
|
+
).rejects.toThrow(/Syntax Error/)
|
|
71
|
+
|
|
72
|
+
expect(span.setStatus).toHaveBeenCalledWith({
|
|
73
|
+
code: OTELAPI.SpanStatusCode.ERROR,
|
|
74
|
+
})
|
|
75
|
+
expect(span.recordException).toHaveBeenCalledWith(expect.any(Error))
|
|
76
|
+
expect(span.end).toHaveBeenCalledTimes(1)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('skips instrumentation entirely when telemetry is disabled', async () => {
|
|
80
|
+
apiOptions.OTEL_ENABLED = false
|
|
81
|
+
|
|
82
|
+
const { data } = await runOperation(
|
|
83
|
+
'query RootSpanQuery { __typename }',
|
|
84
|
+
'RootSpanQuery'
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
expect(data).toEqual({ __typename: 'Query' })
|
|
88
|
+
expect(startSpan).not.toHaveBeenCalled()
|
|
89
|
+
})
|
|
90
|
+
})
|