underpost 3.2.4 → 3.2.8

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 (141) hide show
  1. package/.github/workflows/release.cd.yml +1 -2
  2. package/CHANGELOG.md +268 -1
  3. package/CLI-HELP.md +26 -13
  4. package/Dockerfile +0 -4
  5. package/README.md +3 -3
  6. package/bin/build.js +13 -3
  7. package/bin/deploy.js +570 -1
  8. package/bin/file.js +5 -0
  9. package/conf.js +11 -2
  10. package/jsconfig.json +1 -1
  11. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -3
  12. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +2 -3
  13. package/manifests/deployment/dd-default-development/deployment.yaml +2 -6
  14. package/manifests/deployment/dd-test-development/deployment.yaml +136 -66
  15. package/manifests/deployment/dd-test-development/proxy.yaml +41 -5
  16. package/package.json +20 -11
  17. package/src/api/core/core.controller.js +10 -10
  18. package/src/api/core/core.service.js +10 -10
  19. package/src/api/default/default.controller.js +10 -10
  20. package/src/api/default/default.service.js +10 -10
  21. package/src/api/document/document.controller.js +12 -12
  22. package/src/api/document/document.model.js +10 -16
  23. package/src/api/file/file.controller.js +8 -8
  24. package/src/api/file/file.model.js +10 -10
  25. package/src/api/file/file.service.js +36 -36
  26. package/src/api/test/test.controller.js +8 -8
  27. package/src/api/test/test.service.js +8 -8
  28. package/src/api/user/guest.service.js +99 -0
  29. package/src/api/user/user.controller.js +6 -6
  30. package/src/api/user/user.model.js +8 -13
  31. package/src/api/user/user.service.js +3 -20
  32. package/src/cli/deploy.js +33 -30
  33. package/src/cli/fs.js +62 -5
  34. package/src/cli/image.js +43 -1
  35. package/src/cli/index.js +5 -1
  36. package/src/cli/release.js +58 -2
  37. package/src/cli/repository.js +35 -3
  38. package/src/cli/run.js +304 -38
  39. package/src/cli/ssh.js +1 -1
  40. package/src/cli/static.js +43 -115
  41. package/src/client/Default.index.js +21 -33
  42. package/src/client/components/core/404.js +4 -4
  43. package/src/client/components/core/500.js +4 -4
  44. package/src/client/components/core/Account.js +73 -60
  45. package/src/client/components/core/AgGrid.js +23 -33
  46. package/src/client/components/core/Alert.js +12 -13
  47. package/src/client/components/core/AppStore.js +1 -1
  48. package/src/client/components/core/Auth.js +20 -32
  49. package/src/client/components/core/Badge.js +7 -13
  50. package/src/client/components/core/BtnIcon.js +15 -17
  51. package/src/client/components/core/CalendarCore.js +42 -63
  52. package/src/client/components/core/Chat.js +13 -15
  53. package/src/client/components/core/ClientEvents.js +87 -0
  54. package/src/client/components/core/ColorPaletteElement.js +309 -0
  55. package/src/client/components/core/Content.js +17 -14
  56. package/src/client/components/core/Css.js +15 -71
  57. package/src/client/components/core/CssCore.js +12 -16
  58. package/src/client/components/core/D3Chart.js +4 -4
  59. package/src/client/components/core/Docs.js +60 -59
  60. package/src/client/components/core/DropDown.js +69 -91
  61. package/src/client/components/core/EventBus.js +92 -0
  62. package/src/client/components/core/EventsUI.js +14 -17
  63. package/src/client/components/core/FileExplorer.js +102 -234
  64. package/src/client/components/core/FullScreen.js +47 -75
  65. package/src/client/components/core/Input.js +24 -69
  66. package/src/client/components/core/Keyboard.js +25 -18
  67. package/src/client/components/core/KeyboardAvoidance.js +145 -0
  68. package/src/client/components/core/LoadingAnimation.js +25 -31
  69. package/src/client/components/core/LogIn.js +41 -41
  70. package/src/client/components/core/LogOut.js +23 -14
  71. package/src/client/components/core/Modal.js +397 -176
  72. package/src/client/components/core/NotificationManager.js +14 -18
  73. package/src/client/components/core/Panel.js +54 -50
  74. package/src/client/components/core/PanelForm.js +25 -125
  75. package/src/client/components/core/Polyhedron.js +110 -214
  76. package/src/client/components/core/PublicProfile.js +39 -32
  77. package/src/client/components/core/Recover.js +52 -48
  78. package/src/client/components/core/Responsive.js +88 -32
  79. package/src/client/components/core/RichText.js +9 -18
  80. package/src/client/components/core/Router.js +24 -3
  81. package/src/client/components/core/SearchBox.js +37 -37
  82. package/src/client/components/core/SignUp.js +39 -30
  83. package/src/client/components/core/SocketIo.js +31 -2
  84. package/src/client/components/core/SocketIoHandler.js +6 -6
  85. package/src/client/components/core/ToggleSwitch.js +8 -20
  86. package/src/client/components/core/ToolTip.js +5 -17
  87. package/src/client/components/core/Translate.js +56 -59
  88. package/src/client/components/core/Validator.js +26 -16
  89. package/src/client/components/core/Wallet.js +15 -26
  90. package/src/client/components/core/Worker.js +140 -25
  91. package/src/client/components/core/windowGetDimensions.js +7 -7
  92. package/src/client/components/default/{MenuDefault.js → AppShellDefault.js} +87 -87
  93. package/src/client/components/default/CssDefault.js +12 -12
  94. package/src/client/components/default/LogInDefault.js +6 -4
  95. package/src/client/components/default/LogOutDefault.js +6 -4
  96. package/src/client/components/default/RouterDefault.js +47 -0
  97. package/src/client/components/default/SettingsDefault.js +4 -4
  98. package/src/client/components/default/SignUpDefault.js +6 -4
  99. package/src/client/components/default/TranslateDefault.js +3 -3
  100. package/src/client/services/core/core.service.js +17 -49
  101. package/src/client/services/default/default.management.js +139 -242
  102. package/src/client/services/default/default.service.js +10 -16
  103. package/src/client/services/document/document.service.js +14 -19
  104. package/src/client/services/file/file.service.js +8 -13
  105. package/src/client/services/test/test.service.js +8 -13
  106. package/src/client/services/user/guest.service.js +79 -0
  107. package/src/client/services/user/user.management.js +5 -5
  108. package/src/client/services/user/user.service.js +14 -20
  109. package/src/client/ssr/body/404.js +3 -3
  110. package/src/client/ssr/body/500.js +3 -3
  111. package/src/client/ssr/body/CacheControl.js +5 -2
  112. package/src/client/ssr/body/DefaultSplashScreen.js +19 -12
  113. package/src/client/ssr/mailer/DefaultRecoverEmail.js +19 -20
  114. package/src/client/ssr/mailer/DefaultVerifyEmail.js +15 -16
  115. package/src/client/ssr/offline/Maintenance.js +12 -11
  116. package/src/client/ssr/offline/NoNetworkConnection.js +3 -3
  117. package/src/client/ssr/pages/Test.js +2 -2
  118. package/src/client/sw/core.sw.js +212 -0
  119. package/src/index.js +1 -1
  120. package/src/runtime/express/Dockerfile +4 -4
  121. package/src/runtime/lampp/Dockerfile +8 -7
  122. package/src/runtime/wp/Dockerfile +11 -17
  123. package/src/server/backup.js +1 -2
  124. package/src/server/client-build-docs.js +45 -46
  125. package/src/server/client-build.js +334 -60
  126. package/src/server/client-formatted.js +47 -16
  127. package/src/server/conf.js +29 -13
  128. package/src/server/cron.js +6 -8
  129. package/src/server/dns.js +2 -1
  130. package/src/server/ipfs-client.js +232 -91
  131. package/src/server/process.js +13 -27
  132. package/src/server/start.js +6 -3
  133. package/src/server/valkey.js +134 -235
  134. package/tsconfig.docs.json +15 -0
  135. package/typedoc.json +20 -0
  136. package/jsdoc.json +0 -52
  137. package/src/client/components/core/ColorPalette.js +0 -5267
  138. package/src/client/components/core/JoyStick.js +0 -80
  139. package/src/client/components/default/RoutesDefault.js +0 -49
  140. package/src/client/sw/default.sw.js +0 -127
  141. package/src/client/sw/template.sw.js +0 -84
