underpost 2.8.884 → 2.8.886

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 (82) hide show
  1. package/.env.production +3 -0
  2. package/.github/workflows/ghpkg.ci.yml +1 -1
  3. package/.github/workflows/npmpkg.ci.yml +1 -1
  4. package/.github/workflows/publish.ci.yml +5 -5
  5. package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -1
  6. package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
  7. package/CHANGELOG.md +145 -1
  8. package/Dockerfile +1 -1
  9. package/README.md +5 -121
  10. package/bin/build.js +18 -9
  11. package/bin/deploy.js +102 -197
  12. package/bin/file.js +4 -6
  13. package/cli.md +16 -12
  14. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  15. package/manifests/deployment/dd-test-development/deployment.yaml +54 -54
  16. package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
  17. package/manifests/lxd/underpost-setup.sh +5 -5
  18. package/package.json +3 -3
  19. package/scripts/ssl.sh +164 -0
  20. package/src/cli/baremetal.js +7 -7
  21. package/src/cli/cloud-init.js +1 -1
  22. package/src/cli/cluster.js +31 -3
  23. package/src/cli/cron.js +9 -1
  24. package/src/cli/db.js +64 -2
  25. package/src/cli/deploy.js +189 -4
  26. package/src/cli/env.js +43 -0
  27. package/src/cli/fs.js +96 -2
  28. package/src/cli/image.js +15 -0
  29. package/src/cli/index.js +17 -4
  30. package/src/cli/monitor.js +33 -2
  31. package/src/cli/repository.js +95 -2
  32. package/src/cli/run.js +315 -51
  33. package/src/cli/script.js +32 -0
  34. package/src/cli/secrets.js +34 -0
  35. package/src/cli/test.js +42 -1
  36. package/src/client/components/core/Css.js +16 -8
  37. package/src/client/components/core/Docs.js +5 -13
  38. package/src/client/components/core/Modal.js +48 -29
  39. package/src/client/components/core/Router.js +6 -3
  40. package/src/client/components/core/Worker.js +205 -118
  41. package/src/client/components/core/windowGetDimensions.js +229 -162
  42. package/src/client/components/default/MenuDefault.js +1 -0
  43. package/src/client.dev.js +6 -3
  44. package/src/db/DataBaseProvider.js +65 -12
  45. package/src/db/mariadb/MariaDB.js +39 -6
  46. package/src/db/mongo/MongooseDB.js +51 -133
  47. package/src/index.js +2 -2
  48. package/src/mailer/EmailRender.js +58 -9
  49. package/src/mailer/MailerProvider.js +99 -25
  50. package/src/runtime/express/Express.js +32 -38
  51. package/src/runtime/lampp/Dockerfile +1 -1
  52. package/src/server/auth.js +9 -28
  53. package/src/server/backup.js +20 -0
  54. package/src/server/client-build-live.js +23 -12
  55. package/src/server/client-build.js +136 -91
  56. package/src/server/client-dev-server.js +35 -8
  57. package/src/server/client-icons.js +19 -0
  58. package/src/server/conf.js +543 -80
  59. package/src/server/dns.js +184 -42
  60. package/src/server/downloader.js +65 -24
  61. package/src/server/object-layer.js +260 -162
  62. package/src/server/peer.js +3 -9
  63. package/src/server/proxy.js +93 -76
  64. package/src/server/runtime.js +15 -21
  65. package/src/server/ssr.js +4 -4
  66. package/src/server/start.js +39 -0
  67. package/src/server/tls.js +251 -0
  68. package/src/server/valkey.js +11 -10
  69. package/src/ws/IoInterface.js +133 -39
  70. package/src/ws/IoServer.js +80 -31
  71. package/src/ws/core/core.ws.connection.js +50 -16
  72. package/src/ws/core/core.ws.emit.js +47 -8
  73. package/src/ws/core/core.ws.server.js +62 -10
  74. package/manifests/maas/lxd-preseed.yaml +0 -32
  75. package/src/server/ssl.js +0 -108
  76. /package/{manifests/maas → scripts}/device-scan.sh +0 -0
  77. /package/{manifests/maas → scripts}/gpu-diag.sh +0 -0
  78. /package/{manifests/maas → scripts}/maas-setup.sh +0 -0
  79. /package/{manifests/maas → scripts}/nat-iptables.sh +0 -0
  80. /package/{manifests/maas → scripts}/nvim.sh +0 -0
  81. /package/{manifests/maas → scripts}/snap-clean.sh +0 -0
  82. /package/{manifests/maas → scripts}/ssh-cluster-info.sh +0 -0
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Utility class for managing Progressive Web App (PWA) worker functionalities,
3
+ * including service worker registration, caching, and notification management.
4
+ * This class is designed to be used as a singleton instance (exported as 'Worker').
5
+ * @module src/client/components/core/Worker.js
6
+ * @namespace PwaWorker
7
+ */
8
+
1
9
  import { BtnIcon } from './BtnIcon.js';
