underpost 2.8.883 → 2.8.885

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 (46) hide show
  1. package/README.md +4 -116
  2. package/bin/deploy.js +9 -10
  3. package/bin/file.js +4 -6
  4. package/cli.md +15 -11
  5. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  6. package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
  7. package/package.json +1 -1
  8. package/src/api/user/user.service.js +3 -10
  9. package/src/cli/cluster.js +21 -0
  10. package/src/cli/cron.js +8 -0
  11. package/src/cli/db.js +63 -1
  12. package/src/cli/deploy.js +156 -3
  13. package/src/cli/env.js +43 -0
  14. package/src/cli/fs.js +94 -0
  15. package/src/cli/image.js +8 -0
  16. package/src/cli/index.js +17 -4
  17. package/src/cli/monitor.js +0 -1
  18. package/src/cli/repository.js +95 -2
  19. package/src/client/components/core/Css.js +16 -0
  20. package/src/client/components/core/Docs.js +5 -13
  21. package/src/client/components/core/Modal.js +57 -39
  22. package/src/client/components/core/Router.js +6 -3
  23. package/src/client/components/core/Worker.js +205 -118
  24. package/src/client/components/default/MenuDefault.js +1 -0
  25. package/src/client.dev.js +6 -3
  26. package/src/db/DataBaseProvider.js +65 -12
  27. package/src/db/mariadb/MariaDB.js +39 -6
  28. package/src/db/mongo/MongooseDB.js +51 -133
  29. package/src/index.js +1 -1
  30. package/src/mailer/EmailRender.js +58 -9
  31. package/src/mailer/MailerProvider.js +98 -25
  32. package/src/runtime/express/Express.js +248 -0
  33. package/src/runtime/lampp/Lampp.js +27 -8
  34. package/src/server/auth.js +82 -43
  35. package/src/server/client-build-live.js +14 -5
  36. package/src/server/client-dev-server.js +21 -8
  37. package/src/server/conf.js +78 -25
  38. package/src/server/peer.js +2 -2
  39. package/src/server/runtime.js +49 -208
  40. package/src/server/start.js +39 -0
  41. package/src/ws/IoInterface.js +132 -39
  42. package/src/ws/IoServer.js +79 -31
  43. package/src/ws/core/core.ws.connection.js +50 -16
  44. package/src/ws/core/core.ws.emit.js +47 -8
  45. package/src/ws/core/core.ws.server.js +62 -10
  46. package/src/runtime/nginx/Nginx.js +0 -3
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Repository module for managing Git operations and configurations.
3
+ * @module src/cli/repository.js
4
+ * @namespace UnderpostRepository
5
+ */
6
+
1
7
  import { commitData } from '../client/components/core/CommonJs.js';
2
8
  import dotenv from 'dotenv';
3
9
  import { pbcopy, shellCd, shellExec } from '../server/process.js';
@@ -11,8 +17,23 @@ dotenv.config();
11
17
 
12
18
  const logger = loggerFactory(import.meta);
13
19
 