@@ -12,6 +12,25 @@ import { Worker } from './Worker.js';
12
12
 
13
13
  const logger = loggerFactory(import.meta, { trace: true });
14
14
 
15
+ /**
16
+ * @type {function | null}
17
+ * @description The active routes function registered by the current app router.
18
+ * Replaces the former `window.Routes` global so `getProxyPath` can resolve
19
+ * sub-directory proxy paths without polluting the global scope.
20
+ * @memberof PwaRouter
21
+ */
22
+ let _activeRoutes = null;
23
+
24
+ /**
25
+ * Registers the active routes function for the current app.
26
+ * Called automatically by `LoadRouter`; should not be called manually.
27
+ * @param {function} routesFn - A function returning the routes object.
28
+ * @memberof PwaRouter
29
+ */
30
+ const registerRoutes = (routesFn) => {
31
+ _activeRoutes = routesFn;
32
+ };
33
+
15
34
  /**
16
35
  * @type {Object.<string, function>}
17
36
  * @description Holds event listeners for router changes.
@@ -71,15 +90,15 @@ const setRouterReady = () => {
71
90
 
72
91
  /**
73
92
  * Determines the base path for the application, often used for routing within a sub-directory.
74
- * It checks the current URL's pathname and `window.Routes` to return the appropriate proxy path.
93
+ * It checks the current URL's pathname and the active registered routes to return the appropriate proxy path.
75
94
  *
76
95
  * @returns {string} The calculated proxy path. Returns `/<first-segment>/` if a segment exists,
77
- * otherwise `/`. If `window.Routes` indicates the path is a root route, it returns `/`.
96
+ * otherwise `/`. If the registered routes indicate the path is a root route, it returns `/`.
78
97
  * @memberof PwaRouter
79
98
  */
