underpost 2.8.871 → 2.8.872

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 (37) hide show
  1. package/.github/workflows/release.cd.yml +3 -1
  2. package/README.md +46 -36
  3. package/cli.md +86 -86
  4. package/conf.js +2 -1
  5. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  6. package/package.json +2 -3
  7. package/src/cli/repository.js +1 -0
  8. package/src/cli/run.js +1 -0
  9. package/src/client/components/core/Account.js +2 -1
  10. package/src/client/components/core/AgGrid.js +2 -2
  11. package/src/client/components/core/CalendarCore.js +3 -4
  12. package/src/client/components/core/CommonJs.js +1 -2
  13. package/src/client/components/core/Content.js +2 -1
  14. package/src/client/components/core/Css.js +2 -1
  15. package/src/client/components/core/CssCore.js +2 -1
  16. package/src/client/components/core/Docs.js +4 -4
  17. package/src/client/components/core/FileExplorer.js +3 -3
  18. package/src/client/components/core/JoyStick.js +2 -2
  19. package/src/client/components/core/LoadingAnimation.js +2 -2
  20. package/src/client/components/core/Logger.js +4 -1
  21. package/src/client/components/core/Modal.js +17 -27
  22. package/src/client/components/core/ObjectLayerEngineModal.js +2 -1
  23. package/src/client/components/core/Pagination.js +14 -0
  24. package/src/client/components/core/Panel.js +3 -11
  25. package/src/client/components/core/PanelForm.js +6 -15
  26. package/src/client/components/core/Recover.js +2 -2
  27. package/src/client/components/core/Router.js +178 -33
  28. package/src/client/components/core/Stream.js +1 -1
  29. package/src/client/components/core/VanillaJs.js +0 -83
  30. package/src/client/components/core/Worker.js +2 -2
  31. package/src/client/components/default/MenuDefault.js +4 -3
  32. package/src/client/components/default/RoutesDefault.js +3 -2
  33. package/src/client/services/core/core.service.js +1 -1
  34. package/src/client/ssr/head/DefaultScripts.js +1 -0
  35. package/src/index.js +1 -1
  36. package/src/server/runtime.js +7 -0
  37. package/src/server/ssl.js +1 -2
@@ -1,21 +1,131 @@
1
+ /**
2
+ * Vanilla JavaScript module for manipulating the DOM.
3
+ * @module src/client/components/core/Router.js
4
+ * @namespace PwaRouter
5
+ */
6
+
1
7
  import { titleFormatted } from './CommonJs.js';
2
8
  import { loggerFactory } from './Logger.js';
3
- import { getProxyPath, getQueryParams, htmls, s, setPath } from './VanillaJs.js';
9
+ import { htmls, s } from './VanillaJs.js';
4
10
  import { Modal } from './Modal.js';
5
11
  import { Worker } from './Worker.js';
6
12
 
7
- // Router
13
+ const logger = loggerFactory(import.meta, { trace: true });
8
14
 
15
+ /**
16
+ * @type {Object.<string, function>}
17
+ * @description Holds event listeners for router changes.
18
+ * @memberof PwaRouter
19
+ */
9
20
  const RouterEvents = {};
21
+
22
+ /**
23
+ * @type {string[]}
24
+ * @description Array of core UI component IDs that should not trigger modal close route changes.
25
+ * @memberof PwaRouter
26
+ */
27
+ const coreUI = ['modal-menu', 'main-body', 'main-body-top', 'bottom-bar', 'board-notification'];
28
+ /**
29
+ * @type {Object.<string, function>}
30
+ * @description Holds event listeners for route changes that should close a modal.
31
+ * @memberof PwaRouter
32
+ */
10
33
  const closeModalRouteChangeEvents = {};
11
34
 
