@salesforce/pwa-kit-react-sdk 4.0.0-extensibility-preview.3 → 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 (35) hide show
  1. package/CHANGELOG.md +22 -1
  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 +21 -4
  8. package/ssr/universal/components/redirect-with-status/index.js +2 -2
  9. package/ssr/universal/components/route-component/index.d.ts +1 -1
  10. package/ssr/universal/components/route-component/index.d.ts.map +1 -1
  11. package/ssr/universal/components/route-component/index.js +41 -39
  12. package/ssr/universal/components/route-component/index.test.js +4 -4
  13. package/ssr/universal/components/switch/index.d.ts.map +1 -1
  14. package/ssr/universal/components/switch/index.js +28 -11
  15. package/ssr/universal/components/with-legacy-get-props/index.js +2 -2
  16. package/ssr/universal/components/with-react-query/index.js +3 -3
  17. package/ssr/universal/components/with-react-query/index.test.js +108 -2
  18. package/ssr/universal/contexts/index.d.ts +18 -0
  19. package/ssr/universal/contexts/index.d.ts.map +1 -1
  20. package/ssr/universal/contexts/index.js +25 -1
  21. package/ssr/universal/contexts/index.test.js +26 -0
  22. package/ssr/universal/errors.d.ts +6 -10
  23. package/ssr/universal/errors.d.ts.map +1 -1
  24. package/ssr/universal/errors.js +0 -5
  25. package/ssr/universal/events.d.ts +1 -1
  26. package/ssr/universal/events.d.ts.map +1 -1
  27. package/ssr/universal/events.js +7 -6
  28. package/ssr/universal/events.test.js +4 -4
  29. package/ssr/universal/hooks/index.d.ts +1 -0
  30. package/ssr/universal/hooks/index.d.ts.map +1 -1
  31. package/ssr/universal/hooks/index.js +16 -2
  32. package/ssr/universal/utils.d.ts +1 -1
  33. package/ssr/universal/utils.d.ts.map +1 -1
  34. package/ssr/universal/utils.js +8 -7
  35. package/utils/performance.js +9 -9
package/CHANGELOG.md CHANGED
@@ -1,13 +1,34 @@
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
+
1
7
  ## v4.0.0-extensibility-preview.3 (Dec 13, 2024)
8
+
2
9
  ## v4.0.0-extensibility-preview.2 (Dec 09, 2024)
10
+
3
11
  ## v4.0.0-extensibility-preview.1 (Dec 09, 2024)
12
+
4
13
  ## v4.0.0-extensibility-preview.0 (Nov 28, 2024)
