@salesforce/pwa-kit-react-sdk 3.17.0 → 3.17.1-preview.0

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/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## v3.17.1-preview.0 (Mar 13, 2026)
2
+ - Add base path prefix to support multiple MRT environments under 1 domain [#3614](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3614)
3
+
1
4
  ## v3.17.0 (Mar 12, 2026)
2
5
  - Update test setup for Jest 29 compatibility [#3663](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3663)
3
6
  - Add Node 24 support. Drop Node 16 support [#3652](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/3652)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/pwa-kit-react-sdk",
3
- "version": "3.17.0",
3
+ "version": "3.17.1-preview.0",
4
4
  "description": "A library that supports the isomorphic React rendering pipeline for Commerce Cloud Managed Runtime apps",
5
5
  "homepage": "https://github.com/SalesforceCommerceCloud/pwa-kit/tree/develop/packages/pwa-kit-react-sdk#readme",
6
6
  "bugs": {
@@ -43,7 +43,7 @@
43
43
  "@opentelemetry/resources": "^1.15.1",
44
44
  "@opentelemetry/sdk-trace-base": "^1.15.1",
45
45
  "@opentelemetry/sdk-trace-node": "^1.15.1",
46
- "@salesforce/pwa-kit-runtime": "3.17.0",
46
+ "@salesforce/pwa-kit-runtime": "3.17.1-preview.0",
47
47
  "@tanstack/react-query": "^4.28.0",
48
48
  "cross-env": "^5.2.1",
49
49
  "event-emitter": "^0.3.5",
@@ -57,11 +57,11 @@
57
57
  "devDependencies": {
58
58
  "@h4ad/serverless-adapter": "4.4.0",
59
59
  "@loadable/component": "^5.15.3",
60
- "@salesforce/pwa-kit-dev": "3.17.0",
60
+ "@salesforce/pwa-kit-dev": "3.17.1-preview.0",
61
61
  "@testing-library/jest-dom": "^5.16.5",
62
62
  "@testing-library/react": "^14.0.0",
63
63
  "@testing-library/user-event": "14.4.3",
64
- "internal-lib-build": "3.17.0",
64
+ "internal-lib-build": "3.17.1-preview.0",
65
65
  "node-html-parser": "^3.3.6",
66
66
  "nodemon": "^2.0.22",
67
67
  "react": "^18.2.0",
@@ -86,5 +86,5 @@
86
86
  "publishConfig": {
87
87
  "directory": "dist"
88
88
  },
89
- "gitHead": "6d0cfd2308b9f25d8badd722469074889bd3b891"
89
+ "gitHead": "beabe8a971b6170bddfe08ae3f5ca2f1bfe66aa7"
90
90
  }
@@ -16,6 +16,7 @@ var _component = require("@loadable/component");
16
16
  var _uuidv = require("../../utils/uuidv4.client");
17
17
  var _propTypes = _interopRequireDefault(require("prop-types"));
18
18
  var _loggerInstance = _interopRequireDefault(require("../../utils/logger-instance"));
19
+ var _utils = require("../universal/utils");
19
20
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
20
21
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
21
22
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } /*
@@ -49,10 +50,12 @@ const OuterApp = ({
49
50
  }) => {
50
51
  const AppConfig = (0, _compatibility.getAppConfig)();
51
52
  const isInitialPageRef = (0, _react.useRef)(true);
53
+ const routerBasename = (0, _utils.getRouterBasePath)() || undefined;
52
54
  return /*#__PURE__*/_react.default.createElement(_contexts.ServerContext.Provider, {
53
55
  value: {}
54
56
  }, /*#__PURE__*/_react.default.createElement(_reactRouterDom.BrowserRouter, {
55
- ref: onHydrate
57
+ ref: onHydrate,
58
+ basename: routerBasename
56
59
  }, /*#__PURE__*/_react.default.createElement(_contexts.CorrelationIdProvider, {
57
60
  correlationId: () => {
58
61
  // If we are hydrating an error page use the server correlation id.
@@ -282,6 +282,7 @@ const OuterApp = ({
282
282
  location
283
283
  }) => {
284
284
  const AppConfig = (0, _compatibility.getAppConfig)();
285
+ const routerBasename = (0, _utils.getRouterBasePath)() || undefined;
285
286
  return /*#__PURE__*/_react.default.createElement(_contexts.ServerContext.Provider, {
286
287
  value: {
287
288
  req,
@@ -289,7 +290,8 @@ const OuterApp = ({
289
290
  }
290
291
  }, /*#__PURE__*/_react.default.createElement(_reactRouterDom.StaticRouter, {
291
292
  location: location,
292
- context: routerContext
293
+ context: routerContext,
294
+ basename: routerBasename
293
295
  }, /*#__PURE__*/_react.default.createElement(_contexts.CorrelationIdProvider, {
294
296
  correlationId: res.locals.requestId,
295
297
  resetOnPageChange: false
@@ -383,6 +385,7 @@ const renderApp = args => {
383
385
  __CONFIG__: config,
384
386
  __PRELOADED_STATE__: appState,
385
387
  __ERROR__: error,
388
+ __MRT_ENV_BASE_PATH__: process.env.MRT_ENV_BASE_PATH || '',
386
389
  // `window.Progressive` has a long history at Mobify and some
387
390
  // client-side code depends on it. Maintain its name out of tradition.
388
391
  Progressive: getWindowProgressive(req, res)
@@ -8,6 +8,7 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactRouterDom = require("react-router-dom");
9
9
  var _reactQuery = require("@tanstack/react-query");
10
10
  var _loggerInstance = _interopRequireDefault(require("../../../../utils/logger-instance"));
11
+ var _utils = require("../../utils");
11
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
13
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
14
  function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
@@ -58,6 +59,12 @@ const Refresh = () => {
58
59
  });
59
60
  referrer = '/';
60
61
  }
62
+
63
+ // Remove the base path before navigating (React Router will add it back)
64
+ const basePath = (0, _utils.getRouterBasePath)();
65
+ if (basePath && (referrer.startsWith(basePath + '/') || referrer === basePath)) {
66
+ referrer = referrer.slice(basePath.length) || '/';
67
+ }
61
68
  history.replace(referrer);
62
69
  });
63
70
  return function refetchData() {
@@ -5,6 +5,7 @@ var _react = require("@testing-library/react");
5
5
  var _react2 = _interopRequireDefault(require("react"));
6
6
  var _reactRouterDom = require("react-router-dom");
7
7
  var _index = _interopRequireDefault(require("./index"));
8
+ var _utils = require("../../utils");
8
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
10
  function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
10
11
  function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } /*
@@ -34,6 +35,9 @@ jest.mock('@tanstack/react-query', () => {
34
35
  }))
35
36
  };
36
37
  });
38
+ jest.mock('../../utils', () => ({
39
+ getRouterBasePath: jest.fn(() => '')
40
+ }));
37
41
  test('renders a loading spinner initially', () => {
38
42
  (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_index.default, null));
39
43
  expect(_react.screen.getByTestId('loading-spinner')).toBeInTheDocument();
@@ -75,4 +79,43 @@ test('navigate to homepage if `referrer` search param cannot be found in the pag
75
79
  expect(console.warn).toHaveBeenCalled();
76
80
  expect((0, _reactRouterDom.useHistory)().replace).toHaveBeenCalledWith('/');
77
81
  });
82
+ }));
83
+ test('strips base path from referrer when basePath is set', /*#__PURE__*/_asyncToGenerator(function* () {
84
+ const basePath = '/my-base';
85
+ _utils.getRouterBasePath.mockReturnValue(basePath);
86
+ _reactRouterDom.useLocation.mockImplementationOnce(() => ({
87
+ search: `?referrer=${encodeURIComponent('/my-base/some-page')}`
88
+ }));
89
+ (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_index.default, null));
90
+ jest.runAllTimers();
91
+ yield (0, _react.waitFor)(() => {
92
+ expect((0, _reactRouterDom.useHistory)().replace).toHaveBeenCalledWith('/some-page');
93
+ });
94
+ _utils.getRouterBasePath.mockReturnValue('');
95
+ }));
96
+ test('strips base path from referrer when referrer equals basePath exactly', /*#__PURE__*/_asyncToGenerator(function* () {
97
+ const basePath = '/my-base';
98
+ _utils.getRouterBasePath.mockReturnValue(basePath);
99
+ _reactRouterDom.useLocation.mockImplementationOnce(() => ({
100
+ search: `?referrer=${encodeURIComponent('/my-base')}`
101
+ }));
102
+ (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_index.default, null));
103
+ jest.runAllTimers();
104
+ yield (0, _react.waitFor)(() => {
105
+ expect((0, _reactRouterDom.useHistory)().replace).toHaveBeenCalledWith('/');
106
+ });
107
+ _utils.getRouterBasePath.mockReturnValue('');
108
+ }));
109
+ test('does not strip base path when referrer does not start with basePath', /*#__PURE__*/_asyncToGenerator(function* () {
110
+ const basePath = '/my-base';
111
+ _utils.getRouterBasePath.mockReturnValue(basePath);
112
+ _reactRouterDom.useLocation.mockImplementationOnce(() => ({
113
+ search: `?referrer=${encodeURIComponent('/other-path/page')}`
114
+ }));
115
+ (0, _react.render)(/*#__PURE__*/_react2.default.createElement(_index.default, null));
116
+ jest.runAllTimers();
117
+ yield (0, _react.waitFor)(() => {
118
+ expect((0, _reactRouterDom.useHistory)().replace).toHaveBeenCalledWith('/other-path/page');
119
+ });
120
+ _utils.getRouterBasePath.mockReturnValue('');
78
121
  }));
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
 
3
3
  var utils = _interopRequireWildcard(require("./utils"));
4
+ var _ssrConfig = require("@salesforce/pwa-kit-runtime/utils/ssr-config");
5
+ var _ssrNamespacePaths = require("@salesforce/pwa-kit-runtime/utils/ssr-namespace-paths");
4
6
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
5
7
  /*
6
8
  * Copyright (c) 2021, salesforce.com, inc.
@@ -9,6 +11,12 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
9
11
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
10
12
  */
11
13
 
14
+ jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-config', () => ({
15
+ getConfig: jest.fn()
16
+ }));
17
+ jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-namespace-paths', () => ({
18
+ getEnvBasePath: jest.fn()
19
+ }));
12
20
  describe('getProxyConfigs (client-side)', () => {
13
21
  const configs = [{
14
22
  foo: 'bar'
@@ -26,6 +34,16 @@ describe('getProxyConfigs (client-side)', () => {
26
34
  test('should return proxy configs set on window.Progressive', () => {
27
35
  expect(utils.getProxyConfigs()).toEqual(configs);
28
36
  });
37
+ test('should return empty array when ssrOptions is missing', () => {
38
+ global.Progressive = {};
39
+ expect(utils.getProxyConfigs()).toEqual([]);
40
+ });
41
+ test('should return empty array when proxyConfigs is missing', () => {
42
+ global.Progressive = {
43
+ ssrOptions: {}
44
+ };
45
+ expect(utils.getProxyConfigs()).toEqual([]);
46
+ });
29
47
  });
30
48
  describe('getAssetUrl (client-side)', () => {
31
49
  beforeEach(() => {
@@ -42,4 +60,47 @@ describe('getAssetUrl (client-side)', () => {
42
60
  test('should return origin + path', () => {
43
61
  expect(utils.getAssetUrl('/path')).toBe('test.com/path');
44
62
  });
63
+ });
64
+ describe('getRouterBasePath (client-side)', () => {
65
+ beforeEach(() => {
66
+ jest.clearAllMocks();
67
+ });
68
+ test('should return base path when showBasePath is true', () => {
69
+ const mockBasePath = '/test-base';
70
+ _ssrNamespacePaths.getEnvBasePath.mockReturnValue(mockBasePath);
71
+ _ssrConfig.getConfig.mockReturnValue({
72
+ app: {
73
+ url: {
74
+ showBasePath: true
75
+ }
76
+ }
77
+ });
78
+ expect(utils.getRouterBasePath()).toBe(mockBasePath);
79
+ });
80
+ test('should return empty string when showBasePath is undefined', () => {
81
+ _ssrConfig.getConfig.mockReturnValue({
82
+ app: {
83
+ url: {}
84
+ }
85
+ });
86
+ expect(utils.getRouterBasePath()).toBe('');
87
+ });
88
+ test('should return empty string when showBasePath is false', () => {
89
+ _ssrConfig.getConfig.mockReturnValue({
90
+ app: {
91
+ url: {
92
+ showBasePath: false
93
+ }
94
+ }
95
+ });
96
+ expect(utils.getRouterBasePath()).toBe('');
97
+ });
98
+ test('should return empty string when app config is missing', () => {
99
+ _ssrConfig.getConfig.mockReturnValue({});
100
+ expect(utils.getRouterBasePath()).toBe('');
101
+ });
102
+ test('should return empty string when getConfig returns null', () => {
103
+ _ssrConfig.getConfig.mockReturnValue(null);
104
+ expect(utils.getRouterBasePath()).toBe('');
105
+ });
45
106
  });
@@ -3,9 +3,10 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.getProxyConfigs = exports.getAssetUrl = void 0;
6
+ exports.getRouterBasePath = exports.getProxyConfigs = exports.getAssetUrl = void 0;
7
7
  var _ssrShared = require("@salesforce/pwa-kit-runtime/utils/ssr-shared");
8
8
  var _ssrNamespacePaths = require("@salesforce/pwa-kit-runtime/utils/ssr-namespace-paths");
9
+ var _ssrConfig = require("@salesforce/pwa-kit-runtime/utils/ssr-config");
9
10
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
10
11
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
11
12
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
@@ -58,4 +59,24 @@ const getProxyConfigs = () => {
58
59
  // Clone to avoid accidental mutation of important configuration variables.
59
60
  return configs.map(config => _objectSpread({}, config));
60
61
  };
61
- exports.getProxyConfigs = getProxyConfigs;
62
+
63
+ /**
64
+ * Returns the base path (defined in config.ssrParameters.envBasePath)
65
+ * for React Router routes when showBasePath is enabled in the app config.
66
+ *
67
+ * This function should be used when working with a React Router route
68
+ * (The route is defined in routes.jsx).
69
+ *
70
+ * Use getEnvBasePath (pwa-kit-runtime) if you are working with an express route\
71
+ * (The route is defined in ssr.js).
72
+ *
73
+ * @returns {string} - The base path if showBasePath is true, otherwise an empty string
74
+ */
75
+ exports.getProxyConfigs = getProxyConfigs;
76
+ const getRouterBasePath = () => {
77
+ var _config$app, _config$app$url;
78
+ const config = (0, _ssrConfig.getConfig)();
79
+ const showBasePath = (config === null || config === void 0 ? void 0 : (_config$app = config.app) === null || _config$app === void 0 ? void 0 : (_config$app$url = _config$app.url) === null || _config$app$url === void 0 ? void 0 : _config$app$url.showBasePath) === true;
80
+ return showBasePath ? (0, _ssrNamespacePaths.getEnvBasePath)() : '';
81
+ };
82
+ exports.getRouterBasePath = getRouterBasePath;
@@ -2,6 +2,8 @@
2
2
 
3
3
  var utils = _interopRequireWildcard(require("./utils"));
4
4
  var _ssrShared = require("@salesforce/pwa-kit-runtime/utils/ssr-shared");
5
+ var _ssrConfig = require("@salesforce/pwa-kit-runtime/utils/ssr-config");
6
+ var _ssrNamespacePaths = require("@salesforce/pwa-kit-runtime/utils/ssr-namespace-paths");
5
7
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
6
8
  /**
7
9
  * @jest-environment node
@@ -16,8 +18,53 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
16
18
  // conflicts with the eslint header rule.
17
19
  /* eslint-disable header/header */
18
20
 
21
+ jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-config', () => ({
22
+ getConfig: jest.fn()
23
+ }));
24
+ jest.mock('@salesforce/pwa-kit-runtime/utils/ssr-namespace-paths', () => ({
25
+ getEnvBasePath: jest.fn()
26
+ }));
19
27
  describe('getProxyConfigs (server-side)', () => {
20
28
  test('should return the currently used proxy configs', () => {
21
29
  expect(utils.getProxyConfigs()).toEqual(_ssrShared.proxyConfigs);
22
30
  });
31
+ });
32
+ describe('getRouterBasePath (server-side)', () => {
33
+ beforeEach(() => {
34
+ jest.clearAllMocks();
35
+ });
36
+ test('should return base path when showBasePath is true', () => {
37
+ const mockBasePath = '/test-base';
38
+ _ssrNamespacePaths.getEnvBasePath.mockReturnValue(mockBasePath);
39
+ _ssrConfig.getConfig.mockReturnValue({
40
+ app: {
41
+ url: {
42
+ showBasePath: true
43
+ }
44
+ }
45
+ });
46
+ expect(utils.getRouterBasePath()).toBe(mockBasePath);
47
+ });
48
+ test('should return empty string when showBasePath is undefined', () => {
49
+ _ssrConfig.getConfig.mockReturnValue({
50
+ app: {
51
+ url: {}
52
+ }
53
+ });
54
+ expect(utils.getRouterBasePath()).toBe('');
55
+ });
56
+ test('should return empty string when showBasePath is false', () => {
57
+ _ssrConfig.getConfig.mockReturnValue({
58
+ app: {
59
+ url: {
60
+ showBasePath: false
61
+ }
62
+ }
63
+ });
64
+ expect(utils.getRouterBasePath()).toBe('');
65
+ });
66
+ test('should return empty string when app config is missing', () => {
67
+ _ssrConfig.getConfig.mockReturnValue({});
68
+ expect(utils.getRouterBasePath()).toBe('');
69
+ });
23
70
  });