12
- const logger = loggerFactory(import.meta);
35
+ /**
36
+ * Determines the base path for the application, often used for routing within a sub-directory.
37
+ * It checks the current URL's pathname and `window.Routes` to return the appropriate proxy path.
38
+ *
39
+ * @returns {string} The calculated proxy path. Returns `/<first-segment>/` if a segment exists,
40
+ * otherwise `/`. If `window.Routes` indicates the path is a root route, it returns `/`.
41
+ * @memberof PwaRouter
42
+ */
43
+ const getProxyPath = () => {
44
+ let path = location.pathname.split('/')[1] ? `/${location.pathname.split('/')[1]}/` : '/';
45
+ if (window.Routes && path !== '/' && path.slice(0, -1) in window.Routes()) path = '/';
46
+ return path;
47
+ };
48
+
49
+ /**
50
+ * Sets the browser's path using the History API. It sanitizes the path, handles query strings and hashes,
51
+ * and prevents pushing the same state twice.
52
+ * @param {string} [path='/'] - The new path to set. Can include query strings and hashes.
53
+ * @param {object} [options={ removeSearch: false, removeHash: false }] - Options for path manipulation.
54
+ * @param {boolean} [options.removeSearch=false] - If true, removes the search part of the URL.
55
+ * @param {boolean} [options.removeHash=false] - If true, removes the hash part of the URL. Defaults to `false`.
56
+ * @param {object} [stateStorage={}] - State object to associate with the history entry.
57
+ * @param {string} [title=''] - The title for the new history entry.
58
+ * @memberof PwaRouter
59
+ * @returns {void | undefined} Returns `undefined` if the new path is the same as the current path, otherwise `void` (result of `history.pushState`).
60
+ */
61
+ const setPath = (path = '/', options = { removeSearch: false, removeHash: false }, stateStorage = {}, title = '') => {
62
+ logger.warn(`Set path input`, `${path}`);
63
+ if (!path) path = '/';
64
+
65
+ let [inputPath, inputSearchHash] = `${path}`.split('?');
66
+ let [inputSearch, inputHash] = inputSearchHash ? inputSearchHash.split('#') : [];
67
+
68
+ let sanitizedPath = (inputPath[0] !== '/' ? `/${inputPath}` : inputPath)
69
+ .trim()
70
+ .replaceAll('//', '/')
71
+ .replaceAll(`\\`, '/');
72
+
73
+ if (sanitizedPath.length > 1 && sanitizedPath[sanitizedPath.length - 1] === '/')
74
+ sanitizedPath = sanitizedPath.slice(0, -1);
75
+
76
+ const newFullPath = `${sanitizedPath}${inputSearch && !options.removeSearch ? `?${inputSearch}` : ''}${
77
+ inputHash && !options.removeHash ? `#${inputHash}` : ''
78
+ }`;
79
+ const currentFullPath = `${window.location.pathname}${location.search}${location.hash}`;
80
+ logger.warn(`Set path output`, {
81
+ inputPath: inputPath,
82
+ inputSearch: inputSearch,
83
+ inputHash: inputHash,
84
+ sanitizedPath: sanitizedPath,
85
+ currentLocationSearch: location.search,
86
+ currentLocationHash: location.hash,
87
+ currentFullPath,
88
+ newFullPath,
89
+ });
90
+ if (currentFullPath === newFullPath) {
91
+ logger.warn('Prevent overwriting same path', { currentFullPath, newFullPath });
92
+ return;
93
+ }
94
+ return history.pushState.call(history, stateStorage, title, newFullPath);
95
+ };
96
+
97
+ /**
98
+ * Extracts query parameters from the current URL's search string and returns them as an object.
99
+ * @returns An object containing the query parameters from the current URL is being returned.
100
+ * @memberof PwaRouter
101
+ */
102
+ const getQueryParams = () => {
103
+ const params = new URLSearchParams(window.location.search);
104
+ let queries = {};
105
+ for (const param of params) {
106
+ queries[param[0]] = param[1];
107
+ }
108
+ return queries;
109
+ };
13
110
 
111
+ /**
112
+ * Sanitizes a route string for use in CSS classes or other identifiers.
113
+ * Defaults to 'home' for empty, '/', or '\' routes.
114
+ * @param {string} route - The route string to sanitize.
115
+ * @returns {string} The sanitized route string.
116
+ * @memberof PwaRouter
117
+ */
14
118
  const sanitizeRoute = (route) =>
15
119
  !route || route === '/' || route === `\\`
16
120
  ? 'home'
17
121
  : route.toLowerCase().replaceAll('/', '').replaceAll(`\\`, '').replaceAll(' ', '-');
18
122
 
123
+ /**
124
+ * Sets the document title and updates the active state of the main menu button corresponding to the route.
125
+ * The title is formatted and appended with the main application title from `Worker.title` if it's not already present.
126
+ * @param {string} route - The current route string.
127
+ * @memberof PwaRouter
128
+ */
19
129
  const setDocTitle = (route) => {
20
130
  const _route = sanitizeRoute(route);
21
131
  // logger.warn('setDocTitle', _route);
@@ -27,6 +137,14 @@ const setDocTitle = (route) => {
27
137
  }
28
138
  };
29
139
 
140
+ /**
141
+ * Main router function. It matches the current URL path against the provided routes configuration
142
+ * and renders the corresponding component. It also fires registered router events.
143
+ * @param {object} [options={ Routes: () => {}, e: new PopStateEvent() }] - The router options.
144
+ * @param {function} options.Routes - A function that returns the routes object.
145
+ * @param {PopStateEvent} options.e - The popstate event object.
146
+ * @memberof PwaRouter
147
+ */
30
148
  const Router = function (options = { Routes: () => {}, e: new PopStateEvent() }) {
31
149
  const { e, Routes } = options;
32
150
  const proxyPath = getProxyPath();
@@ -50,20 +168,43 @@ const Router = function (options = { Routes: () => {}, e: new PopStateEvent() })
50
168
  }
51
169
  };
52
170
 
171
+ /**
172
+ * Initializes the router and sets up the `onpopstate` event listener to handle browser
173
+ * back/forward navigation.
174
+ * @param {object} RouterInstance - The router instance configuration, including the `Routes` function.
175
+ * @memberof PwaRouter
176
+ */
53
177
  const LoadRouter = function (RouterInstance) {
54
178
  Router(RouterInstance);
55
179
  window.onpopstate = (e) => Router({ ...RouterInstance, e });
56
180
  };
57
181
 
58
- const setQueryPath = (options = { path: '', queryPath: '', replace: false }, queryKey = 'cid') => {
59
- const { queryPath, path, replace } = options;
182
+ /**
183
+ * Sets the URL path with a specific query parameter, commonly used for content IDs.
184
+ * This function constructs a new URI based on the proxy path, a given path, and an optional query parameter.
185
+ * @param {object} [options={ path: '', queryPath: '' }] - The path options.
186
+ * @param {string} [options.path=''] - The base path segment.
187
+ * @memberof PwaRouter
188
+ */
189
+ const setQueryPath = (options = { path: '', queryPath: '' }, queryKey = 'cid') => {
190
+ const { queryPath, path } = options;
60
191
  const newUri = `${getProxyPath()}${path === 'home' ? '' : `${path}/`}${
61
192
  typeof queryPath === 'string' && queryPath ? `?${queryKey}=${queryPath}` : ''
62
193
  }`;
63
194
  const currentUri = `${window.location.pathname}${location.search}`;
64
- if (currentUri !== newUri && currentUri !== `${newUri}/`) setPath(newUri, {}, '', { replace });
195
+ if (currentUri !== newUri && currentUri !== `${newUri}/`) setPath(newUri, {}, '');
65
196
  };
66
197
 
198
+ /**
199
+ * Registers a listener for route changes that specifically watches for a `queryKey` parameter
200
+ * on a matching `routeId`. The provided event callback is triggered with the query parameter's value.
201
+ * @param {object} options - The listener options.
202
+ * @param {string} options.id - A unique ID for the listener.
203
+ * @param {string} options.routeId - The route ID to listen for.
204
+ * @param {function(string): void} options.event - The callback function to execute with the query path value (or an empty string if not found).
205
+ * @param {string} [queryKey='cid'] - The query parameter key to look for.
206
+ * @memberof PwaRouter
207
+ */
67
208
  const listenQueryPathInstance = ({ id, routeId, event }, queryKey = 'cid') => {
68
209
  RouterEvents[id] = ({ path, pushPath, proxyPath, route }) => {
69
210
  if ((route === '' && routeId === 'home') || (route && routeId && route === routeId)) {
@@ -80,14 +221,21 @@ const listenQueryPathInstance = ({ id, routeId, event }, queryKey = 'cid') => {
80
221
  });
81
222
  };
82
223
 
83
- const triggerCloseModalRouteChangeEvents = (newPath) => {
84
- console.warn('[closeModalRouteChangeEvent]', newPath);
85
- for (const event of Object.keys(closeModalRouteChangeEvents)) closeModalRouteChangeEvents[event](newPath);
86
- };
87
-
224
+ /**
225
+ * Handles the logic for changing the route when a modal is closed. It determines the next URL
226
+ * based on the remaining open modals or falls back to a home URL.
227
+ * @param {object} [options={}] - Options for the modal close event.
228
+ * @param {string} options.closedId - The ID of the modal that was just closed.
229
+ * @memberof PwaRouter
230
+ */
88
231
  const closeModalRouteChangeEvent = (options = {}) => {
89
- const { closedId, homeCid } = options;
232
+ logger.warn('closeModalRouteChangeEvent', options);
233
+ const { closedId } = options;
90
234
  if (!closedId) return;
235
+ if (coreUI.find((id) => closedId.startsWith(id))) {
236
+ logger.warn('prevent core ui component close');
237
+ return;
238
+ }
91
239
 
92
240
  const remainingModals = Object.keys(Modal.Data).filter(
93
241
  (id) => id !== closedId && (Modal.Data[id]?.options?.route || Modal.Data[id]?.options?.query),
@@ -95,27 +243,20 @@ const closeModalRouteChangeEvent = (options = {}) => {
95
243
 
96
244
  const topModalId = remainingModals.reverse().find((id) => Modal.Data[id]);
97
245
 
98
- if (topModalId) {
99
- const topModal = Modal.Data[topModalId];
100
- const route = topModal.options.route;
101
- const query = topModal.query;
102
- const path = route ? `${getProxyPath()}${route}` : location.pathname;
103
- const newUrl = `${path}${query || ''}`;
104
-
105
- triggerCloseModalRouteChangeEvents(newUrl);
106
- setPath(newUrl, {}, '', { replace: true });
107
- setDocTitle(route || path);
108
- Modal.setTopModalCallback(topModalId);
109
- } else {
110
- const homeUrl = `${getProxyPath()}${homeCid ? `?cid=${homeCid}` : ''}`;
111
- triggerCloseModalRouteChangeEvents(homeUrl);
112
- setPath(homeUrl, {}, '', { replace: true });
113
- setDocTitle('home');
114
- }
246
+ for (const event of Object.keys(closeModalRouteChangeEvents)) closeModalRouteChangeEvents[event]();
247
+ if (topModalId) Modal.setTopModalCallback(topModalId);
248
+ setPath(`${getProxyPath()}${Modal.Data[topModalId]?.options?.route || 'home'}`);
115
249
  };
116
250
 
117
- const handleModalViewRoute = (options = {}) => {
118
- const { route, RouterInstance } = options;
251
+ /**
252
+ * Handles routing for modals that are meant to be displayed as a "view" (e.g., a full-page modal).
253
+ * It updates the URL to reflect the modal's route.
254
+ * @param {object} [options={ route: 'home' }] - The options for handling the modal view route.
255
+ * @param {string} options.route - The route associated with the modal view.
256
+ * @memberof PwaRouter
257
+ */
258
+ const handleModalViewRoute = (options = { route: 'home' }) => {
259
+ const { route } = options;
119
260
  if (!route) return;
120
261
 
121
262
  let path = window.location.pathname;
@@ -130,13 +271,17 @@ const handleModalViewRoute = (options = {}) => {
130
271
  };
131
272
 
132
273
  export {
274
+ RouterEvents,
275
+ closeModalRouteChangeEvents,
276
+ coreUI,
133
277
  Router,
134
278
  setDocTitle,
135
279
  LoadRouter,
136
- RouterEvents,
137
280
  setQueryPath,
138
281
  listenQueryPathInstance,
139
282
  closeModalRouteChangeEvent,
140
283
  handleModalViewRoute,
141
- closeModalRouteChangeEvents,
284
+ getQueryParams,
285
+ getProxyPath,
286
+ setPath,
142
287
  };
@@ -1,5 +1,5 @@
1
1
  import { loggerFactory } from './Logger.js';
2
- import { getProxyPath } from './VanillaJs.js';
2
+ import { getProxyPath } from './Router.js';
3
3
 
4
4
  // https://peerjs.com/docs/
5
5
 
@@ -132,71 +132,6 @@ const copyData = (data) =>
132
132
  */
133
133
  const pasteData = () => new Promise((resolve) => navigator.clipboard.readText().then((clipText) => resolve(clipText)));
134
134
 
135
- /**
136
- * The setPath function in JavaScript updates the browser's history with a new path, state, and title.
137
- * @param path - The `path` parameter is a string that represents the URL path where you want to
138
- * navigate or update in the browser history. It is the first parameter in the `setPath` function and
139
- * has a default value of `'/'`.
140
- * @param stateStorage - The `stateStorage` parameter in the `setPath` function is an object that
141
- * represents the state object associated with the new history entry. It is used to store data related
142
- * to the state of the application when navigating to a new path using `history.pushState()`. This data
143
- * can be accessed later
144
- * @param title - The `title` parameter in the `setPath` function is a string that represents the
145
- * title of the new history entry. It is used as the title of the new history entry in the browser's
146
- * history.
147
- * @param {object} [options={}] - Additional options.
148
- * @param {boolean} [options.replace=false] - If true, use `history.replaceState` instead of `history.pushState`.
149
- * @memberof VanillaJS
150
- */
151
- const setPath = (path = '/', stateStorage = {}, title = '', options = {}) => {
152
- if (!path) path = '/';
153
-
154
- const [inputPath, inputSearch] = `${path}`.split('?');
155
-
156
- let sanitizedPath = (inputPath[0] !== '/' ? `/${inputPath}` : inputPath)
157
- .trim()
158
- .replaceAll('//', '/')
159
- .replaceAll(`\\`, '/');
160
-
161
- if (sanitizedPath.length > 1 && sanitizedPath[sanitizedPath.length - 1] === '/')
162
- sanitizedPath = sanitizedPath.slice(0, -1);
163
-
164
- const newFullPath = `${sanitizedPath}${inputSearch ? `?${inputSearch}` : location.search}${location.hash ?? ''}`;
165
- const currentFullPath = `${window.location.pathname}${location.search}${location.hash}`;
166
-
167
- if (currentFullPath === newFullPath) {
168
- console.warn('Prevent overwriting same path', {
169
- newFullPath,
170
- currentFullPath,
171
- });
172
- return;
173
- }
174
- const historyMethod = options.replace ? history.replaceState : history.pushState;
175
- console.warn(`Set path (${options.replace ? 'replace' : 'push'})`, {
176
- inputPath: inputPath,
177
- inputSearch: inputSearch,
178
- sanitizedPath: sanitizedPath,
179
- currentLocationSearch: location.search,
180
- currentLocationHash: location.hash,
181
- });
182
- return historyMethod.call(history, stateStorage, title, newFullPath);
183
- };
184
-
185
- /**
186
- * The function `getQueryParams` extracts query parameters from the current URL and returns them as an
187
- * object.
188
- * @returns An object containing the query parameters from the current URL is being returned.
189
- * @memberof VanillaJS
190
- */
191
- const getQueryParams = () => {
192
- const params = new URLSearchParams(window.location.search);
193
- let queries = {};
194
- for (const param of params) {
195
- queries[param[0]] = param[1];
196
- }
197
- return queries;
198
- };
199
-
200
135
  /**
201
136
  * The `preHTML` function in JavaScript replaces special characters like &, <, and > with their
202
137
  * corresponding HTML entities.
@@ -374,21 +309,6 @@ const getBlobFromUint8ArrayFile = (data = [[]], mimetype = 'application/octet-st
374
309
  return new Blob([new Uint8Array(data)], { type: mimetype });
375
310
  };
376
311
 
377
- // Router
378
- /**
379
- * The function `getProxyPath` returns a proxy path based on the current location pathname.
380
- * @returns The `getProxyPath` function returns the path based on the current location. If the first
381
- * segment of the pathname is not empty, it returns `/<first-segment>/`, otherwise it returns `/`. If
382
- * the `window.Routes` object exists and the path is not `/` and the path without the trailing slash is
383
- * a key in the `window.Routes` object, it returns `/`.
384
- * @memberof VanillaJS
385
- */
386
- const getProxyPath = () => {
387
- let path = location.pathname.split('/')[1] ? `/${location.pathname.split('/')[1]}/` : '/';
388
- if (window.Routes && path !== '/' && path.slice(0, -1) in window.Routes()) path = '/';
389
- return path;
390
- };
391
-
392
312
  /**
393
313
  * The function `isNavigator` checks if the user agent string contains a specified name.
394
314
  * @param name - The `name` parameter is a string that represents the name of a browser or device to
@@ -477,8 +397,6 @@ export {
477
397
  sa,
478
398
  copyData,
479
399
  pasteData,
480
- setPath,
481
- getQueryParams,
482
400
  preHTML,
483
401
  disableOptionsClick,
484
402
  checkFullScreen,
@@ -487,7 +405,6 @@ export {
487
405
  getResponsiveData,
488
406
  isElement,
489
407
  downloadFile,
490
- getProxyPath,
491
408
  getRawContentFile,
492
409
  getBlobFromUint8ArrayFile,
493
410
  isNavigator,
@@ -5,8 +5,8 @@ import { LoadingAnimation } from './LoadingAnimation.js';
5
5
  import { loggerFactory } from './Logger.js';
6
6
  import { LoadRouter } from './Router.js';
7
7
  import { Translate } from './Translate.js';
8
- import { getProxyPath, htmls, s } from './VanillaJs.js';
9
-
8
+ import { s } from './VanillaJs.js';
9
+ import { getProxyPath } from './Router.js';
10
10
  const logger = loggerFactory(import.meta);
11
11
 
12
12
  const Worker = {
@@ -17,10 +17,11 @@ import { LogOut } from '../core/LogOut.js';
17
17
  import { buildBadgeToolTipMenuOption, Modal, renderMenuLabel, renderViewTitle } from '../core/Modal.js';
18
18
  import { SignUp } from '../core/SignUp.js';
19
19
  import { Translate } from '../core/Translate.js';
20
- import { getProxyPath, htmls, s } from '../core/VanillaJs.js';
20
+ import { htmls, s } from '../core/VanillaJs.js';
21
+ import { getProxyPath } from '../core/Router.js';
21
22
  import { ElementsDefault } from './ElementsDefault.js';
22
23
  import Sortable from 'sortablejs';
23
- import { RouterDefault } from './RoutesDefault.js';
24
+ import { RouterDefault, BannerAppTemplate } from './RoutesDefault.js';
24
25
  import { SettingsDefault } from './SettingsDefault.js';
25
26
  import { Badge } from '../core/Badge.js';
26
27
  import { Docs } from '../core/Docs.js';
@@ -35,7 +36,7 @@ const MenuDefault = {
35
36
  const id = getId(this.Data, 'menu-');
36
37
  this.Data[id] = {};
37
38
  const RouterInstance = RouterDefault();
38
- const { BannerAppTemplate } = RouterInstance;
39
+
39
40
  const { barConfig } = await Themes[Css.currentTheme]();
40
41
  const heightTopBar = 50;
41
42
  const heightBottomBar = 50;
@@ -1,6 +1,7 @@
1
1
  import { loggerFactory } from '../core/Logger.js';
2
2
  import { Modal } from '../core/Modal.js';
3
- import { getProxyPath, s } from '../core/VanillaJs.js';
3
+ import { s } from '../core/VanillaJs.js';
4
+ import { getProxyPath } from '../core/Router.js';
4
5
 
5
6
  const logger = loggerFactory(import.meta);
6
7
 
@@ -39,7 +40,7 @@ const RoutesDefault = () => {
39
40
  window.Routes = RoutesDefault;
40
41
 
41
42
  const RouterDefault = () => {
42
- return { Routes: RoutesDefault, BannerAppTemplate };
43
+ return { Routes: RoutesDefault };
43
44
  };
44
45
 
45
46
  export { RoutesDefault, RouterDefault, BannerAppTemplate };
@@ -1,6 +1,6 @@
1
1
  import { Auth } from '../../components/core/Auth.js';
2
2
  import { loggerFactory } from '../../components/core/Logger.js';
3
- import { getProxyPath } from '../../components/core/VanillaJs.js';
3
+ import { getProxyPath } from '../../components/core/Router.js';
4
4
 
5
5
  const logger = loggerFactory(import.meta);
6
6
 
@@ -1,3 +1,4 @@
1
1
  SrrComponent = ({ ssrPath }) => html`