5
14
  - Integrate Application Extensions Project. (#2099)[https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2099]
6
15
  - Add new `getStaticAssetUrl` utility to access assets specifically in the `/static` folder. (#2040)[https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2040]
7
16
  - Update Application Extensions import in `react-rendering.js` and `main.js` (#2004)[https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2004]
8
17
  - Define interface of the app extension's config [#2010](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2010)
9
- ## v3.9.0-dev (Oct 29, 2024)
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)
10
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)
11
32
 
12
33
  ## v3.8.0 (Oct 28, 2024)
13
34
  - [Server Affinity] - Attach dwsid to SCAPI request headers [#2090](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2090)
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.3",
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.3",
42
- "@salesforce/pwa-kit-runtime": "4.0.0-extensibility-preview.3",
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.3",
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.3",
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": "904de01e826117febeea952e034478349e16ea4d"
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.
@@ -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)
@@ -15,8 +15,8 @@ const _excluded = ["status", "staticContext"];
15
15
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
16
16
  */
17
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 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; }
19
- 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; }
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
20
  /**
21
21
  * The `RedirectWithStatus` component is used to specify a different status code when redirecting via
22
22
  * the Redirect component.
@@ -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;
@@ -49,7 +49,7 @@ const withLegacyGetProps = Wrapped => {
49
49
  // to avoid blocking the execution of the getProps function to maximize performance
50
50
  // getTemplateName should be very fast, under 0.2ms
51
51
  c.getTemplateName().then(templateName => {
52
- res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.getProps}::${templateName}`, 'start');
52
+ res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.getProps}.${templateName}`, 'start');
53
53
  });
54
54
  return c.getProps ? c.getProps({
55
55
  req,
@@ -58,7 +58,7 @@ const withLegacyGetProps = Wrapped => {
58
58
  location
59
59
  }).then(result => {
60
60
  c.getTemplateName().then(templateName => {
61
- res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.getProps}::${templateName}`, 'end');
61
+ res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.getProps}.${templateName}`, 'end');
62
62
  });
63
63
  return result;
64
64
  }) : Promise.resolve({});
@@ -83,10 +83,10 @@ const withReactQuery = (Wrapped, options = {}) => {
83
83
  yield Promise.all(queries.map((q, i) => {
84
84
  var _q$meta, _q$meta2;
85
85
  // always include the index to avoid duplicate entries
86
- const displayName = (_q$meta = q.meta) !== null && _q$meta !== void 0 && _q$meta.displayName ? `${(_q$meta2 = q.meta) === null || _q$meta2 === void 0 ? void 0 : _q$meta2.displayName}:${i}` : `${i}`;
87
- res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}::${displayName}`, 'start');
86
+ const displayName = (_q$meta = q.meta) !== null && _q$meta !== void 0 && _q$meta.displayName ? `${(_q$meta2 = q.meta) === null || _q$meta2 === void 0 ? void 0 : _q$meta2.displayName}-${i}` : `${i}`;
87
+ res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}.${displayName}`, 'start');
88
88
  return q.fetch().then(result => {
89
- res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}::${displayName}`, 'end', {
89
+ res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}.${displayName}`, 'end', {
90
90
  detail: q.queryHash
91
91
  });
92
92
  return result;
@@ -4,14 +4,23 @@ var _index = require("./index");
4
4
  var _react = require("@testing-library/react");
5
5
  var _react2 = _interopRequireDefault(require("react"));
6
6
  var _loggerInstance = _interopRequireDefault(require("../../../../utils/logger-instance"));
7
+ var _performance = require("../../../../utils/performance");
7
8
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
8
- /*
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
+ 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; }
12
+ 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; }
13
+ 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; }
14
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
15
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /*
9
16
  * Copyright (c) 2022, Salesforce, Inc.
10
17
  * All rights reserved.
11
18
  * SPDX-License-Identifier: BSD-3-Clause
12
19
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
13
20
  */
14
-
21
+ jest.mock('@tanstack/react-query', () => _objectSpread(_objectSpread({}, jest.requireActual('@tanstack/react-query')), {}, {
22
+ dehydrate: jest.fn().mockReturnValue({})
23
+ }));
15
24
  jest.mock('../../../../utils/logger-instance', () => {
16
25
  return {
17
26
  error: jest.fn()
@@ -98,4 +107,101 @@ describe('withReactQuery', function () {
98
107
  getHOCsInUse: () => ['xyz']
99
108
  }).getHOCsInUse()).toHaveLength(2);
100
109
  });