20
+ /**
21
+ * @class UnderpostRepository
22
+ * @description Manages Git operations and configurations.
23
+ * This class provides a set of static methods to automate various
24
+ * Git operations, including cloning, pulling, and committing changes.
25
+ * @memberof UnderpostRepository
26
+ */
14
27
  class UnderpostRepository {
15
28
  static API = {
29
+ /**
30
+ * Clones a Git repository from GitHub.
31
+ * @param {string} [gitUri=`${process.env.GITHUB_USERNAME}/pwa-microservices-template`] - The URI of the GitHub repository (e.g., "username/repository").
32
+ * @param {object} [options={ bare: false, g8: false }] - Cloning options.
33
+ * @param {boolean} [options.bare=false] - If true, performs a bare clone.
34
+ * @param {boolean} [options.g8=false] - If true, uses the .g8 extension.
35
+ * @memberof UnderpostRepository
36
+ */
16
37
  clone(gitUri = `${process.env.GITHUB_USERNAME}/pwa-microservices-template`, options = { bare: false, g8: false }) {
17
38
  const gExtension = options.g8 === true ? '.g8' : '.git';
18
39
  const repoName = gitUri.split('/').pop();
@@ -26,6 +47,14 @@ class UnderpostRepository {
26
47
  },
27
48
  );
28
49
  },
50
+ /**
51
+ * Pulls updates from a GitHub repository.
52
+ * @param {string} [repoPath='./'] - The local path to the repository.
53
+ * @param {string} [gitUri=`${process.env.GITHUB_USERNAME}/pwa-microservices-template`] - The URI of the GitHub repository.
54
+ * @param {object} [options={ g8: false }] - Pulling options.
55
+ * @param {boolean} [options.g8=false] - If true, uses the .g8 extension.
56
+ * @memberof UnderpostRepository
57
+ */
29
58
  pull(
30
59
  repoPath = './',
31
60
  gitUri = `${process.env.GITHUB_USERNAME}/pwa-microservices-template`,
@@ -41,6 +70,18 @@ class UnderpostRepository {
41
70
  },
42
71
  );
43
72
  },