2
2
  <script type="text/javascript" src="${ssrPath}dist/validator/validator.min.js"></script>
3
+ <script type="text/javascript" src="${ssrPath}dist/ag-grid-community/ag-grid-community.min.js"></script>
3
4
  `;
package/src/index.js CHANGED
@@ -35,7 +35,7 @@ class Underpost {
35
35
  * @type {String}
36
36
  * @memberof Underpost
37
37
  */
38
- static version = 'v2.8.871';
38
+ static version = 'v2.8.872';
39
39
  /**
40
40
  * Repository cli API
41
41
  * @static
@@ -404,6 +404,13 @@ const buildRuntime = async () => {
404
404
  const path404 = `${directory ? directory : `${getRootDirectory()}${rootHostPath}`}/404/index.html`;
405
405
  const page404 = fs.existsSync(path404) ? `${path === '/' ? '' : path}/404` : undefined;
406
406
  app.use(function (req, res, next) {
407
+ // if /<path>/home redirect to /<path>
408
+ const homeRedirectPath = `${path === '/' ? '' : path}/home`;
409
+ if (req.url.startsWith(homeRedirectPath)) {
410
+ const redirectUrl = req.url.replace('/home', '');
411
+ return res.redirect(redirectUrl.startsWith('/') ? redirectUrl : `/${redirectUrl}`);
412
+ }
413
+
407
414
  if (page404) return res.status(404).redirect(page404);
408
415
  else {
409
416
  res.set('Content-Type', 'text/html');
package/src/server/ssl.js CHANGED
@@ -50,8 +50,7 @@ const buildSSL = async (host) => {
50
50
 
51
51
  fs.writeFileSync(`./engine-private/ssl/${host}/_ca_bundle.crt`, ca, 'utf8');
52
52
  fs.writeFileSync(`./engine-private/ssl/${host}/_ca_full_bundle.crt`, caFull, 'utf8');
53
- // TODO: no repeat folderHost match
54
- // fs.removeSync(`${sslPath}/${folderHost}`);
53
+
55
54
  return true;
56
55
  }
57
56
  }