2
10
  import { s4 } from './CommonJs.js';
3
11
  import { EventsUI } from './EventsUI.js';
@@ -9,11 +17,64 @@ import { s } from './VanillaJs.js';
9
17
  import { getProxyPath } from './Router.js';
10
18
  const logger = loggerFactory(import.meta);
11
19
 
12
- const Worker = {
13
- devMode: () => location.origin.match('localhost') || location.origin.match('127.0.0.1'),
14
- instance: async function ({ router, render }) {
15
- Worker.title = `${s('title').textContent}`;
16
- // logger.warn('Init worker', Worker.title);
20
+ /**
21
+ * Manages the PWA lifecycle, service workers, and related client-side events.
22
+ * @memberof PwaWorker
23
+ */
24
+ class PwaWorker {
25
+ /**
26
+ * The application title, usually from the <title> tag content.
27
+ * @type {string}
28
+ */
29
+ title = '';
30
+
31
+ /**
32
+ * Tracks if notification permission has been granted and is active.
33
+ * @type {boolean}
34
+ */
35
+ notificationActive = false;
36
+
37
+ /**
38
+ * A function reference to the service worker's update method (registration.update()),
39
+ * dynamically set upon successful registration status check.
40
+ * @type {function(): Promise<void>}
41
+ */
42
+ updateServiceWorker = async () => {};
43
+
44
+ /**
45
+ * Router instance reference, initialized during the `instance` call.
46
+ * @type {object | null}
47
+ */
48
+ RouterInstance = null;
49
+
50
+ /**
51
+ * Creates an instance of PwaWorker and initializes the application title.
52
+ * @memberof PwaWorker
53
+ */
54
+ constructor() {
55
+ this.title = `${s('title').textContent}`;
56
+ }
57
+
58
+ /**
59
+ * Checks if the application is running in development mode (localhost or 127.0.0.1).
60
+ * @memberof PwaWorker
61
+ * @returns {boolean} True if in development mode.
62
+ */
63
+ devMode() {
64
+ return location.origin.match('localhost') || location.origin.match('127.0.0.1');
65
+ }
66
+
67
+ /**
68
+ * Initializes the PWA worker, registers global/worker event listeners,
69
+ * checks service worker status, and renders the initial content.
70
+ * This is the main entry point for the worker setup.
71
+ * @memberof PwaWorker
72
+ * @param {object} options - Configuration options.
73
+ * @param {function(): object} options.router - Function to get the router instance.
74
+ * @param {function(): Promise<void>} options.render - Function to render the application's UI.
75
+ * @returns {Promise<void>}
76
+ */
77
+ async instance({ router, render }) {
17
78
  window.ononline = async () => {
18
79
  logger.warn('ononline');
19
80
  };
@@ -23,13 +84,15 @@ const Worker = {
23
84
  setTimeout(() => {
24
85
  if ('onLine' in navigator && navigator.onLine) window.ononline();
25
86
  });
87
+
26
88
  if ('serviceWorker' in navigator) {
27
89
  navigator.serviceWorker.addEventListener('controllerchange', () => {
28
90
  logger.info('The controller of current browsing context has changed.');
29
91
  });
30
92
  navigator.serviceWorker.ready.then((worker) => {
31
- logger.info('Ready', worker);
32
- // event message
93
+ logger.info('Service Worker Ready', worker);
94
+
95
+ // event message listener
33
96
  navigator.serviceWorker.addEventListener('message', (event) => {
34
97
  logger.info('Received event message', event.data);
35
98
  const { status } = event.data;
@@ -68,36 +131,53 @@ const Worker = {
68
131
  LoadRouter(this.RouterInstance);
69
132
  LoadingAnimation.removeSplashScreen();
70
133
  if (this.devMode()) {
71
- const delayLiveReload = 1250;
72
- // Dev mode
73
-
74
- window.addEventListener('visibilitychange', (event) => {
75
- // if (document.visibilityState === 'visible') {
76
- // Worker.reload(delayLiveReload);
77
- // }
78
- });
79
- window.addEventListener('focus', function () {
80
- // Worker.reload(delayLiveReload);
81
- });
134
+ // const delayLiveReload = 1250;
135
+ // window.addEventListener('visibilitychange', () => {
136
+ // if (document.visibilityState === 'visible') {
137
+ // this.reload(delayLiveReload);
138
+ // }
139
+ // });
140
+ // window.addEventListener('focus', () => {
141
+ // this.reload(delayLiveReload);
142
+ // });
82
143
  }
83
144
  window.serviceWorkerReady = true;
84
- },
145
+ }
146
+
147
+ /**
148
+ * Gets the current service worker registration.
149
+ * @memberof PwaWorker
150
+ * @returns {Promise<ServiceWorkerRegistration | undefined>} The service worker registration object, or undefined.
151
+ */
152
+ async getRegistration() {
153
+ return navigator.serviceWorker.getRegistration();
154
+ }
85
155
 
86
- // Get the current service worker registration.
87
- getRegistration: async function () {
88
- return await navigator.serviceWorker.getRegistration();
89
- },
90
- reload: async function (timeOut = 3000) {
91
- return await new Promise((resolve) => {
92
- if (navigator.serviceWorker && navigator.serviceWorker.controller)
156
+ /**
157
+ * Forces the current service worker to skip waiting and reloads the page
158
+ * to apply the new service worker immediately.
159
+ * @memberof PwaWorker
160
+ * @param {number} [timeOut=3000] - Delay in milliseconds before reloading the page.
161
+ * @returns {Promise<void>} A promise that resolves after the page is reloaded.
162
+ */
163
+ async reload(timeOut = 3000) {
164
+ return new Promise((resolve) => {
165
+ if (navigator.serviceWorker && navigator.serviceWorker.controller) {
93
166
  navigator.serviceWorker.controller.postMessage({
94
167
  status: 'skipWaiting',
95
168
  });
96
- // (location.href = `${location.origin}${location.pathname}${location.search}`)
169
+ }
97
170
  setTimeout(() => resolve(location.reload()), timeOut);
98
171
  });
99
- },
100
- update: async function () {
172
+ }
173
+
174
+ /**
175
+ * Updates the application by clearing specific caches and running the service worker update logic.
176
+ * Cache names matching 'components/', 'services/', or '.index.js' are deleted.
177
+ * @memberof PwaWorker
178
+ * @returns {Promise<void>}
179
+ */
180
+ async update() {
101
181
  const isInstall = await this.status();
102
182
  if (isInstall) {
103
183
  const cacheNames = await caches.keys();
@@ -108,11 +188,17 @@ const Worker = {
108
188
  }
109
189
  await this.updateServiceWorker();
110
190
  }
111
- },
112
- updateServiceWorker: async function () {},
113
- status: function () {
191
+ }
192
+
193
+ /**
194
+ * Checks the current status of all service worker registrations and sets the
195
+ * `updateServiceWorker` function reference if an active worker is found.
196
+ * @memberof PwaWorker
197
+ * @returns {Promise<boolean>} True if at least one service worker is registered.
198
+ */
199
+ status() {
114
200
  let status = false;
115
- return new Promise((resolve, reject) => {
201
+ return new Promise((resolve) => {
116
202
  if ('serviceWorker' in navigator) {
117
203
  navigator.serviceWorker
118
204
  .getRegistrations()
@@ -122,81 +208,87 @@ const Worker = {
122
208
  else if (registration.waiting) logger.info('waiting', registration);
123
209
  else if (registration.active) {
124
210
  logger.info('active', registration);
211
+ // Dynamically set the update function
125
212
  this.updateServiceWorker = async () => await registration.update();
126
213
  }
127
214
  }
128
215
  if (registrations.length > 0) status = true;
216
+ resolve(status);
129
217
  })
130
218
  .catch((...args) => {
131
- logger.error(...args);
132
- return resolve(false);
133
- })
134
- .finally((...args) => {
135
- logger.info('Finally status', args);
136
- return resolve(status);
219
+ logger.error('Error getting service worker registrations:', ...args);
220
+ resolve(false);
137
221
  });
138
222
  } else {
139
- logger.warn('Disabled');
140
- return resolve(false);
223
+ logger.warn('Service Worker Disabled in browser');
224
+ resolve(false);
141
225
  }
142
226
  });
143
- },
144
- install: function () {
145
- return new Promise((resolve, reject) => {
227
+ }
228
+
229
+ /**
230
+ * Registers the service worker (`sw.js`) with the browser.
231
+ * @memberof PwaWorker
232
+ * @returns {Promise<Array<any>>} A promise that resolves with the registration arguments.
233
+ */
234
+ install() {
235
+ return new Promise((resolve) => {
146
236
  if ('serviceWorker' in navigator) {
147
237
  navigator.serviceWorker
148
238
  .register(`${getProxyPath()}sw.js`, {
149
- // scope: getProxyPath(),
150
- // scope: '/',
151
239
  type: 'module',
152
240
  })
153
241
  .then((...args) => {
154
- logger.warn('Already Registered', args);
242
+ logger.warn('Service Worker Registered', args);
243
+ resolve(args);
155
244
  })
156
245
  .catch((...args) => {
157
- logger.error(...args);
158
- return resolve(args);
159
- })
160
- .finally((...args) => {
161
- logger.info('Finally install', args);
162
- return resolve(args);
246
+ logger.error('Error registering service worker:', ...args);
247
+ resolve(args);
163
248
  });
164
249
  } else {
165
- logger.warn('Disabled');
166
- return resolve();
250
+ logger.warn('Service Worker Disabled in browser');
251
+ resolve([]);
167
252
  }
168
253
  });
169
- },
170
- uninstall: function () {
171
- return new Promise(async (resolve, reject) => {
254
+ }
255
+
256
+ /**
257
+ * Unregisters all service workers and deletes all application caches.
258
+ * @memberof PwaWorker
259
+ * @returns {Promise<Array<any>>} A promise that resolves after uninstallation.
260
+ */
261
+ uninstall() {
262
+ return new Promise(async (resolve) => {
172
263
  if ('serviceWorker' in navigator) {
173
- navigator.serviceWorker
174
- .getRegistrations()
175
- .then(async (registrations) => {
176
- const cacheNames = await caches.keys();
177
- for (const cacheName of cacheNames) await caches.delete(cacheName);
178
- for (const registration of registrations) {
179
- logger.info('remove', registration);
180
- registration.unregister();
181
- }
182
- })
183
- .catch((...args) => {
184
- logger.error(...args);
185
- return resolve(args);
186
- })
187
- .finally((...args) => {
188
- logger.info('Finally uninstall', args);
189
- return resolve(args);
190
- });
264
+ try {
265
+ const registrations = await navigator.serviceWorker.getRegistrations();
266
+ const cacheNames = await caches.keys();
267
+ for (const cacheName of cacheNames) await caches.delete(cacheName);
268
+ for (const registration of registrations) {
269
+ logger.info('Removing service worker registration', registration);
270
+ registration.unregister();
271
+ }
272
+ resolve([]);
273
+ } catch (error) {
274
+ logger.error('Error during service worker uninstallation:', error);
275
+ resolve([error]);
276
+ }
191
277
  } else {
192
- logger.warn('Disabled');
193
- return resolve();
278
+ logger.warn('Service Worker Disabled in browser');
279
+ resolve([]);
194
280
  }
195
281
  });
196
- },
197
- notificationActive: false,
198
- notificationRequestPermission: function () {
199
- return new Promise((resolve, reject) =>
282
+ }
283
+
284
+ /**
285
+ * Requests permission from the user to display notifications.
286
+ * Sets the internal `notificationActive` state.
287
+ * @memberof PwaWorker
288
+ * @returns {Promise<boolean>} True if permission is granted, false otherwise.
289
+ */
290
+ notificationRequestPermission() {
291
+ return new Promise((resolve) =>
200
292
  Notification.requestPermission().then((result) => {
201
293
  if (result === 'granted') {
202
294
  this.notificationActive = true;
@@ -207,8 +299,14 @@ const Worker = {
207
299
  }
208
300
  }),
209
301
  );
210
- },
211
- notificationShow: function () {
302
+ }
303
+
304
+ /**
305
+ * Shows a sample notification if permission is granted.
306
+ * @memberof PwaWorker
307
+ * @returns {void}
308
+ */
309
+ notificationShow() {
212
310
  Notification.requestPermission().then((result) => {
213
311
  if (result === 'granted') {
214
312
  navigator.serviceWorker.ready.then((registration) => {
@@ -217,18 +315,25 @@ const Worker = {
217
315
  icon: '../images/touch/chrome-touch-icon.png',
218
316
  vibrate: [200, 100, 200, 100, 200, 100, 200],
219
317
  tag: 'vibration-sample',
220
- requireInteraction: true, // boolean to manually close the notification
318
+ requireInteraction: true,
221
319
  });
222
320
  });
223
321
  }
224
322
  });
225
- },
226
- // TODO: GPS management
227
- RenderSetting: async function () {
323
+ }
324
+
325
+ /**
326
+ * Renders the UI for PWA settings, including buttons for cleaning cache and worker management.
327
+ * It also attaches the click handler for the 'clean-cache' button.
328
+ * @memberof PwaWorker
329
+ * @returns {Promise<string>} The HTML string for the settings section.
330
+ */
331
+ async RenderSetting() {
228
332
  setTimeout(() => {
333
+ // Event listener for the clean cache button
229
334
  EventsUI.onClick(`.btn-clean-cache`, async (e) => {
230
335
  e.preventDefault();
231
- // await this.update();
336
+ // Clear local storage, uninstall the worker, and reload
232
337
  localStorage.clear();
233
338
  await this.uninstall();
234
339
  await this.reload();
@@ -252,33 +357,15 @@ const Worker = {
252
357
  label: html`<i class="fas fa-sync-alt"></i> ${Translate.Render('Reload')}`,
253
358
  })}
254
359
  </div>`;
255
- return;
256
- s(`.btn-uninstall-service-controller`).classList.add('hide');
257
- EventsUI.onClick(`.btn-install-service-controller`, async (e) => {
258
- e.preventDefault();
259
- const result = await this.install();
260
- s(`.btn-install-service-controller`).classList.add('hide');
261
- s(`.btn-uninstall-service-controller`).classList.remove('hide');
262
- });
263
- EventsUI.onClick(`.btn-uninstall-service-controller`, async (e) => {
264
- e.preventDefault();
265
- const result = await this.uninstall();
266
- s(`.btn-uninstall-service-controller`).classList.add('hide');
267
- s(`.btn-install-service-controller`).classList.remove('hide');
268
- });
269
- EventsUI.onClick(`.btn-reload`, async (e) => {
270
- e.preventDefault();
271
- location.reload();
272
- });
273
- const workerStatus = await this.status();
274
- if (workerStatus) {
275
- s(`.btn-install-service-controller`).classList.add('hide');
276
- s(`.btn-uninstall-service-controller`).classList.remove('hide');
277
- } else {
278
- s(`.btn-uninstall-service-controller`).classList.add('hide');
279
- s(`.btn-install-service-controller`).classList.remove('hide');
280
- }
281
- },
282
- };
360
+ }
361
+ }
362
+
363
+ // Create the singleton instance
364
+ const PwaWorkerInstance = new PwaWorker();
365
+
366
+ // Export the new class name for modern usage
367
+ export { PwaWorker };
283
368
 
284
- export { Worker };
369
+ // Export the instance with the old name (`Worker`) for backward compatibility,
370
+ // ensuring existing code consuming the module continues to work.
371
+ export { PwaWorkerInstance as Worker };