@salesforce/pwa-kit-react-sdk 4.0.0-extensibility-preview.2 → 4.0.0-extensibility-preview.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/package.json +10 -10
  3. package/ssr/browser/main.d.ts.map +1 -1
  4. package/ssr/browser/main.js +7 -3
  5. package/ssr/browser/main.test.js +8 -8
  6. package/ssr/server/react-rendering.d.ts.map +1 -1
  7. package/ssr/server/react-rendering.js +22 -5
  8. package/ssr/server/react-rendering.test.js +23 -0
  9. package/ssr/universal/components/redirect-with-status/index.d.ts +3 -0
  10. package/ssr/universal/components/redirect-with-status/index.d.ts.map +1 -0
  11. package/ssr/universal/components/redirect-with-status/index.js +46 -0
  12. package/ssr/universal/components/redirect-with-status/index.test.js +46 -0
  13. package/ssr/universal/components/route-component/index.d.ts +1 -1
  14. package/ssr/universal/components/route-component/index.d.ts.map +1 -1
  15. package/ssr/universal/components/route-component/index.js +41 -39
  16. package/ssr/universal/components/route-component/index.test.js +4 -4
  17. package/ssr/universal/components/switch/index.d.ts.map +1 -1
  18. package/ssr/universal/components/switch/index.js +28 -11
  19. package/ssr/universal/components/with-legacy-get-props/index.js +2 -2
  20. package/ssr/universal/components/with-react-query/index.js +3 -3
  21. package/ssr/universal/components/with-react-query/index.test.js +108 -2
  22. package/ssr/universal/contexts/index.d.ts +18 -0
  23. package/ssr/universal/contexts/index.d.ts.map +1 -1
  24. package/ssr/universal/contexts/index.js +25 -1
  25. package/ssr/universal/contexts/index.test.js +26 -0
  26. package/ssr/universal/errors.d.ts +6 -10
  27. package/ssr/universal/errors.d.ts.map +1 -1
  28. package/ssr/universal/errors.js +0 -5
  29. package/ssr/universal/events.d.ts +1 -1
  30. package/ssr/universal/events.d.ts.map +1 -1
  31. package/ssr/universal/events.js +7 -6
  32. package/ssr/universal/events.test.js +4 -4
  33. package/ssr/universal/hooks/index.d.ts +4 -0
  34. package/ssr/universal/hooks/index.d.ts.map +1 -1
  35. package/ssr/universal/hooks/index.js +49 -3
  36. package/ssr/universal/utils.d.ts +1 -1
  37. package/ssr/universal/utils.d.ts.map +1 -1
  38. package/ssr/universal/utils.js +8 -7
  39. package/utils/performance.js +11 -11
  40. package/utils/url.d.ts.map +1 -1
  41. package/utils/url.js +3 -1