110
+ test('Performance markers use hyphen as delimiter for displayName', /*#__PURE__*/_asyncToGenerator(function* () {
111
+ const mockPerformanceTimer = {
112
+ mark: jest.fn()
113
+ };
114
+ const mockQueryMeta = {
115
+ displayName: 'TestQuery'
116
+ };
117
+ const mockQueryCache = {
118
+ getAll: jest.fn().mockReturnValue([{
119
+ options: {
120
+ enabled: true
121
+ },
122
+ meta: mockQueryMeta,
123
+ queryHash: 'test-hash',
124
+ fetch: jest.fn().mockResolvedValue({})
125
+ }])
126
+ };
127
+ const mockQueryClient = {
128
+ getQueryCache: jest.fn().mockReturnValue(mockQueryCache)
129
+ };
130
+ const res = {
131
+ locals: {
132
+ __queryClient: mockQueryClient
133
+ },
134
+ __performanceTimer: mockPerformanceTimer
135
+ };
136
+ const Component = (0, _index.withReactQuery)({});
137
+ yield Component.doInitAppState({
138
+ res,
139
+ appJSX: /*#__PURE__*/_react2.default.createElement("div", null, "Test")
140
+ });
141
+ expect(mockPerformanceTimer.mark).toHaveBeenCalledWith(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}.TestQuery-0`, 'start');
142
+ expect(mockPerformanceTimer.mark).toHaveBeenCalledWith(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}.TestQuery-0`, 'end', expect.objectContaining({
143
+ detail: 'test-hash'
144
+ }));
145
+ }));
146
+ test('Performance markers use index as displayName when meta.displayName is not available', /*#__PURE__*/_asyncToGenerator(function* () {
147
+ const mockPerformanceTimer = {
148
+ mark: jest.fn()
149
+ };
150
+ const mockQueryCache = {
151
+ getAll: jest.fn().mockReturnValue([{
152
+ options: {
153
+ enabled: true
154
+ },
155
+ meta: {},
156
+ queryHash: 'test-hash',
157
+ fetch: jest.fn().mockResolvedValue({})
158
+ }])
159
+ };
160
+ const mockQueryClient = {
161
+ getQueryCache: jest.fn().mockReturnValue(mockQueryCache)
162
+ };
163
+ const res = {
164
+ locals: {
165
+ __queryClient: mockQueryClient
166
+ },
167
+ __performanceTimer: mockPerformanceTimer
168
+ };
169
+ const Component = (0, _index.withReactQuery)({});
170
+ yield Component.doInitAppState({
171
+ res,
172
+ appJSX: /*#__PURE__*/_react2.default.createElement("div", null, "Test")
173
+ });
174
+
175
+ // Verify the performance marker uses just the index when no displayName is available
176
+ expect(mockPerformanceTimer.mark).toHaveBeenCalledWith(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}.0`, 'start');
177
+ expect(mockPerformanceTimer.mark).toHaveBeenCalledWith(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}.0`, 'end', expect.objectContaining({
178
+ detail: 'test-hash'
179
+ }));
180
+ }));
181
+ test('Performance markers for reactQueryPrerender are set correctly', /*#__PURE__*/_asyncToGenerator(function* () {
182
+ const mockPerformanceTimer = {
183
+ mark: jest.fn()
184
+ };
185
+ const mockQueryCache = {
186
+ getAll: jest.fn().mockReturnValue([])
187
+ };
188
+ const mockQueryClient = {
189
+ getQueryCache: jest.fn().mockReturnValue(mockQueryCache)
190
+ };
191
+ const res = {
192
+ locals: {
193
+ __queryClient: mockQueryClient
194
+ },
195
+ __performanceTimer: mockPerformanceTimer
196
+ };
197
+ const Component = (0, _index.withReactQuery)({});
198
+ yield Component.doInitAppState({
199
+ res,
200
+ appJSX: /*#__PURE__*/_react2.default.createElement("div", null, "Test")
201
+ });
202
+
203
+ // Verify the performance markers for reactQueryPrerender are set correctly
204
+ expect(mockPerformanceTimer.mark).toHaveBeenCalledWith(_performance.PERFORMANCE_MARKS.reactQueryPrerender, 'start');
205
+ expect(mockPerformanceTimer.mark).toHaveBeenCalledWith(_performance.PERFORMANCE_MARKS.reactQueryPrerender, 'end');
206
+ }));
101
207
  });
@@ -21,6 +21,24 @@ export namespace CorrelationIdProvider {
21
21
  }
22
22
  }
23
23
  export const ServerContext: React.Context<any>;
24
+ export const RoutesContext: React.Context<any>;
25
+ /**
26
+ * This provider initializes the routes
27
+ * @param children
28
+ * @param routes - array of routes
29
+ */
30
+ export function RoutesProvider({ routes, children }: {
31
+ routes: any;
32
+ children: any;
33
+ }): import("react/jsx-runtime").JSX.Element;
34
+ export namespace RoutesProvider {
35
+ export namespace propTypes_1 {
36
+ export const routes: PropTypes.Validator<any[]>;
37
+ const children_1: PropTypes.Validator<NonNullable<PropTypes.ReactNodeLike>>;
38
+ export { children_1 as children };
39
+ }
40
+ export { propTypes_1 as propTypes };
41
+ }
24
42
  import React from "react";
25
43
  import PropTypes from "prop-types";