73
+ /**
74
+ * Creates a Git commit with a conventional commit message.
75
+ * @param {string} [repoPath='./'] - The local path to the repository.
76
+ * @param {string} [commitType='feat'] - The type of commit (e.g., 'feat', 'fix', 'docs', 'reset').
77
+ * @param {string} [subModule=''] - The submodule or scope of the commit.
78
+ * @param {string} [message=''] - The commit message.
79
+ * @param {object} [options={ copy: false, info: false, empty: false }] - Commit options.
80
+ * @param {boolean} [options.copy=false] - If true, copies the commit message to the clipboard.
81
+ * @param {boolean} [options.info=false] - If true, displays information about commit types.
82
+ * @param {boolean} [options.empty=false] - If true, allows an empty commit.
83
+ * @memberof UnderpostRepository
84
+ */
44
85
  commit(
45
86
  repoPath = './',
46
87
  commitType = 'feat',
@@ -65,9 +106,18 @@ class UnderpostRepository {
65
106
  shellExec(`cd ${repoPath} && git commit ${options?.empty ? `--allow-empty ` : ''}-m "${_message}"`);
66
107
  },
67
108
 
109
+ /**
110
+ * Pushes commits to a remote GitHub repository.
111
+ * @param {string} [repoPath='./'] - The local path to the repository.
112
+ * @param {string} [gitUri=`${process.env.GITHUB_USERNAME}/pwa-microservices-template`] - The URI of the GitHub repository.
113
+ * @param {object} [options={ f: false, g8: false }] - Push options.
114
+ * @param {boolean} [options.f=false] - If true, forces the push.
115
+ * @param {boolean} [options.g8=false] - If true, uses the .g8 extension.
116
+ * @memberof UnderpostRepository
117
+ */
68
118
  push(
69
119
  repoPath = './',
70
- gitUri = `${process.env.GITHUB_USERNAME}/pwa-microservices-template}`,
120
+ gitUri = `${process.env.GITHUB_USERNAME}/pwa-microservices-template`,
71
121
  options = { f: false, g8: false },
72
122
  ) {
73
123
  const gExtension = options.g8 === true || options.G8 === true ? '.g8' : '.git';
@@ -90,11 +140,34 @@ class UnderpostRepository {
90
140
  );
91
141
  },
92
142
 
93
- new(repositoryName, options = { dev: false, deployId: false, cluster: false }) {
143
+ /**
144
+ * Creates a new Underpost project, service, or configuration.
145
+ * @param {string} repositoryName - The name of the new project or service, or a deployId.
146
+ * @param {object} [options={ dev: false, deployId: false, cluster: false, subConf: '' }] - Creation options.
147
+ * @param {boolean} [options.dev=false] - If true, sets up a development project.
148
+ * @param {boolean} [options.deployId=false] - If true, creates deploy ID configuration files.
149
+ * @param {boolean} [options.cluster=false] - If true, creates cluster configuration files.
150
+ * @param {string} [options.subConf=''] - If provided, creates a sub-configuration for a deployId.
151
+ * @returns {Promise<void>} A promise that resolves when the operation is complete.
152
+ * @memberof UnderpostRepository
153
+ */
154
+ new(repositoryName, options = { dev: false, deployId: false, cluster: false, subConf: '' }) {
94
155
  return new Promise(async (resolve, reject) => {
95
156
  try {
96
157
  await logger.setUpInfo();
97
158
  actionInitLog();
159
+ if (options.subConf && typeof options.subConf === 'string') {
160
+ const deployId = repositoryName;
161
+ logger.info('Creating sub conf', {
162
+ deployId,
163
+ subConf: options.subConf,
164
+ });
165
+ fs.copySync(
166
+ `./engine-private/conf/${deployId}/conf.server.json`,
167
+ `./engine-private/conf/${deployId}/conf.server.dev.${options.subConf}.json`,
168
+ );
169
+ return resolve();
170
+ }
98
171
  if (repositoryName === 'service')
99
172
  return resolve(
100
173
  await UnderpostStartUp.API.listenPortController(UnderpostStartUp.API.listenServerFactory(), ':'),
@@ -126,12 +199,26 @@ class UnderpostRepository {
126
199
  });
127
200
  },
128
201
 
202
+ /**
203
+ * Gets a list of deleted files from a Git repository.
204
+ * @param {string} [path='.'] - The path to the repository.
205
+ * @returns {string[]} An array of deleted file paths.
206
+ * @memberof UnderpostRepository
207
+ */
129
208
  getDeleteFiles(path = '.') {
130
209
  const commandUntrack = `cd ${path} && git ls-files --deleted`;
131
210
  const diffUntrackOutput = shellExec(commandUntrack, { stdout: true, silent: true });
132
211
  return diffUntrackOutput.toString().split('\n').filter(Boolean);
133
212
  },
134
213
 
214
+ /**
215
+ * Gets a list of changed (modified and untracked) files in a Git repository.
216
+ * @param {string} [path='.'] - The path to the repository.
217
+ * @param {string} [extension=''] - An optional file extension to filter by.
218
+ * @param {boolean} [head=false] - If true, diffs against HEAD^.
219
+ * @returns {string[]} An array of changed file paths.
220
+ * @memberof UnderpostRepository
221
+ */
135
222
  getChangedFiles(path = '.', extension = '', head = false) {
136
223
  const extensionFilter = extension ? `-- '***.${extension}'` : '';
137
224
  const command = `cd ${path} && git diff ${head ? 'HEAD^ HEAD ' : ''}--name-only ${extensionFilter}`;
@@ -146,6 +233,12 @@ class UnderpostRepository {
146
233
  .concat(diffUntrackOutput.toString().split('\n').filter(Boolean))
147
234
  .filter((f) => !deleteFiles.includes(f));
148
235
  },
236
+ /**
237
+ * Updates the private configuration repository for a given deployId.
238
+ * @param {string} deployId - The deployment ID.
239
+ * @returns {{validVersion: boolean, engineVersion: string, deployVersion: string}} An object indicating if the versions are valid.
240
+ * @memberof UnderpostRepository
241
+ */
149
242
  privateConfUpdate(deployId) {
150
243
  shellCd(`/home/dd/engine`);
151
244
  const privateRepoName = `engine-${deployId.split('dd-')[1]}-private`;
@@ -831,6 +831,14 @@ const subThemeManager = {
831
831
  color: ${this.lightColor};
832
832
  background-color: ${lightenHex(this.lightColor, 0.8)};
833
833
  }
834
+ .main-sub-btn-active {
835
+ color: ${this.lightColor};
836
+ background-color: rgba(0, 0, 0, 0.3);
837
+ }
838
+ .main-sub-btn-active:hover {
839
+ color: ${this.lightColor};
840
+ background-color: rgba(0, 0, 0, 0.2);
841
+ }
834
842
  </style>`;
835
843
  };
836
844
  },
@@ -845,6 +853,14 @@ const subThemeManager = {
845
853
  color: ${lightenHex(this.darkColor, 0.8)};
846
854
  background-color: ${darkenHex(this.darkColor, 0.75)};
847
855
  }
856
+ .main-sub-btn-active {
857
+ color: ${lightenHex(this.darkColor, 0.8)};
858
+ background-color: rgba(255, 255, 255, 0.3);
859
+ }
860
+ .main-sub-btn-active:hover {
861
+ color: ${lightenHex(this.darkColor, 0.8)};
862
+ background-color: rgba(255, 255, 255, 0.2);
863
+ }
848
864
  </style>`;
849
865
  };
850
866
  },
@@ -8,7 +8,7 @@ import { htmls, s } from './VanillaJs.js';
8
8
  // https://mintlify.com/docs/quickstart
9
9
 
10
10
  const Docs = {
11
- RenderModal: async function (type, modalOptions) {
11
+ RenderModal: async function (type) {
12
12
  const docData = this.Data.find((d) => d.type === type);
13
13
  const ModalId = `modal-docs-${docData.type}`;
14
14
  const { barConfig } = await Themes[Css.currentTheme]();
@@ -35,7 +35,7 @@ const Docs = {
35
35
  observer: true,
36
36
  barMode: 'top-bottom-bar',
37
37
  query: true,
38
- ...modalOptions,
38
+ RouterInstance: Modal.Data['modal-docs'].options.RouterInstance,
39
39
  });
40
40
  Modal.Data[ModalId].onObserverListener[ModalId] = () => {
41
41
  if (s(`.iframe-${ModalId}`))
@@ -118,25 +118,17 @@ const Docs = {
118
118
  const { idModal } = options;
119
119
  this.Tokens[idModal] = options;
120
120
  setTimeout(() => {
121
- const cleanActive = () => {
122
- s(`.btn-docs-src`).classList.remove('main-btn-menu-active');
123
- s(`.btn-docs-api`).classList.remove('main-btn-menu-active');
124
- s(`.btn-docs-coverage`).classList.remove('main-btn-menu-active');
125
- };
126
121
  s(`.btn-docs-src`).onclick = async () => {
127
122
  setQueryPath({ path: 'docs', queryPath: 'src' });
128
- cleanActive();
129
- await this.RenderModal('src', options.modalOptions);
123
+ await this.RenderModal('src');
130
124
  };
131
125
  s(`.btn-docs-api`).onclick = async () => {
132
126
  setQueryPath({ path: 'docs', queryPath: 'api' });
133
- cleanActive();
134
- await this.RenderModal('api', options.modalOptions);
127
+ await this.RenderModal('api');
135
128
  };
136
129
  s(`.btn-docs-coverage`).onclick = async () => {
137
130
  setQueryPath({ path: 'docs', queryPath: 'coverage' });
138
- cleanActive();
139
- await this.RenderModal('coverage', options.modalOptions);
131
+ await this.RenderModal('coverage');
140
132
  };
141
133
 
142
134
  s(`.btn-docs-coverage-link`).onclick = () => {
@@ -21,6 +21,8 @@ import {
21
21
  getProxyPath,
22
22
  setPath,
23
23
  coreUI,
24
+ sanitizeRoute,
25
+ getQueryParams,
24
26
  } from './Router.js';
25
27
  import { NotificationManager } from './NotificationManager.js';
26
28
  import { EventsUI } from './EventsUI.js';
@@ -90,11 +92,6 @@ const Modal = {
90
92
  query: options.query ? `${window.location.search}` : undefined,
91
93
  getTop: () => {
92
94
  const result = windowGetH() - (options.heightBottomBar ? options.heightBottomBar : heightDefaultBottomBar);
93
- // TODO: mobile padding gap on init size top height, Iphone SE responsive case
94
- // logger.warn('getTop', {
95
- // top: result,
96
- // height: Modal.Data[idModal].getHeight(),
97
- // });
98
95
  return result;
99
96
  },
100
97
  getHeight: () => {
@@ -120,6 +117,10 @@ const Modal = {
120
117
  }px`
121
118
  : `-${ops?.open ? '0px' : originSlideMenuWidth}px`
122
119
  }`,
120
+ center: () => {
121
+ top = `${windowGetH() / 2 - height / 2}px`;
122
+ left = `${windowGetW() / 2 - width / 2}px`;
123
+ },
123
124
  };
124
125
 
125
126
  if (options && 'mode' in options) {
@@ -1169,6 +1170,7 @@ const Modal = {
1169
1170
  });
1170
1171
  EventsUI.onClick(`.action-btn-home`, async () => {
1171
1172
  await Modal.onHomeRouterEvent();
1173
+ subMenuHandler(Object.keys(options.RouterInstance.Routes()));
1172
1174
  Object.keys(this.Data[idModal].onHome).map((keyListener) => this.Data[idModal].onHome[keyListener]());
1173
1175
  });
1174
1176
  EventsUI.onClick(`.action-btn-app-icon`, () => s(`.action-btn-home`).click());
@@ -1349,7 +1351,6 @@ const Modal = {
1349
1351
  removeEvent();
1350
1352
  }
1351
1353
  });
1352
- // TODO: mobile padding gap on init size top height, Iphone SE responsive case
1353
1354
  setTimeout(window.onresize);
1354
1355
  });
1355
1356
  })();
@@ -1387,10 +1388,7 @@ const Modal = {
1387
1388
  return;
1388
1389
  }
1389
1390
 
1390
- if (idModal !== 'main-body' && options.mode !== 'view' && !options.disableCenter) {
1391
- top = `${windowGetH() / 2 - height / 2}px`;
1392
- left = `${windowGetW() / 2 - width / 2}px`;
1393
- }
1391
+ if (idModal !== 'main-body' && options.mode !== 'view' && !options.disableCenter) Modal.Data[idModal].center();
1394
1392
 
1395
1393
  const render = html` <style class="style-${idModal}">
1396
1394
  .${idModal} {
@@ -1860,26 +1858,14 @@ const Modal = {
1860
1858
  s(`.btn-maximize-${idModal}`).style.display = null;
1861
1859
 
1862
1860
  // Restore original dimensions and position
1861
+ this.Data[idModal].center();
1863
1862
  modal.style.transform = '';
1864
- modal.style.height = '';
1865
- left = 0;
1866
- width = 300;
1867
- modal.style.left = `${left}px`;
1863
+ modal.style.height = `${height}px`;
1864
+ modal.style.left = left;
1865
+ modal.style.top = top;
1868
1866
  modal.style.width = `${width}px`;
1869
1867
  modal.style.overflow = '';
1870
1868
 
1871
- // Reset drag position
1872
- dragPosition = { x: 0, y: 0 };
1873
-
1874
- // Set new position
1875
- modal.style.transform = `translate(0, 0)`;
1876
-
1877
- // Adjust top position based on top bar visibility
1878
- const heightDefaultTopBar = 40; // Default top bar height if not specified
1879
- s(`.${idModal}`).style.top = s(`.main-body-btn-ui-close`).classList.contains('hide')
1880
- ? `0px`
1881
- : `${options.heightTopBar ? options.heightTopBar : heightDefaultTopBar}px`;
1882
-
1883
1869
  // Re-enable drag after restore
1884
1870
  if (dragInstance) {
1885
1871
  dragInstance.updateOptions({
@@ -2191,14 +2177,13 @@ const Modal = {
2191
2177
  : { ...Modal.subMenuBtnClass, _: { btnSelector, labelSelector } };
2192
2178
 
2193
2179
  for (const keyDataBtn of Object.keys(_data)) {
2194
- const { btnSelector, labelSelector, open, top } = _data[keyDataBtn];
2180
+ const { labelSelector, top } = _data[keyDataBtn];
2195
2181
  if (top)
2196
2182
  setTimeout(() => {
2197
2183
  top();
2198
2184
  });
2199
- if (open) continue;
2200
2185
  sa(labelSelector).forEach((el) => {
2201
- el.classList.add('hide');
2186
+ if (!el.classList.contains('hide')) el.classList.add('hide');
2202
2187
  el.style.transition = null;
2203
2188
  });
2204
2189
 
@@ -2414,7 +2399,7 @@ const buildBadgeToolTipMenuOption = (id, sideKey = 'left') => {
2414
2399
  };
2415
2400
 
2416
2401
  const isSubMenuOpen = (subMenuId) => {
2417
- return s(`.down-arrow-submenu-${subMenuId}`).style.rotate === '180deg';
2402
+ return s(`.down-arrow-submenu-${subMenuId}`) && s(`.down-arrow-submenu-${subMenuId}`).style.rotate === '180deg';
2418
2403
  };
2419
2404
 
2420
2405
  const subMenuRender = async (subMenuId) => {
@@ -2425,11 +2410,16 @@ const subMenuRender = async (subMenuId) => {
2425
2410
 
2426
2411
  if (!menuBtn || !menuContainer || !arrow) return;
2427
2412
 
2428
- // if (Modal.subMenuBtnClass[subMenuId] && !(isSubMenuOpen(subMenuId) && Modal.subMenuBtnClass[subMenuId].open === true))
2429
- // Modal.subMenuBtnClass[subMenuId].open = false;
2430
-
2431
2413
  const top = () => {
2432
- menuContainer.style.top = menuBtn.offsetTop + Modal.Data['modal-menu'].options.heightTopBar + 'px';
2414
+ let value = menuBtn.offsetTop + Modal.Data['modal-menu'].options.heightTopBar;
2415
+
2416
+ const isHidden = s('.main-body-btn-ui-open').classList.contains('hide');
2417
+ const isTopBottom = Modal.Data['modal-menu'].options.barMode === 'top-bottom-bar';
2418
+
2419
+ if (!isTopBottom && isHidden) value -= 51;
2420
+ else if (!isHidden) value += 51;
2421
+
2422
+ menuContainer.style.top = `${value}px`;
2433
2423
  };
2434
2424
 
2435
2425
  Modal.subMenuBtnClass[subMenuId] = {
@@ -2442,8 +2432,7 @@ const subMenuRender = async (subMenuId) => {
2442
2432
  menuBtn.style.transition = '.3s';
2443
2433
  arrow.style.transition = '.3s';
2444
2434
 
2445
- if (Modal.subMenuBtnClass[subMenuId].open) {
2446
- Modal.subMenuBtnClass[subMenuId].open = false;
2435
+ if (isSubMenuOpen(subMenuId)) {
2447
2436
  // Close animation
2448
2437
  menuContainer.style.overflow = 'hidden';
2449
2438
  menuContainer.style.height = '0px';
@@ -2453,8 +2442,12 @@ const subMenuRender = async (subMenuId) => {
2453
2442
  arrow.style.rotate = '0deg';
2454
2443
  });
2455
2444
  } else {
2456
- Modal.menuTextLabelAnimation('modal-menu', subMenuId);
2457
- Modal.subMenuBtnClass[subMenuId].open = true;
2445
+ sa(`.menu-label-text-${subMenuId}`).forEach((el) => {
2446
+ if (!el.classList.contains('hide')) el.classList.add('hide');
2447
+ });
2448
+ setTimeout(() => {
2449
+ Modal.menuTextLabelAnimation('modal-menu', subMenuId);
2450
+ });
2458
2451
  // Open animation
2459
2452
  setTimeout(top, 360);
2460
2453
  menuContainer.style.width = '320px';
@@ -2473,4 +2466,29 @@ const subMenuRender = async (subMenuId) => {
2473
2466
  }, 500);
2474
2467
  };
2475
2468
 
2476
- export { Modal, renderMenuLabel, renderViewTitle, buildBadgeToolTipMenuOption, subMenuRender, isSubMenuOpen };
2469
+ const subMenuHandler = (routes, route) => {
2470
+ route = sanitizeRoute(route);
2471
+ for (let _route of routes) {
2472
+ _route = sanitizeRoute(_route);
2473
+ if (_route !== route) {
2474
+ if (isSubMenuOpen(_route)) subMenuRender(_route);
2475
+ }
2476
+ }
2477
+ setTimeout(() => {
2478
+ let cid = getQueryParams().cid;
2479
+ if (s(`.main-sub-btn-active`)) s(`.main-sub-btn-active`).classList.remove('main-sub-btn-active');
2480
+ if (cid && s(`.btn-${route}-${cid}`)) {
2481
+ s(`.btn-${route}-${cid}`).classList.add('main-sub-btn-active');
2482
+ }
2483
+ });
2484
+ };
2485
+
2486
+ export {
2487
+ Modal,
2488
+ renderMenuLabel,
2489
+ renderViewTitle,
2490
+ buildBadgeToolTipMenuOption,
2491
+ subMenuRender,
2492
+ isSubMenuOpen,
2493
+ subMenuHandler,
2494
+ };
@@ -7,7 +7,7 @@
7
7
  import { titleFormatted } from './CommonJs.js';
8
8
  import { loggerFactory } from './Logger.js';
9
9
  import { htmls, s } from './VanillaJs.js';
10
- import { Modal } from './Modal.js';
10
+ import { Modal, subMenuHandler } from './Modal.js';
11
11
  import { Worker } from './Worker.js';
12
12
 
13
13
  const logger = loggerFactory(import.meta, { trace: true });
@@ -162,6 +162,7 @@ const Router = function (options = { Routes: () => {}, e: new PopStateEvent() })
162
162
 
163
163
  if (path === pushPath) {
164
164
  for (const event of Object.keys(RouterEvents)) RouterEvents[event](routerEvent);
165
+ subMenuHandler(Object.keys(Routes()), route);
165
166
  setDocTitle(route);
166
167
  return Routes()[`/${route}`].render();
167
168
  }
@@ -256,14 +257,15 @@ const closeModalRouteChangeEvent = (options = {}) => {
256
257
  * @param {string} options.route - The route associated with the modal view.
257
258
  * @memberof PwaRouter
258
259
  */
259
- const handleModalViewRoute = (options = { route: '' }) => {
260
- const { route } = options;
260
+ const handleModalViewRoute = (options = { RouterInstance: { Routes: () => {} }, route: '' }) => {
261
+ const { route, RouterInstance } = options;
261
262
  if (!route) return;
262
263
 
263
264
  let path = window.location.pathname;
264
265
  if (path !== '/' && path[path.length - 1] === '/') path = path.slice(0, -1);
265
266
  const proxyPath = getProxyPath();
266
267
  const newPath = `${proxyPath}${route}`;
268
+ if (RouterInstance && RouterInstance.Routes) subMenuHandler(Object.keys(RouterInstance.Routes()), route);
267
269
 
268
270
  if (path !== newPath) {
269
271
  setPath(newPath);
@@ -311,4 +313,5 @@ export {
311
313
  getProxyPath,
312
314
  setPath,
313
315
  setQueryParams,
316
+ sanitizeRoute,
314
317
  };