80
99
  const getProxyPath = () => {
81
100
  let path = location.pathname.split('/')[1] ? `/${location.pathname.split('/')[1]}/` : '/';
82
- if (window.Routes && path !== '/' && path.slice(0, -1) in window.Routes()) path = '/';
101
+ if (_activeRoutes && path !== '/' && path.slice(0, -1) in _activeRoutes()) path = '/';
83
102
  return path;
84
103
  };
85
104
 
@@ -241,6 +260,7 @@ const Router = function (options = { Routes: () => {}, e: new PopStateEvent() })
241
260
  */
242
261
  const LoadRouter = async function (RouterInstance) {
243
262
  await RouterReady;
263
+ if (RouterInstance.Routes) registerRoutes(RouterInstance.Routes);
244
264
  Router(RouterInstance);
245
265
  window.onpopstate = (e) => {
246
266
  Router({ ...RouterInstance, e });
@@ -478,6 +498,7 @@ const setQueryParams = (newParams, options = { replace: true }) => {
478
498
 
479
499
  export {
480
500
  RouterEvents,
501
+ registerRoutes,
481
502
  navigateToProfile,
482
503
  closeModalRouteChangeEvents,
483
504
  coreUI,
@@ -14,18 +14,18 @@ import { darkTheme, ThemeEvents, subThemeManager, lightenHex, darkenHex } from '
14
14
  const logger = loggerFactory(import.meta);
15
15
 
16
16
  /**
17
- * SearchBox singleton object providing extensible search functionality.
17
+ * SearchBox class providing extensible search functionality.
18
18
  * Supports default menu/route search and pluggable search providers with
19
19
  * custom rendering, click handlers, and result merging.
20
20
  * @memberof SearchBoxClient
21
21
  */
22
- const SearchBox = {
22
+ class SearchBox {
23
23
  /**
24
24
  * Internal data storage for search state and handlers.
25
25
  * @type {object}
26
26
  * @memberof SearchBoxClient.SearchBox
27
27
  */
28
- Data: {},
28
+ static Data = {};
29
29
 
30
30
  /**
31
31
  * Registry of registered search provider plugins.
@@ -38,7 +38,7 @@ const SearchBox = {
38
38
  * @type {Array<object>}
39
39
  * @memberof SearchBoxClient.SearchBox
40
40
  */
41
- providers: [],
41
+ static providers = [];
42
42
 
43
43
  /**
44
44
  * Recent search results manager with localStorage persistence.
@@ -47,7 +47,7 @@ const SearchBox = {
47
47
  * @type {object}
48
48
  * @memberof SearchBoxClient.SearchBox
49
49
  */
50
- RecentResults: {
50
+ static RecentResults = {
51
51
  /**
52
52
  * Storage key for localStorage persistence
53
53
  * @type {string}
@@ -159,7 +159,7 @@ const SearchBox = {
159
159
  });
160
160
  this.saveAll(filtered);
161
161
  },
162
- },
162
+ };
163
163
 
164
164
  /**
165
165
  * Registers a search provider plugin for extensible search functionality.
@@ -173,7 +173,7 @@ const SearchBox = {
173
173
  * @param {number} [provider.priority=50] - Priority for result ordering (lower = higher priority).
174
174
  * @returns {void}
175
175
  */
176
- registerProvider: function (provider) {
176
+ static registerProvider(provider) {
177
177
  if (!provider.id || !provider.search) {
178
178
  logger.error('Invalid provider. Must have id and search function');
179
179
  return;
@@ -192,7 +192,7 @@ const SearchBox = {
192
192
  });
193
193
 
194
194
  logger.info(`Registered search provider: ${provider.id}`);
195
- },
195
+ }
196
196
 
197
197
  /**
198
198
  * Unregisters a search provider by its ID.
@@ -200,10 +200,10 @@ const SearchBox = {
200
200
  * @param {string} providerId - The ID of the provider to unregister.
201
201
  * @returns {void}
202
202
  */
203
- unregisterProvider: function (providerId) {
203
+ static unregisterProvider(providerId) {
204
204
  this.providers = this.providers.filter((p) => p.id !== providerId);
205
205
  logger.info(`Unregistered search provider: ${providerId}`);
206
- },
206
+ }
207
207
 
208
208
  /**
209
209
  * Default result renderer with support for tags and badges.
@@ -219,13 +219,13 @@ const SearchBox = {
219
219
  * @param {string} result.providerId - Provider ID that generated this result.
220
220
  * @returns {string} HTML string for the search result.
221
221
  */
222
- defaultRenderResult: function (result) {
222
+ static defaultRenderResult(result) {
223
223
  const icon = result.icon || '<i class="fas fa-file"></i>';
224
224
  const title = result.title || result.id || 'Untitled';
225
225
  const subtitle = result.subtitle || '';
226
226
  const tags = result.tags || [];
227
227
 
228
- // Render tags if available
228
+ // instance tags if available
229
229
  const tagsHtml =
230
230
  tags.length > 0
231
231
  ? `<div class="search-result-tags">
@@ -247,7 +247,7 @@ const SearchBox = {
247
247
  </div>
248
248
  </div>
249
249
  `;
250
- },
250
+ }
251
251
 
252
252
  /**
253
253
  * Navigates through search results using keyboard arrow keys.
@@ -260,7 +260,7 @@ const SearchBox = {
260
260
  * @param {number} totalItems - Total number of result items.
261
261
  * @returns {number} New active index after navigation.
262
262
  */
263
- navigateResults: function (direction, containerId, currentIndex, totalItems) {
263
+ static navigateResults(direction, containerId, currentIndex, totalItems) {
264
264
  if (!containerId || totalItems === 0) return currentIndex;
265
265
 
266
266
  const container = s(`#${containerId}`) || s(`.${containerId}`);
@@ -289,7 +289,7 @@ const SearchBox = {
289
289
  }
290
290
 
291
291
  return newIndex;
292
- },
292
+ }
293
293
 
294
294
  /**
295
295
  * Searches through default application routes for matches.
@@ -303,7 +303,7 @@ const SearchBox = {
303
303
  * @param {string} [context.options.searchCustomImgClass] - Custom image class to search for.
304
304
  * @returns {Array<object>} Array of route search results.
305
305
  */
306
- searchRoutes: function (query, context) {
306
+ static searchRoutes(query, context) {
307
307
  const results = [];
308
308
  const { RouterInstance, options = {} } = context;
309
309
 
@@ -346,7 +346,7 @@ const SearchBox = {
346
346
  }
347
347
  }
348
348
  return results;
349
- },
349
+ }
350
350
 
351
351
  /**
352
352
  * Executes search across all registered providers and default routes.
@@ -356,7 +356,7 @@ const SearchBox = {
356
356
  * @param {object} [context={}] - Search context object passed to all providers.
357
357
  * @returns {Promise<Array<object>>} Promise resolving to combined, priority-sorted results array.
358
358
  */
359
- search: async function (query, context = {}) {
359
+ static async search(query, context = {}) {
360
360
  const allResults = [];
361
361
 
362
362
  // Always include default route search (backward compatible)
@@ -387,7 +387,7 @@ const SearchBox = {
387
387
  allResults.sort((a, b) => (a.priority || 50) - (b.priority || 50));
388
388
 
389
389
  return allResults;
390
- },
390
+ }
391
391
 
392
392
  /**
393
393
  * Renders search results into a container element.
@@ -396,10 +396,10 @@ const SearchBox = {
396
396
  * @memberof SearchBoxClient.SearchBox
397
397
  * @param {Array<object>} results - Array of search results to render.
398
398
  * @param {string} containerId - Results container element ID or class name.
399
- * @param {object} [context={}] - Render context passed to renderers and handlers.
399
+ * @param {object} [context={}] - instance context passed to renderers and handlers.
400
400
  * @returns {void}
401
401
  */
402
- renderResults: function (results, containerId, context = {}) {
402
+ static renderResults(results, containerId, context = {}) {
403
403
  const container = s(`#${containerId}`) || s(`.${containerId}`);
404
404
  if (!container) {
405
405
  logger.warn(`Container ${containerId} not found`);
@@ -468,7 +468,7 @@ const SearchBox = {
468
468
  provider.attachTagHandlers();
469
469
  }
470
470
  });
471
- },
471
+ }
472
472
 
473
473
  /**
474
474
  * Attaches delete event handlers to result delete buttons within a specific container.
@@ -481,7 +481,7 @@ const SearchBox = {
481
481
  * @param {object} [context={}] - Context object.
482
482
  * @returns {void}
483
483
  */
484
- attachDeleteHandlers: function (container, results, containerId, context = {}) {
484
+ static attachDeleteHandlers(container, results, containerId, context = {}) {
485
485
  // Only select delete buttons within this specific container
486
486
  const deleteButtons = container.querySelectorAll('.search-result-delete-btn');
487
487
  deleteButtons.forEach((btn) => {
@@ -530,7 +530,7 @@ const SearchBox = {
530
530
  }
531
531
  });
532
532
  });
533
- },
533
+ }
534
534
 
535
535
  /**
536
536
  * Renders a default route search result.
@@ -542,11 +542,11 @@ const SearchBox = {
542
542
  * @param {HTMLElement} [result.fontAwesomeIcon] - FontAwesome icon element.
543
543
  * @param {HTMLElement} [result.imgElement] - Image icon element.
544
544
  * @param {number} index - The index of this result in the results array.
545
- * @param {object} [context={}] - Render context object.
545
+ * @param {object} [context={}] - instance context object.
546
546
  * @param {object} [context.options] - Additional rendering options.
547
547
  * @returns {string} HTML string for the route search result.
548
548
  */
549
- renderRouteResult: function (result, index, context = {}) {
549
+ static renderRouteResult(result, index, context = {}) {
550
550
  const { options = {} } = context;
551
551
  const routerId = result.routerId;
552
552
  const fontAwesomeIcon = result.fontAwesomeIcon;
@@ -584,7 +584,7 @@ const SearchBox = {
584
584
  }
585
585
  }
586
586
 
587
- const translatedText = Translate.Render(routerId);
587
+ const translatedText = Translate.instance(routerId);
588
588
 
589
589
  return html`
590
590
  <div
@@ -600,7 +600,7 @@ const SearchBox = {
600
600
  </div>
601
601
  </div>
602
602
  `;
603
- },
603
+ }
604
604
 
605
605
  /**
606
606
  * Attaches click event handlers to all rendered search results.
@@ -612,7 +612,7 @@ const SearchBox = {
612
612
  * @param {Function} [context.onResultClick] - Callback invoked after any result is clicked.
613
613
  * @returns {void}
614
614
  */
615
- attachClickHandlers: function (results, containerId, context = {}) {
615
+ static attachClickHandlers(results, containerId, context = {}) {
616
616
  results.forEach((result, index) => {
617
617
  const element = s(`[data-result-index="${index}"]`);
618
618
  if (!element) return;
@@ -643,7 +643,7 @@ const SearchBox = {
643
643
  }
644
644
  };
645
645
  });
646
- },
646
+ }
647
647
 
648
648
  /**
649
649
  * Scrolls an element into view within a scrollable container if needed.
@@ -668,7 +668,7 @@ const SearchBox = {
668
668
  * @param {HTMLElement} container - The scrollable container (or parent of scrollable).
669
669
  * @returns {void}
670
670
  */
671
- scrollIntoViewIfNeeded: function (element, container) {
671
+ static scrollIntoViewIfNeeded(element, container) {
672
672
  if (!element || !container) return;
673
673
 
674
674
  // CRITICAL FIX: Find the actual scrollable container
@@ -744,7 +744,7 @@ const SearchBox = {
744
744
  });
745
745
  }
746
746
  }, 0);
747
- },
747
+ }
748
748
 