26
44
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ssr/universal/contexts/index.js"],"names":[],"mappings":"AAYA,sDAAkD;AAGlD;;;;;;;GAOG;AACH;;;;4CAiCC;;;;;;;;;AA3CD,+CAA2C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ssr/universal/contexts/index.js"],"names":[],"mappings":"AAYA,sDAAkD;AAGlD;;;;;;;GAOG;AACH;;;;4CAiCC;;;;;;;;;AA3CD,+CAA2C;AAoD3C,+CAA2C;AAE3C;;;;GAIG;AACH;;;4CAQC"}
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.ServerContext = exports.CorrelationIdProvider = exports.CorrelationIdContext = void 0;
6
+ exports.ServerContext = exports.RoutesProvider = exports.RoutesContext = exports.CorrelationIdProvider = exports.CorrelationIdContext = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
9
  var _reactRouterDom = require("react-router-dom");
@@ -69,4 +69,28 @@ CorrelationIdProvider.propTypes = {
69
69
  resetOnPageChange: _propTypes.default.bool,
70
70
  correlationId: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func]).isRequired,
71
71
  location: _propTypes.default.object
72
+ };
73
+ const RoutesContext = exports.RoutesContext = /*#__PURE__*/_react.default.createContext();
74
+
75
+ /**
76
+ * This provider initializes the routes
77
+ * @param children
78
+ * @param routes - array of routes
79
+ */
80
+ const RoutesProvider = ({
81
+ routes,
82
+ children
83
+ }) => {
84
+ const [_routes, setRoutes] = (0, _react.useState)(routes);
85
+ return /*#__PURE__*/_react.default.createElement(RoutesContext.Provider, {
86
+ value: {
87
+ routes: _routes,
88
+ setRoutes
89
+ }
90
+ }, children);
91
+ };
92
+ exports.RoutesProvider = RoutesProvider;
93
+ RoutesProvider.propTypes = {
94
+ routes: _propTypes.default.array.isRequired,
95
+ children: _propTypes.default.node.isRequired
72
96
  };
@@ -98,4 +98,30 @@ describe('CorrelationIdProvider', function () {
98
98
  // expecting the provider to have a different correlation id when a page navigation happens
99
99
  expect(firstRenderedId).not.toEqual(secondRenderedId);
100
100
  }));
101
+ });
102
+ describe('RoutesProvider', () => {
103
+ it('provides routes via context', () => {
104
+ const testRoutes = [{
105
+ path: '/home'
106
+ }, {
107
+ path: '/about'
108
+ }];
109
+ const TestComponent = () => {
110
+ const {
111
+ routes
112
+ } = (0, _hooks.useRoutes)();
113
+ return /*#__PURE__*/_react.default.createElement("div", null, routes.map(route => route.path).join(', '));
114
+ };
115
+ (0, _react2.render)(/*#__PURE__*/_react.default.createElement(_index.RoutesProvider, {
116
+ routes: testRoutes
117
+ }, /*#__PURE__*/_react.default.createElement(TestComponent, null)));
118
+ expect(_react2.screen.getByText('/home, /about')).toBeInTheDocument();
119
+ });
120
+ it('throws an error when useRoutes is used outside RoutesProvider', () => {
121
+ const TestComponent = () => {
122
+ (0, _hooks.useRoutes)();
123
+ return null;
124
+ };
125
+ expect(() => (0, _react2.render)(/*#__PURE__*/_react.default.createElement(TestComponent, null))).toThrow('useRoutes must be used within a RoutesProvider');
126
+ });
101
127
  });