package/CHANGELOG.md CHANGED
@@ -1,11 +1,39 @@
1
+ ## v4.0.0-extensibility-preview.4 (Feb 12, 2025)
2
+ - Replace `event-emitter` in favor of the native `EventTarget` [#2289](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2289)
3
+ - Call app extension's new methods `getRoutes` and `getRoutesAsync` [#2308](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2308)
4
+ - Call app extension's `beforeRouteMatch` method with updated parameters [#2308](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2308)
5
+ - Enhanced SSR rendering by serializing application extension async routes [#2300](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2300)
6
+
7
+ ## v4.0.0-extensibility-preview.3 (Dec 13, 2024)
8
+
1
9
  ## v4.0.0-extensibility-preview.2 (Dec 09, 2024)
10
+
2
11
  ## v4.0.0-extensibility-preview.1 (Dec 09, 2024)
12
+
3
13
  ## v4.0.0-extensibility-preview.0 (Nov 28, 2024)
4
14
  - Integrate Application Extensions Project. (#2099)[https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2099]
5
15
  - Add new `getStaticAssetUrl` utility to access assets specifically in the `/static` folder. (#2040)[https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2040]
6
16
  - Update Application Extensions import in `react-rendering.js` and `main.js` (#2004)[https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2004]
7
17
  - Define interface of the app extension's config [#2010](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2010)
8
18
 
19
+ ## v3.10.0 (Feb 18, 2025)
20
+ - Fix the performance logging util to use the correct delimiter for the server-timing header. [#2225](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2295)
21
+
22
+ ## v3.9.2 (Mar 07, 2025)
23
+ - Update PWA-Kit SDKs to v3.9.2 [#2304](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2304)
24
+
25
+ ## v3.9.1 (Mar 05, 2025)
26
+ - Update PWA-Kit SDKs to v3.9.1 [#2301](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2301)
27
+
28
+ ## v3.9.0 (Feb 18, 2025)
29
+ - Fix the performance logging util to not round duration. [#2199](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2199)
30
+ - Add RedirectWithStatus component, allowing finer grained control of rediriects and their status code [#2173](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2173)
31
+ - Support Node 22 [#2218](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2218)
32
+
33
+ ## v3.8.0 (Oct 28, 2024)
34
+ - [Server Affinity] - Attach dwsid to SCAPI request headers [#2090](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2090)
35
+ - Create useOrigin hook to return an app origin that takes x-forwarded-host header into consideration. [#2050](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2050)
36
+
9
37
  ## v3.7.0 (Aug 07, 2024)
10
38
  - Add `beforeHydrate` option to withReactQuery component [#1912](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1912)
11
39
  - Add server side rendering performance metrics via query parameter `__server_timing` or environment variable `SERVER_TIMING`, the metrics is available in the console logs and response header `server-timing`. [#1895](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1895)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/pwa-kit-react-sdk",
3
- "version": "4.0.0-extensibility-preview.2",
3
+ "version": "4.0.0-extensibility-preview.4",
4
4
  "description": "A library that supports the isomorphic React rendering pipeline for Commerce Cloud Managed Runtime apps",
5
5
  "types": "dist/index.d.ts",
6
6
  "homepage": "https://github.com/SalesforceCommerceCloud/pwa-kit/tree/develop/packages/pwa-kit-react-sdk#readme",
@@ -38,11 +38,9 @@
38
38
  "@loadable/babel-plugin": "^5.15.3",
39
39
  "@loadable/server": "^5.15.3",
40
40
  "@loadable/webpack-plugin": "^5.15.2",
41
- "@salesforce/pwa-kit-extension-sdk": "4.0.0-extensibility-preview.2",
42
- "@salesforce/pwa-kit-runtime": "4.0.0-extensibility-preview.2",
43
- "@tanstack/react-query": "^4.28.0",
41
+ "@salesforce/pwa-kit-extension-sdk": "4.0.0-extensibility-preview.4",
42
+ "@salesforce/pwa-kit-runtime": "4.0.0-extensibility-preview.4",
44
43
  "cross-env": "^5.2.1",
45
- "event-emitter": "^0.3.5",
46
44
  "hoist-non-react-statics": "^3.3.2",
47
45
  "prop-types": "^15.8.1",
48
46
  "react-ssr-prepass": "^1.5.0",
@@ -52,14 +50,15 @@
52
50
  },
53
51
  "devDependencies": {
54
52
  "@loadable/component": "^5.15.3",
55
- "@salesforce/pwa-kit-dev": "4.0.0-extensibility-preview.2",
53
+ "@salesforce/pwa-kit-dev": "4.0.0-extensibility-preview.4",
56
54
  "@testing-library/jest-dom": "^5.16.5",
57
55
  "@testing-library/react": "^14.0.0",
58
56
  "@testing-library/user-event": "^14.4.3",
59
57
  "@types/hoist-non-react-statics": "~3.3.5",
58
+ "@types/mocha": "^10.0.10",
60
59
  "@types/react": "~18.2.0",
61
60
  "@types/react-dom": "~18.2.1",
62
- "internal-lib-build": "4.0.0-extensibility-preview.2",
61
+ "internal-lib-build": "4.0.0-extensibility-preview.4",
63
62
  "node-html-parser": "^3.3.6",
64
63
  "nodemon": "^2.0.22",
65
64
  "react": "^18.2.0",
@@ -72,17 +71,18 @@
72
71
  },
73
72
  "peerDependencies": {
74
73
  "@loadable/component": "^5.15.3",
74
+ "@tanstack/react-query": "^4.28.0",
75
75
  "react": "^18.2.0",
76
76
  "react-dom": "^18.2.0",
77
77
  "react-helmet": "^6.1.0",
78
78
  "react-router-dom": "^5.3.4"
79
79
  },
80
80
  "engines": {
81
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
82
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
81
+ "node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
82
+ "npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
83
83
  },
84
84
  "publishConfig": {
85
85
  "directory": "dist"
86
86
  },
87
- "gitHead": "6b5da20f750f39d89c490cf77f1bf160c7e3d8f7"
87
+ "gitHead": "5ad3b1f0e598cfe0fbdec5b1212b4dabc0a8733c"
88
88
  }
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/ssr/browser/main.jsx"],"names":[],"mappings":"AA0BO,2EAoBN;AAEM;;;;;;;4CAmCN;;;;;;;;;;;AAWM,uCA6DN"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/ssr/browser/main.jsx"],"names":[],"mappings":"AA0BO,2EAoBN;AAEM;;;;;;;4CAmCN;;;;;;;;;;;AAWM,uCA8DN"}
@@ -58,7 +58,10 @@ const OuterApp = ({
58
58
  // Invoke the Application Extensions 'beforeRouteMatch' hook. This hook accepts ALL the routes for the current
59
59
  // application including all routes added from the configured extensions.
60
60
  extensions.forEach(applicationExtension => {
61
- routes = applicationExtension.beforeRouteMatch(routes);
61
+ routes = applicationExtension.beforeRouteMatch({
62
+ allRoutes: routes,
63
+ locals
64
+ });
62
65
  });
63
66
  return /*#__PURE__*/_react.default.createElement(_contexts.ServerContext.Provider, {
64
67
  value: {}
@@ -113,7 +116,7 @@ const start = exports.start = /*#__PURE__*/function () {
113
116
  // this to set up, eg. Redux stores.
114
117
  const locals = {};
115
118
 
116
- // AppConfig.restore *must* come before getRoutes()
119
+ // AppConfig.restore *must* come before getAllRoutes()
117
120
  AppConfig.restore(locals, window.__PRELOADED_STATE__.__STATE_MANAGEMENT_LIBRARY);
118
121
 
119
122
  // We need to tell the routeComponent HOC when the app is hydrating in order to
@@ -132,10 +135,11 @@ const start = exports.start = /*#__PURE__*/function () {
132
135
  applicationExtensions,
133
136
  locals
134
137
  });
138
+ const routes = yield (0, _routeComponent.getAllRoutes)(locals);
135
139
  const props = {
136
140
  error: window.__ERROR__,
137
141
  locals: locals,
138
- routes: (0, _routeComponent.getRoutes)(locals),
142
+ routes,
139
143
  extensions: applicationExtensions,
140
144
  WrappedApp
141
145
  };
@@ -9,16 +9,16 @@ var _uuidv = require("../../utils/uuidv4.client");
9
9
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
10
10
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
11
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
- /*
12
+ 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); }
13
+ 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); }); }; } /*
13
14
  * Copyright (c) 2022, salesforce.com, inc.
14
15
  * All rights reserved.
15
16
  * SPDX-License-Identifier: BSD-3-Clause
16
17
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
17
18
  */
18
-
19
19
  jest.mock('../../utils/uuidv4.client');
20
20
  describe('main', function () {
21
- test('OuterApp renders without error', () => {
21
+ test('OuterApp renders without error', /*#__PURE__*/_asyncToGenerator(function* () {
22
22
  _uuidv.uuidv4.mockReturnValueOnce('7f21aea5-6962-4162-8204-9da85c802022');
23
23
  const oldPreloadedState = window.__PRELOADED_STATE__;
24
24
  window.__PRELOADED_STATE__ = {
@@ -29,15 +29,15 @@ describe('main', function () {
29
29
  const props = {
30
30
  error: undefined,
31
31
  locals,
32
- routes: (0, _routeComponent.getRoutes)(locals),
32
+ routes: yield (0, _routeComponent.getAllRoutes)(locals),
33
33
  WrappedApp: (0, _routeComponent.routeComponent)(App, false, locals),
34
34
  extensions: []
35
35
  };
36
36
  (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_main.OuterApp, props));
37
37
  expect(_react2.screen.getByText('App')).toBeInTheDocument();
38
38
  window.__PRELOADED_STATE__ = oldPreloadedState;
39
- });
40
- test('OuterApp triggers the error page when there is an error', () => {
39
+ }));
40
+ test('OuterApp triggers the error page when there is an error', /*#__PURE__*/_asyncToGenerator(function* () {
41
41
  const oldWindowError = window.__ERROR__;
42
42
  window.__ERROR__ = new errors.HTTPNotFound('Not found');
43
43
  const App = () => /*#__PURE__*/_react.default.createElement("div", null, "App");
@@ -45,12 +45,12 @@ describe('main', function () {
45
45
  const props = {
46
46
  error: window.__ERROR__,
47
47
  locals,
48
- routes: (0, _routeComponent.getRoutes)(locals),
48
+ routes: yield (0, _routeComponent.getAllRoutes)(locals),
49
49
  WrappedApp: (0, _routeComponent.routeComponent)(App, false, locals),
50
50
  extensions: []
51
51
  };
52
52
  (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_main.OuterApp, props));
53
53
  expect(_react2.screen.getByText('Error Status: 404')).toBeInTheDocument();
54
54
  window.__ERROR__ = oldWindowError;
55
- });
55
+ }));
56
56
  });
@@ -1 +1 @@
1
- {"version":3,"file":"react-rendering.d.ts","sourceRoot":"","sources":["../../../src/ssr/server/react-rendering.js"],"names":[],"mappings":"AAyDA,+CAA4C;AAyBrC,+DA4BN;AAYM,oEA0IN;;AAiKD;;;oDAIK"}
1
+ {"version":3,"file":"react-rendering.d.ts","sourceRoot":"","sources":["../../../src/ssr/server/react-rendering.js"],"names":[],"mappings":"AAyDA,+CAA4C;AAyBrC,+DA4BN;AAYM,oEAsJN;;AAkKD;;;oDAIK"}
@@ -140,7 +140,7 @@ const render = exports.render = /*#__PURE__*/function () {
140
140
  applicationExtensions,
141
141
  locals: res.locals
142
142
  });
143
- let routes = (0, _routeComponent.getRoutes)(res.locals);
143
+ let routes = yield (0, _routeComponent.getAllRoutes)(res.locals);
144
144
  const [pathname] = req.originalUrl.split('?');
145
145
  const location = {
146
146
  pathname,
@@ -149,11 +149,25 @@ const render = exports.render = /*#__PURE__*/function () {
149
149
  })
150
150
  };
151
151
 
152
+ // Some application extensions need to be serialized because they have asynchronous state
153
+ const serializedExtensions = Object.fromEntries(applicationExtensions.flatMap(extension => {
154
+ if (typeof extension.getRoutesAsync !== 'function') return [];
155
+ const routes = extension.serializeAsyncRoutes();
156
+ // TODO W-18257236: Use a unique key for each extension like the extension ID from
157
+ // extension-meta.json
158
+ return [[extension.getName(), {
159
+ routes
160
+ }]];
161
+ }));
162
+
152
163
  // Step 1 - Find the match.
153
164
 
154
165
  // Call `beforeRouteMatch` application extension hook.
155
166
  applicationExtensions.forEach(applicationExtension => {
156
- routes = applicationExtension.beforeRouteMatch(routes);
167
+ routes = applicationExtension.beforeRouteMatch({
168
+ allRoutes: routes,
169
+ locals: res.locals
170
+ });
157
171
  });
158
172
  res.__performanceTimer.mark(_performance.PERFORMANCE_MARKS.routeMatching, 'start');
159
173
  let route;
@@ -225,7 +239,8 @@ const render = exports.render = /*#__PURE__*/function () {
225
239
  res,
226
240
  location,
227
241
  config,
228
- appJSX
242
+ appJSX,
243
+ serializedExtensions
229
244
  });
230
245
  } catch (e) {
231
246
  // This is an unrecoverable error.
@@ -252,7 +267,7 @@ const render = exports.render = /*#__PURE__*/function () {
252
267
  res.setHeader('Server-Timing', res.__performanceTimer.buildServerTimingHeader());
253
268
  }
254
269
  if (redirectUrl) {
255
- res.redirect(302, redirectUrl);
270
+ res.redirect(routerContext.status || 302, redirectUrl);
256
271
  } else {
257
272
  res.status(status).send(html);
258
273
  }
@@ -310,7 +325,8 @@ const renderApp = args => {
310
325
  appStateError,
311
326
  appJSX,
312
327
  appState,
313
- config
328
+ config,
329
+ serializedExtensions
314
330
  } = args;
315
331
  const extractor = new _server2.ChunkExtractor({
316
332
  statsFile: BUNDLES_PATH,
@@ -373,6 +389,7 @@ const renderApp = args => {
373
389
  __CONFIG__: config,
374
390
  __PRELOADED_STATE__: appState,
375
391
  __ERROR__: error,
392
+ __EXTENSIONS__: serializedExtensions,
376
393
  // `window.Progressive` has a long history at Mobify and some
377
394
  // client-side code depends on it. Maintain its name out of tradition.
378
395
  Progressive: getWindowProgressive(req, res)
@@ -58,6 +58,7 @@ jest.mock('../universal/routes', () => {
58
58
  const React = require('react');
59
59
  const PropTypes = require('prop-types');
60
60
  const errors = require('../universal/errors');
61
+ const RedirectWithStatus = require('../universal/components/redirect-with-status').default;
61
62
  const {
62
63
  Redirect
63
64
  } = require('react-router-dom');
@@ -175,6 +176,17 @@ jest.mock('../universal/routes', () => {
175
176
  });
176
177
  }
177
178
  }
179
+ class RedirectWithStatusPage extends React.Component {
180
+ static getProps() {
181
+ return Promise.resolve();
182
+ }
183
+ render() {
184
+ return /*#__PURE__*/React.createElement(RedirectWithStatus, {
185
+ to: "/elsewhere/",
186
+ status: 301
187
+ });
188
+ }
189
+ }
178
190
  class HelmetPage extends React.Component {
179
191
  static getProps() {
180
192
  return Promise.resolve();
@@ -289,6 +301,9 @@ jest.mock('../universal/routes', () => {
289
301
  }, {
290
302
  path: '/redirect/',
291
303
  component: RedirectPage
304
+ }, {
305
+ path: '/redirectWithStatus/',
306
+ component: RedirectWithStatusPage
292
307
  }, {
293
308
  path: '/init-sets-status/',
294
309
  component: InitSetsStatusPage
@@ -512,6 +527,14 @@ describe('The Node SSR Environment', () => {
512
527
  assertions: res => {
513
528
  expect(res.statusCode).toBe(302);
514
529
  }
530
+ }, {
531
+ description: `can redirect with HTTP 301 status`,
532
+ req: {
533
+ url: '/redirectWithStatus/'
534
+ },
535
+ assertions: res => {
536
+ expect(res.statusCode).toBe(301);
537
+ }
515
538
  }, {
516
539
  description: `500 on unknown errors in getProps`,
517
540
  req: {
@@ -0,0 +1,3 @@
1
+ declare const _default: any;
2
+ export default _default;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/ssr/universal/components/redirect-with-status/index.jsx"],"names":[],"mappings":""}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _reactRouterDom = require("react-router-dom");
9
+ var _propTypes = _interopRequireDefault(require("prop-types"));
10
+ const _excluded = ["status", "staticContext"];
11
+ /*
12
+ * Copyright (c) 2024, Salesforce, Inc.
13
+ * All rights reserved.
14
+ * SPDX-License-Identifier: BSD-3-Clause
15
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
16
+ */
17
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
18
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
19
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
20
+ /**
21
+ * The `RedirectWithStatus` component is used to specify a different status code when redirecting via
22
+ * the Redirect component.
23
+ * The default redirect behavior when this component is not used is to set a 302 status.
24
+ *
25
+ * @param {number} status - The HTTP status code. Defaults to 302 if not specified
26
+ * @param {object} staticContext - The router context
27
+ * @param {string} to - The redirect's target path
28
+ */
29
+ const RedirectWithStatus = _ref => {
30
+ let {
31
+ status = 302,
32
+ staticContext
33
+ } = _ref,
34
+ props = _objectWithoutProperties(_ref, _excluded);
35
+ // Handle server-side rendering
36
+ if (staticContext) {
37
+ staticContext.status = status;
38
+ }
39
+ return /*#__PURE__*/_react.default.createElement(_reactRouterDom.Redirect, props);
40
+ };
41
+ RedirectWithStatus.propTypes = {
42
+ status: _propTypes.default.number,
43
+ staticContext: _propTypes.default.object,
44
+ to: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object])
45
+ };
46
+ var _default = exports.default = (0, _reactRouterDom.withRouter)(RedirectWithStatus);
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+
3
+ var _react = _interopRequireDefault(require("react"));
4
+ var _react2 = require("@testing-library/react");
5
+ var _reactRouterDom = require("react-router-dom");
6
+ var _history = require("history");
7
+ var _index = _interopRequireDefault(require("./index"));
8
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
+ 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
+ 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); }); }; } /*
11
+ * Copyright (c) 2024, salesforce.com, inc.
12
+ * All rights reserved.
13
+ * SPDX-License-Identifier: BSD-3-Clause
14
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
15
+ */
16
+ describe('RedirectWithStatus', () => {
17
+ test('Redirects if no status or context is provided', () => {
18
+ const targetUrl = '/target';
19
+ const history = (0, _history.createMemoryHistory)();
20
+ history.push('/redirect');
21
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_reactRouterDom.Router, {
22
+ history: history
23
+ }, /*#__PURE__*/_react.default.createElement(_reactRouterDom.Route, {
24
+ path: "/redirect"
25
+ }, /*#__PURE__*/_react.default.createElement(_index.default, {
26
+ to: targetUrl
27
+ }))));
28
+ expect(history.location.pathname).toBe(targetUrl);
29
+ });
30
+ test('Redirect renders with correct status', /*#__PURE__*/_asyncToGenerator(function* () {
31
+ const context = {};
32
+ const status = 303;
33
+ const targetUrl = '/target';
34
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_reactRouterDom.StaticRouter, {
35
+ location: "/redirect",
36
+ context: context
37
+ }, /*#__PURE__*/_react.default.createElement(_reactRouterDom.Route, {
38
+ path: "/redirect"
39
+ }, /*#__PURE__*/_react.default.createElement(_index.default, {
40
+ status: status,
41
+ to: targetUrl
42
+ }))));
43
+ expect(context.status).toBe(status);
44
+ expect(context.url).toBe(targetUrl);
45
+ }));
46
+ });
@@ -2,5 +2,5 @@ export function routeComponent(Wrapped: any, isPage: any, locals: any): {
2
2
  (props: any): import("react/jsx-runtime").JSX.Element;
3
3
  displayName: string;
4
4
  };
5
- export function getRoutes(locals?: {}): any[];
5
+ export function getAllRoutes(locals?: {}): Promise<any[]>;
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/ssr/universal/components/route-component/index.js"],"names":[],"mappings":"AAyDO;;;EAkVN;AASM,8CAwBN"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/ssr/universal/components/route-component/index.js"],"names":[],"mappings":"AAyDO;;;EAkVN;AAWM,0DA0BN"}
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.routeComponent = exports.getRoutes = void 0;
6
+ exports.routeComponent = exports.getAllRoutes = void 0;
7
7
  var _propTypes = _interopRequireDefault(require("prop-types"));
8
8
  var _react = _interopRequireDefault(require("react"));
9
9
  var _reactRouterDom = require("react-router-dom");
@@ -11,14 +11,14 @@ var _hoistNonReactStatics = _interopRequireDefault(require("hoist-non-react-stat
11
11
  var _appErrorBoundary = require("../../components/app-error-boundary");
12
12
  var _throw2 = _interopRequireDefault(require("../../components/throw-404"));
13
13
  var _compatibility = require("../../compatibility");
14
- var _routes2 = _interopRequireDefault(require("../../routes"));
14
+ var _routes = _interopRequireDefault(require("../../routes"));
15
15
  var _events = require("../../events");
16
16
  var _withLegacyGetProps = require("../../components/with-legacy-get-props");
17
17
  var _refresh = _interopRequireDefault(require("../refresh"));
18
18
  const _excluded = ["component"];
19
19
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
20
- function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var s = Object.getOwnPropertySymbols(e); for (r = 0; r < s.length; r++) o = s[r], t.includes(o) || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
21
- function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
20
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
21
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
22
22
  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); }
23
23
  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); }); }; }
24
24
  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; }
@@ -381,43 +381,45 @@ const routeComponent = (Wrapped, isPage, locals) => {
381
381
  };
382
382
 
383
383
  /**
384
- * Wrap all the components found in the application's route config with the
385
- * route-component HOC so that they all support `getProps` methods server-side
386
- * and client-side in the same way.
384
+ * Get all of the routes, including those from the app itself, the app
385
+ * extensions, and the SDK's internal routes.
386
+ *
387
+ * Also, wrap each route's component with the route-component HOC so that
388
+ * they all support `getProps` methods server-side and client-side in the same way.
387
389
  *
388
390
  * @private
389
391
  */
390
392
  exports.routeComponent = routeComponent;
391
- const getRoutes = (locals = {}) => {
392
- let _routes = _routes2.default;
393
- const {
394
- applicationExtensions = []
395
- } = locals;
396
- if (typeof _routes2.default === 'function') {
397
- _routes = (0, _routes2.default)();
398
- }
399
-
400
- // Call the `extendRoutes` function for all the Application Extensions.
401
- applicationExtensions.forEach(applicationExtension => {
402
- _routes = applicationExtension.extendRoutes(_routes);
393
+ const getAllRoutes = exports.getAllRoutes = /*#__PURE__*/function () {
394
+ var _ref2 = _asyncToGenerator(function* (locals = {}) {
395
+ const {
396
+ applicationExtensions = []
397
+ } = locals;
398
+ const extensionRoutes = (yield Promise.all(applicationExtensions.map(extension => typeof extension.getRoutesAsync === 'function' ? extension.getRoutesAsync({
399
+ locals
400
+ }) : extension.getRoutes({
401
+ locals
402
+ })))).flat();
403
+ const allRoutes = [
404
+ // NOTE: this route needs to be above _routes, in case _routes has a fallback route of `path: '*'`
405
+ {
406
+ path: '/__pwa-kit/refresh',
407
+ component: _refresh.default
408
+ }, ...extensionRoutes, ...(typeof _routes.default === 'function' ? (0, _routes.default)() : _routes.default), {
409
+ path: '*',
410
+ component: _throw2.default
411
+ }];
412
+ return allRoutes.map(_ref3 => {
413
+ let {
414
+ component
415
+ } = _ref3,
416
+ rest = _objectWithoutProperties(_ref3, _excluded);
417
+ return _objectSpread({
418
+ component: component ? routeComponent(component, true, locals) : component
419
+ }, rest);
420
+ });
403
421
  });
404
- const allRoutes = [
405
- // NOTE: this route needs to be above _routes, in case _routes has a fallback route of `path: '*'`
406
- {
407
- path: '/__pwa-kit/refresh',
408
- component: _refresh.default
409
- }, ..._routes, {
410
- path: '*',
411
- component: _throw2.default
412
- }];
413
- return allRoutes.map(_ref2 => {
414
- let {
415
- component
416
- } = _ref2,
417
- rest = _objectWithoutProperties(_ref2, _excluded);
418
- return _objectSpread({
419
- component: component ? routeComponent(component, true, locals) : component
420
- }, rest);
421
- });
422
- };
423
- exports.getRoutes = getRoutes;
422
+ return function getAllRoutes() {
423
+ return _ref2.apply(this, arguments);
424
+ };
425
+ }();
@@ -253,9 +253,9 @@ describe('The routeComponent component', () => {
253
253
  });
254
254
  }));
255
255
  });
256
- describe('getRoutes', () => {
257
- test('wraps components with the routeComponent HOC', () => {
258
- const mappedRoutes = (0, _index.getRoutes)();
256
+ describe('getAllRoutes', () => {
257
+ test('wraps components with the routeComponent HOC', /*#__PURE__*/_asyncToGenerator(function* () {
258
+ const mappedRoutes = yield (0, _index.getAllRoutes)();
259
259
  expect(mappedRoutes).toHaveLength(3);
260
260
  const [first, second, third] = mappedRoutes;
261
261
  const expectedRefetchName = 'WithErrorHandling(withRouter(routeComponent(Refresh)))';
@@ -264,7 +264,7 @@ describe('getRoutes', () => {
264
264
  expect(second.component.displayName).toBe(expectedName);
265
265
  const expected404Name = 'WithErrorHandling(withRouter(routeComponent(Throw404)))';
266
266
  expect(third.component.displayName).toBe(expected404Name);
267
- });
267
+ }));
268
268
  });
269
269
 
270
270
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/ssr/universal/components/switch/index.jsx"],"names":[],"mappings":";AAYA;;;;;;;;GAQG;AACH,6EAwBC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/ssr/universal/components/switch/index.jsx"],"names":[],"mappings":";AAcA;;;;;;;;GAQG;AACH,6EAeC"}
@@ -9,6 +9,8 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
9
9
  var _reactRouterDom = require("react-router-dom");
10
10
  var _appErrorBoundary = _interopRequireDefault(require("../app-error-boundary"));
11
11
  var _reactUid = require("react-uid");
12
+ var _contexts = require("../../contexts");
13
+ var _hooks = require("../../hooks");
12
14
  const _excluded = ["component"];
13
15
  /*
14
16
  * Copyright (c) 2021, salesforce.com, inc.
@@ -18,8 +20,8 @@ const _excluded = ["component"];
18
20
  */
19
21
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
20
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); }
21
- function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var s = Object.getOwnPropertySymbols(e); for (r = 0; r < s.length; r++) o = s[r], t.includes(o) || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
22
- function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
23
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
24
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
23
25
  /**
24
26
  * The Switch component packages up the bits of rendering that are shared between
25
27
  * server and client-side. It's *mostly* a react-router Switch component, hence the
@@ -38,9 +40,28 @@ const Switch = props => {
38
40
  } = props;
39
41
  return /*#__PURE__*/_react.default.createElement(_reactUid.UIDReset, null, /*#__PURE__*/_react.default.createElement(_appErrorBoundary.default, {
40
42
  error: error
41
- }, !error && /*#__PURE__*/_react.default.createElement(App, {
43
+ }, !error && /*#__PURE__*/_react.default.createElement(_contexts.RoutesProvider, {
44
+ routes: routes
45
+ }, /*#__PURE__*/_react.default.createElement(App, {
42
46
  preloadedProps: appState.appProps
43
- }, /*#__PURE__*/_react.default.createElement(_reactRouterDom.Switch, null, routes.map((route, i) => {
47
+ }, /*#__PURE__*/_react.default.createElement(RoutesConsumer, {
48
+ appState: appState
49
+ })))));
50
+ };
51
+ Switch.propTypes = {
52
+ error: _propTypes.default.object,
53
+ appState: _propTypes.default.object,
54
+ routes: _propTypes.default.array,
55
+ App: _propTypes.default.func,
56
+ preloadedProps: _propTypes.default.object
57
+ };
58
+ const RoutesConsumer = ({
59
+ appState
60
+ }) => {
61
+ const {
62
+ routes
63
+ } = (0, _hooks.useRoutes)();
64
+ return /*#__PURE__*/_react.default.createElement(_reactRouterDom.Switch, null, routes.map((route, i) => {
44
65
  const {
45
66
  component: Component
46
67
  } = route,
@@ -50,13 +71,9 @@ const Switch = props => {
50
71
  }, routeProps), /*#__PURE__*/_react.default.createElement(_reactUid.UIDFork, null, /*#__PURE__*/_react.default.createElement(Component, {
51
72
  preloadedProps: appState.pageProps
52
73
  })));
53
- })))));
74
+ }));
54
75
  };
55
- Switch.propTypes = {
56
- error: _propTypes.default.object,
57
- appState: _propTypes.default.object,
58
- routes: _propTypes.default.array,
59
- App: _propTypes.default.func,
60
- preloadedProps: _propTypes.default.object
76
+ RoutesConsumer.propTypes = {
77
+ appState: _propTypes.default.object.isRequired
61
78
  };
62
79
  var _default = exports.default = Switch;