749
749
  /**
750
750
  * Gets base CSS styles for SearchBox with theme-aware styling.
@@ -753,7 +753,7 @@ const SearchBox = {
753
753
  * @memberof SearchBoxClient.SearchBox
754
754
  * @returns {string} CSS string containing all base SearchBox styles.
755
755
  */
756
- getBaseStyles: () => {
756
+ static getBaseStyles = () => {
757
757
  // Get theme color from subThemeManager
758
758
  const themeColor = darkTheme ? subThemeManager.darkColor : subThemeManager.lightColor;
759
759
  const hasThemeColor = themeColor && themeColor !== null;
@@ -968,7 +968,7 @@ const SearchBox = {
968
968
  transition: all 0.2s ease;
969
969
  }
970
970
  `;
971
- },
971
+ };
972
972
 
973
973
  /**
974
974
  * Injects base SearchBox styles into the document head.
@@ -977,7 +977,7 @@ const SearchBox = {
977
977
  * @memberof SearchBoxClient.SearchBox
978
978
  * @returns {void}
979
979
  */
980
- injectStyles: function () {
980
+ static injectStyles() {
981
981
  const styleId = 'search-box-base-styles';
982
982
  let styleTag = document.getElementById(styleId);
983
983
 
@@ -1001,7 +1001,7 @@ const SearchBox = {
1001
1001
  }
1002
1002
  };
1003
1003
  }
1004
- },
1005
- };
1004
+ }
1005
+ }
1006
1006
 
1007
1007
  export { SearchBox };
@@ -1,19 +1,29 @@
1
1
  import { UserService } from '../../services/user/user.service.js';
2
2
  import { Auth } from './Auth.js';
3
3
  import { BtnIcon } from './BtnIcon.js';
4
+ import { AuthEventType, authSignupEvents } from './ClientEvents.js';
4
5
  import { EventsUI } from './EventsUI.js';
5
6
  import { Input } from './Input.js';
6
7
  import { NotificationManager } from './NotificationManager.js';
7
8
  import { Translate } from './Translate.js';
8
9
  import { Validator } from './Validator.js';
9
10
  import { s } from './VanillaJs.js';
10
-
11
- const SignUp = {
12
- Event: {},
13
- Trigger: async function (options) {
14
- for (const eventKey of Object.keys(this.Event)) await this.Event[eventKey](options);
15
- },
16
- Render: async function (options = { bottomRender: async () => '' }) {
11
+ class SignUp {
12
+ static Event = {};
13
+ static onSignup(listener, options = {}) {
14
+ return authSignupEvents.on(AuthEventType.signup, listener, options);
15
+ }
16
+ static offSignup(key) {
17
+ return authSignupEvents.off(key);
18
+ }
19
+ static hasSignupListener(key) {
20
+ return authSignupEvents.has(key);
21
+ }
22
+ static async Trigger(options) {
23
+ await authSignupEvents.emit(AuthEventType.signup, options);
24
+ for (const eventKey of Object.keys(SignUp.Event)) await SignUp.Event[eventKey](options);
25
+ }
26
+ static async instance(options = { bottomRender: async () => '' }) {
17
27
  setTimeout(async () => {
18
28
  const formData = [
19
29
  {
@@ -33,7 +43,6 @@ const SignUp = {
33
43
  },
34
44
  ];
35
45
  const validators = await Validator.instance(formData);
36
-
37
46
  EventsUI.onClick(`.btn-sign-up`, async (e) => {
38
47
  e.preventDefault();
39
48
  const { errorMessage } = await validators();
@@ -47,23 +56,23 @@ const SignUp = {
47
56
  let error = '';
48
57
  if (data.message) {
49
58
  if (data.message.match('duplicate')) {
50
- if (data.message.match('username')) error += Translate.Render('error-username-taken');
51
- if (data.message.match('email')) error += Translate.Render('error-email-taken');
59
+ if (data.message.match('username')) error += Translate.instance('error-username-taken');
60
+ if (data.message.match('email')) error += Translate.instance('error-email-taken');
52
61
  } else {
53
- if (data.message.match('username')) error += Translate.Render('error-username-invalid');
54
- if (data.message.match('email')) error += Translate.Render('error-email-invalid');
55
- if (data.message.match('password')) error += Translate.Render('error-password-invalid');
62
+ if (data.message.match('username')) error += Translate.instance('error-username-invalid');
63
+ if (data.message.match('email')) error += Translate.instance('error-email-invalid');
64
+ if (data.message.match('password')) error += Translate.instance('error-password-invalid');
56
65
  }
57
66
  return error;
58
67
  }
59
- return Translate.Render('error-register-user');
68
+ return Translate.instance('error-register-user');
60
69
  };
61
70
  NotificationManager.Push({
62
71
  html:
63
72
  typeof result.data === 'string'
64
73
  ? result.data
65
74
  : result.status === 'success'
66
- ? Translate.Render(`success-register-user`)
75
+ ? Translate.instance(`success-register-user`)
67
76
  : handleSignUpError(result),
68
77
  status: result.status,
69
78
  });
@@ -81,64 +90,64 @@ const SignUp = {
81
90
  });
82
91
  });
83
92
  return html`
84
- ${await BtnIcon.Render({
93
+ ${await BtnIcon.instance({
85
94
  class: 'in section-mp form-button btn-sign-up-i-have-account',
86
- label: html`<i class="fas fa-sign-in-alt"></i> ${Translate.Render('i-have-account')}<br />${Translate.Render(
95
+ label: html`<i class="fas fa-sign-in-alt"></i> ${Translate.instance('i-have-account')}<br />${Translate.instance(
87
96
  'log-in',
88
97
  )}`,
89
98
  type: 'button',
90
99
  })}
91
100
  <form class="in">
92
101
  <div class="in">
93
- ${await Input.Render({
102
+ ${await Input.instance({
94
103
  id: `sign-up-username`,
95
104
  type: 'text',
96
- label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.Render('username')}`,
105
+ label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.instance('username')}`,
97
106
  containerClass: 'inl section-mp width-mini-box input-container',
98
107
  placeholder: true,
99
108
  })}
100
109
  </div>
101
110
  <div class="in">
102
- ${await Input.Render({
111
+ ${await Input.instance({
103
112
  id: `sign-up-email`,
104
113
  type: 'email',
105
- label: html`<i class="fa-solid fa-envelope"></i> ${Translate.Render('email')}`,
114
+ label: html`<i class="fa-solid fa-envelope"></i> ${Translate.instance('email')}`,
106
115
  containerClass: 'inl section-mp width-mini-box input-container',
107
116
  placeholder: true,
108
117
  autocomplete: 'email',
109
118
  })}
110
119
  </div>
111
120
  <div class="in">
112
- ${await Input.Render({
121
+ ${await Input.instance({
113
122
  id: `sign-up-password`,
114
123
  type: 'password',
115
124
  autocomplete: 'new-password',
116
- label: html`<i class="fa-solid fa-lock"></i> ${Translate.Render('password')}`,
125
+ label: html`<i class="fa-solid fa-lock"></i> ${Translate.instance('password')}`,
117
126
  containerClass: 'inl section-mp width-mini-box input-container',
118
127
  placeholder: true,
119
128
  })}
120
129
  </div>
121
130
  <div class="in">
122
- ${await Input.Render({
131
+ ${await Input.instance({
123
132
  id: `sign-up-repeat-password`,
124
133
  type: 'password',
125
134
  autocomplete: 'new-password',
126
- label: html`<i class="fa-solid fa-lock"></i> ${Translate.Render('repeat')} ${Translate.Render('password')}`,
135
+ label: html`<i class="fa-solid fa-lock"></i> ${Translate.instance('repeat')}
136
+ ${Translate.instance('password')}`,
127
137
  containerClass: 'inl section-mp width-mini-box input-container',
128
138
  placeholder: true,
129
139
  })}
130
140
  </div>
131
141
  ${options?.bottomRender ? await options.bottomRender() : ``}
132
142
  <div class="in">
133
- ${await BtnIcon.Render({
143
+ ${await BtnIcon.instance({
134
144
  class: 'in section-mp form-button btn-sign-up',
135
- label: Translate.Render('sign-up'),
145
+ label: Translate.instance('sign-up'),
136
146
  type: 'submit',
137
147
  })}
138
148
  </div>
139
149
  </form>
140
150
  `;
141
- },
142
- };
143
-
151
+ }
152
+ }
144
153
  export { SignUp };
@@ -6,6 +6,7 @@
6
6
  * @namespace SocketIoProvider
7
7
  */
8
8
  import { io } from 'socket.io/client-dist/socket.io.esm.min.js';
9
+ import { SocketEventType, socketEvents } from './ClientEvents.js';
9
10
  import { loggerFactory } from './Logger.js';
10
11
  import { getWsBasePath, getWsBaseUrl } from '../../services/core/core.service.js';
11
12
 
@@ -46,6 +47,30 @@ class SocketIoProvider {
46
47
  * @type {string|undefined}
47
48
  */
48
49
  static host;
50
+ static onConnect(listener, options = {}) {
51
+ return socketEvents.on(SocketEventType.connect, listener, options);
52
+ }
53
+ static offConnect(key) {
54
+ return socketEvents.off(key);
55
+ }
56
+ static onConnectError(listener, options = {}) {
57
+ return socketEvents.on(SocketEventType.connectError, listener, options);
58
+ }
59
+ static offConnectError(key) {
60
+ return socketEvents.off(key);
61
+ }
62
+ static onDisconnect(listener, options = {}) {
63
+ return socketEvents.on(SocketEventType.disconnect, listener, options);
64
+ }
65
+ static offDisconnect(key) {
66
+ return socketEvents.off(key);
67
+ }
68
+ static onChannel(type, listener, options = {}) {
69
+ return socketEvents.on(SocketEventType.channel(type), listener, options);
70
+ }
71
+ static offChannel(key) {
72
+ return socketEvents.off(key);
73
+ }
49
74
 
50
75
  /**
51
76
  * Emits a JSON-serialized payload to the server on the specified channel.
@@ -75,7 +100,7 @@ class SocketIoProvider {
75
100
  * @param {Object.<string, Object>} [options.channels] - Channel definitions to register listeners for.
76
101
  * @returns {Promise<void>}
77
102
  */
78
- static async Init(options) {
103
+ static async instance(options) {
79
104
  if (this.socket) this.socket.disconnect();
80
105
  const path = getWsBasePath();
81
106
  this.host = options.host ? options.host : getWsBaseUrl({ wsBasePath: '' });
@@ -93,16 +118,19 @@ class SocketIoProvider {
93
118
 
94
119
  this.socket.on('connect', () => {
95
120
  logger.info(`event: connect | session id: ${this.socket.id}`);
121
+ socketEvents.emit(SocketEventType.connect, { id: this.socket.id });
96
122
  Object.keys(this.Event.connect).map((keyEvent) => this.Event.connect[keyEvent]());
97
123
  });
98
124
 
99
125
  this.socket.on('connect_error', (err) => {
100
126
  logger.info(`event: connect_error | reason: ${err.message}`);
127
+ socketEvents.emit(SocketEventType.connectError, { error: err });
101
128
  Object.keys(this.Event.connect_error).map((keyEvent) => this.Event.connect_error[keyEvent](err));
102
129
  });
103
130
 
104
131
  this.socket.on('disconnect', (reason) => {
105
132
  logger.info(`event: disconnect | reason: ${reason}`);
133
+ socketEvents.emit(SocketEventType.disconnect, { reason });
106
134
  Object.keys(this.Event.disconnect).map((keyEvent) => this.Event.disconnect[keyEvent](reason));
107
135
  });
108
136
 
@@ -120,8 +148,9 @@ class SocketIoProvider {
120
148
  static setChannels(channels) {
121
149
  Object.keys(channels).map((type) => {
122
150
  logger.info(`load chanel`, type);
123
- this.Event[type] = {};
151
+ if (!this.Event[type]) this.Event[type] = {};
124
152
  this.socket.on(type, (...args) => {
153
+ socketEvents.emit(SocketEventType.channel(type), { type, args });
125
154
  Object.keys(this.Event[type]).map((keyEvent) => this.Event[type][keyEvent](args));
126
155
  });
127
156
  });
@@ -28,14 +28,14 @@ class SocketIoHandlerProvider {
28
28
  *
29
29
  * @static
30
30
  * @param {import('./AppStore.js').AppStore} appStore - The app-specific AppStore instance.
31
- * @returns {{ Init: function(): Promise<void> }} An object with an `Init` method for SocketIo event registration.
31
+ * @returns {{ instance: function(): Promise<void> }} An object with an `instance` method for SocketIo event registration.
32
32
  */
33
33
  static create(appStore) {
34
34
  return {
35
- Init() {
35
+ instance() {
36
36
  return new Promise((resolve) => {
37
37
  for (const type of Object.keys(appStore.Data)) {
38
- SocketIo.Event[type][s4()] = async (args) => {
38
+ SocketIo.onChannel(type, async ({ args }) => {
39
39
  args = JSON.parse(args[0]);
40
40
  switch (type) {
41
41
  case 'chat':
@@ -61,10 +61,10 @@ class SocketIoHandlerProvider {
61
61
  default:
62
62
  break;
63
63
  }
64
- };
64
+ }, { key: s4() });
65
65
  }
66
- SocketIo.Event.connect[s4()] = async (reason) => {};
67
- SocketIo.Event.disconnect[s4()] = async (reason) => {};
66
+ SocketIo.onConnect(async ({ id }) => {}, { key: s4() });
67
+ SocketIo.onDisconnect(async ({ reason }) => {}, { key: s4() });
68
68
  return resolve();
69
69
  });
70
70
  },