@@ -1,13 +1,9 @@
1
- export class HTTPError extends Error {
2
- constructor(status: any, message: any);
3
- constructor: typeof HTTPError;
4
- __proto__: HTTPError;
5
- message: any;
6
- status: any;
1
+ export declare class HTTPError extends Error {
2
+ status: number;
3
+ constructor(status: number, message: string);
4
+ toString(): string;
7
5
  }
8
- export class HTTPNotFound extends HTTPError {
9
- constructor(message: any);
10
- constructor: typeof HTTPNotFound;
11
- __proto__: HTTPNotFound;
6
+ export declare class HTTPNotFound extends HTTPError {
7
+ constructor(message: string);
12
8
  }
13
9
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/ssr/universal/errors.js"],"names":[],"mappings":"AAOA;IACI,uCAMC;IAJG,8BAA4B;IAC5B,qBAAoC;IACpC,aAAsB;IACtB,YAAoB;CAM3B;AAED;IACI,0BAIC;IAFG,iCAA+B;IAC/B,wBAAuC;CAE9C"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/ssr/universal/errors.ts"],"names":[],"mappings":"AAOA,qBAAa,SAAU,SAAQ,KAAK;IAChC,MAAM,EAAE,MAAM,CAAA;gBAEF,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAK3C,QAAQ;CAGX;AAED,qBAAa,YAAa,SAAQ,SAAS;gBAC3B,OAAO,EAAE,MAAM;CAG9B"}
@@ -14,9 +14,6 @@ exports.HTTPNotFound = exports.HTTPError = void 0;
14
14
  class HTTPError extends Error {
15
15
  constructor(status, message) {
16
16
  super(message);
17
- this.constructor = HTTPError;
18
- this.__proto__ = HTTPError.prototype;
19
- this.message = message;
20
17
  this.status = status;
21
18
  }
22
19
  toString() {
@@ -27,8 +24,6 @@ exports.HTTPError = HTTPError;
27
24
  class HTTPNotFound extends HTTPError {
28
25
  constructor(message) {
29
26
  super(404, message);
30
- this.constructor = HTTPNotFound;
31
- this.__proto__ = HTTPNotFound.prototype;
32
27
  }
33
28
  }
34
29
  exports.HTTPNotFound = HTTPNotFound;
@@ -3,7 +3,7 @@ export namespace PAGEEVENTS {
3
3
  const ERROR: string;
4
4
  }
5
5
  export const pages: Pages;
6
- declare class Pages {
6
+ declare class Pages extends EventTarget {
7
7
  pageLoad(templateName: any, start: any, end: any): void;
8
8
  error(name: any, content: any): void;
9
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/ssr/universal/events.js"],"names":[],"mappings":";;;;AAiCA,0BAAgC;AApBhC;IACI,wDAOC;IACD,qCAMC;CACJ"}
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/ssr/universal/events.js"],"names":[],"mappings":";;;;AA6BA,0BAAgC;AAlBhC;IACI,wDAOC;IACD,qCAMC;CACJ"}
@@ -4,8 +4,6 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.pages = exports.PAGEEVENTS = void 0;
7
- var _eventEmitter = _interopRequireDefault(require("event-emitter"));
8
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
7
  /*
10
8
  * Copyright (c) 2021, salesforce.com, inc.
11
9
  * All rights reserved.
@@ -17,22 +15,25 @@ const PAGEEVENTS = exports.PAGEEVENTS = {
17
15
  PAGELOAD: 'PAGELOAD',
18
16
  ERROR: 'ERROR'
19
17
  };
20
- class Pages {
18
+ class Pages extends EventTarget {
21
19
  pageLoad(templateName, start, end) {
22
20
  const payload = {
23
21
  templateName,
24
22
  start,
25
23
  end
26
24
  };
27
- this.emit(PAGEEVENTS.PAGELOAD, payload);
25
+ this.dispatchEvent(new CustomEvent(PAGEEVENTS.PAGELOAD, {
26
+ detail: payload
27
+ }));
28
28
  }
29
29
  error(name, content) {
30
30
  const payload = {
31
31
  name,
32
32
  content
33
33
  };
34
- this.emit(PAGEEVENTS.ERROR, payload);
34
+ this.dispatchEvent(new CustomEvent(PAGEEVENTS.ERROR, {
35
+ detail: payload
36
+ }));
35
37
  }
36
38
  }
37
- (0, _eventEmitter.default)(Pages.prototype);
38
39
  const pages = exports.pages = new Pages();
@@ -12,8 +12,8 @@ describe('Page Events', () => {
12
12
  test('emit and receive a PAGELOAD Page Event', () => {
13
13
  expect.assertions(1);
14
14
  return new Promise(resolve => {
15
- _events.pages.on(_events.PAGEEVENTS.PAGELOAD, evt => {
16
- expect(JSON.stringify(evt)).toEqual(JSON.stringify({
15
+ _events.pages.addEventListener(_events.PAGEEVENTS.PAGELOAD, evt => {
16
+ expect(JSON.stringify(evt.detail)).toEqual(JSON.stringify({
17
17
  templateName: 'blah',
18
18
  start: 123,
19
19
  end: 456
@@ -26,8 +26,8 @@ describe('Page Events', () => {
26
26
  test('emit and receive a ERROR Page Event', () => {
27
27
  expect.assertions(1);
28
28
  return new Promise(resolve => {
29
- _events.pages.on(_events.PAGEEVENTS.ERROR, evt => {
30
- expect(JSON.stringify(evt)).toEqual(JSON.stringify({
29
+ _events.pages.addEventListener(_events.PAGEEVENTS.ERROR, evt => {
30
+ expect(JSON.stringify(evt.detail)).toEqual(JSON.stringify({
31
31
  name: 'blah',
32
32
  content: 'more blah'
33
33
  }));
@@ -3,6 +3,7 @@ export function useServerContext(): ServerContext;
3
3
  export function useOrigin({ fromXForwardedHeader }: {
4
4
  fromXForwardedHeader?: boolean | undefined;
5
5
  }): string;
6
+ export function useRoutes(): object;
6
7
  /**
7
8
  * Server context
8
9
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ssr/universal/hooks/index.js"],"names":[],"mappings":"AAgBO,oCAFM,MAAM,CAQlB;AAiBM,oCANM,aAAa,CAUzB;AAcM;;IAHM,MAAM,CAiBlB;;;;;;;;SA5Ca,MAAM;;;;SACN,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ssr/universal/hooks/index.js"],"names":[],"mappings":"AAgBO,oCAFM,MAAM,CAQlB;AAiBM,oCANM,aAAa,CAUzB;AAcM;;IAHM,MAAM,CAiBlB;AAOM,6BAFM,MAAM,CAQlB;;;;;;;;SAzDa,MAAM;;;;SACN,MAAM"}
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.useServerContext = exports.useOrigin = exports.useCorrelationId = void 0;
6
+ exports.useServerContext = exports.useRoutes = exports.useOrigin = exports.useCorrelationId = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _contexts = require("../contexts");
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); }
@@ -81,4 +81,18 @@ const useOrigin = ({
81
81
  }
82
82
  return APP_ORIGIN;
83
83
  };
84
- exports.useOrigin = useOrigin;
84
+
85
+ /**
86
+ * Use this hook to get the routes value of the closest RoutesProvider component.
87
+ *
88
+ * @returns {object} array of routes
89
+ */
90
+ exports.useOrigin = useOrigin;
91
+ const useRoutes = () => {
92
+ const context = (0, _react.useContext)(_contexts.RoutesContext);
93
+ if (!context) {
94
+ throw new Error('useRoutes must be used within a RoutesProvider');
95
+ }
96
+ return context;
97
+ };
98
+ exports.useRoutes = useRoutes;
@@ -18,7 +18,7 @@ export declare const getAssetUrl: (path: string) => string;
18
18
  * @function
19
19
  * @returns {string} The full URL to the static asset.
20
20
  */
21
- export declare const getStaticAssetUrl: (path: string, opts: GetAssetUrlOptions) => string;
21
+ export declare const getStaticAssetUrl: (path?: string, opts?: GetAssetUrlOptions) => string;
22
22
  /**
23
23
  * @typedef {Object} ProxyConfig
24
24
  * @property {String} protocol - http or https
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/ssr/universal/utils.ts"],"names":[],"mappings":"AAuBA,KAAK,kBAAkB,GAAG;IACtB,uBAAuB,CAAC,EAAE,MAAM,CAAA;CACnC,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,SAAU,MAAM,WAQvC,CAAA;AAID;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,SAAU,MAAM,QAAQ,kBAAkB,WAiBvE,CAAA;AAED;;;;;GAKG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,WAS3B,CAAA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/ssr/universal/utils.ts"],"names":[],"mappings":"AAuBA,KAAK,kBAAkB,GAAG;IACtB,uBAAuB,CAAC,EAAE,MAAM,CAAA;CACnC,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,SAAU,MAAM,WAQvC,CAAA;AAID;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,yBAAqB,kBAAkB,WAkBpE,CAAA;AAED;;;;;GAKG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,WAS3B,CAAA"}
@@ -20,7 +20,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
20
20
  */ /* eslint-disable @typescript-eslint/ban-ts-comment */ // @ts-ignore
21
21
  // @ts-ignore
22
22
  const onClient = typeof window !== 'undefined';
23
- const EXTENIONS_NAMESPACE = '__extensions';
23
+ const EXTENSIONS_NAMESPACE = '__extensions';
24
24
  const STATIC_FOLDER = 'static';
25
25
  /**
26
26
  * Get the URL that should be used to load an asset from the bundle.
@@ -38,7 +38,7 @@ const getAssetUrl = path => {
38
38
  };
39
39
 
40
40
  // TODO: Once we establish that we have a new @salesforce/pwa-kit-extensibility package, we can move this utility to
41
- // it as to not have direct references to extensibilty in the sdk. This will also reduce duplicate code.
41
+ // it as to not have direct references to extensibility in the sdk. This will also reduce duplicate code.
42
42
  /**
43
43
  * Get the URL that should be used to load a static asset from the bundle.
44
44
  *
@@ -49,21 +49,22 @@ const getAssetUrl = path => {
49
49
  * @returns {string} The full URL to the static asset.
50
50
  */
51
51
  exports.getAssetUrl = getAssetUrl;
52
- const getStaticAssetUrl = (path, opts) => {
52
+ const getStaticAssetUrl = (path = '', opts = {}) => {
53
53
  const {
54
54
  appExtensionPackageName = ''
55
55
  } = opts || {};
56
56
 
57
57
  /* istanbul ignore next */
58
- const publicPath = onClient ?
59
- // @ts-ignore
60
- `${window.Progressive.buildOrigin}` : `${_ssrNamespacePaths.bundleBasePath}/${process.env.BUNDLE_ID || 'development'}/`;
58
+ let publicPath = getAssetUrl('');
61
59
 
62
60
  // Ensure all defined path arguments start with `/`.
63
61
  if (path && !path.startsWith('/')) {
64
62
  path = `/${path}`;
65
63
  }
66
- return `${publicPath}/${STATIC_FOLDER}${appExtensionPackageName ? `/${EXTENIONS_NAMESPACE}/${appExtensionPackageName}` : ''}${path ? path : ''}`;
64
+ if (publicPath && !publicPath.endsWith('/')) {
65
+ publicPath = `${publicPath}/`;
66
+ }
67
+ return `${publicPath}${STATIC_FOLDER}${appExtensionPackageName ? `/${EXTENSIONS_NAMESPACE}/${appExtensionPackageName}` : ''}${path ? path : ''}`;
67
68
  };
68
69
 
69
70
  /**
@@ -14,14 +14,14 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
14
14
  */
15
15
 
16
16
  const PERFORMANCE_MARKS = exports.PERFORMANCE_MARKS = {
17
- total: 'ssr:total',
18
- renderToString: 'ssr:render-to-string',
19
- routeMatching: 'ssr:route-matching',
20
- loadComponent: 'ssr:load-component',
21
- fetchStrategies: 'ssr:fetch-strategies',
22
- reactQueryPrerender: 'ssr:fetch-strategies:react-query:pre-render',
23
- reactQueryUseQuery: 'ssr:fetch-strategies:react-query:use-query',
24
- getProps: 'ssr:fetch-strategies:get-prop'
17
+ total: 'ssr.total',
18
+ renderToString: 'ssr.render-to-string',
19
+ routeMatching: 'ssr.route-matching',
20
+ loadComponent: 'ssr.load-component',
21
+ fetchStrategies: 'ssr.fetch-strategies',
22
+ reactQueryPrerender: 'ssr.fetch-strategies.react-query.pre-render',
23
+ reactQueryUseQuery: 'ssr.fetch-strategies.react-query.use-query',
24
+ getProps: 'ssr.fetch-strategies.get-prop'
25
25
  };
26
26
 
27
27
  /**
@@ -60,7 +60,7 @@ class PerformanceTimer {
60
60
  */
61
61
  buildServerTimingHeader() {
62
62
  const header = this.metrics.map(metric => {
63
- return `${metric.name};dur=${metric.duration}`;
63
+ return `${metric.name};dur=${metric.duration.toFixed(2)}`;
64
64
  }).join(', ');
65
65
  return header;
66
66
  }