underpost 3.1.3 → 3.2.0
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.
- package/.env.example +0 -2
- package/.github/workflows/ghpkg.ci.yml +4 -4
- package/.github/workflows/npmpkg.ci.yml +28 -11
- package/.github/workflows/pwa-microservices-template-page.cd.yml +3 -4
- package/.github/workflows/pwa-microservices-template-test.ci.yml +3 -3
- package/.github/workflows/release.cd.yml +4 -4
- package/CHANGELOG.md +324 -1
- package/CLI-HELP.md +49 -3
- package/README.md +3 -2
- package/bin/build.js +18 -12
- package/bin/deploy.js +177 -124
- package/bin/file.js +3 -0
- package/conf.js +3 -2
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +72 -50
- package/manifests/deployment/dd-test-development/proxy.yaml +13 -4
- package/manifests/deployment/playwright/deployment.yaml +1 -1
- package/nodemon.json +1 -1
- package/package.json +22 -15
- package/scripts/rhel-grpc-setup.sh +56 -0
- package/src/api/file/file.ref.json +18 -0
- package/src/api/user/user.service.js +8 -7
- package/src/cli/cluster.js +7 -7
- package/src/cli/db.js +76 -242
- package/src/cli/deploy.js +104 -65
- package/src/cli/env.js +1 -0
- package/src/cli/fs.js +2 -1
- package/src/cli/index.js +42 -1
- package/src/cli/kubectl.js +211 -0
- package/src/cli/release.js +284 -0
- package/src/cli/repository.js +291 -75
- package/src/cli/run.js +188 -33
- package/src/cli/test.js +3 -3
- package/src/client/Default.index.js +3 -4
- package/src/client/components/core/AppStore.js +69 -0
- package/src/client/components/core/CalendarCore.js +2 -2
- package/src/client/components/core/DropDown.js +129 -17
- package/src/client/components/core/Keyboard.js +2 -2
- package/src/client/components/core/LogIn.js +2 -2
- package/src/client/components/core/LogOut.js +2 -2
- package/src/client/components/core/Modal.js +0 -1
- package/src/client/components/core/Panel.js +0 -1
- package/src/client/components/core/PanelForm.js +19 -19
- package/src/client/components/core/SocketIo.js +82 -29
- package/src/client/components/core/SocketIoHandler.js +75 -0
- package/src/client/components/core/Stream.js +143 -95
- package/src/client/components/core/Webhook.js +40 -7
- package/src/client/components/default/AppStoreDefault.js +5 -0
- package/src/client/components/default/LogInDefault.js +3 -3
- package/src/client/components/default/LogOutDefault.js +2 -2
- package/src/client/components/default/MenuDefault.js +5 -5
- package/src/client/components/default/SocketIoDefault.js +3 -51
- package/src/client/services/core/core.service.js +20 -8
- package/src/client/services/user/user.management.js +2 -2
- package/src/index.js +24 -1
- package/src/runtime/express/Express.js +18 -1
- package/src/runtime/lampp/Dockerfile +9 -2
- package/src/runtime/lampp/Lampp.js +4 -3
- package/src/runtime/wp/Dockerfile +64 -0
- package/src/runtime/wp/Wp.js +497 -0
- package/src/server/auth.js +24 -1
- package/src/server/backup.js +19 -1
- package/src/server/client-build-docs.js +9 -2
- package/src/server/client-build.js +31 -31
- package/src/server/client-formatted.js +109 -57
- package/src/server/ipfs-client.js +24 -1
- package/src/server/peer.js +8 -0
- package/src/server/runtime.js +25 -1
- package/src/server/start.js +6 -0
- package/src/ws/IoInterface.js +1 -10
- package/src/ws/IoServer.js +14 -33
- package/src/ws/core/channels/core.ws.chat.js +65 -20
- package/src/ws/core/channels/core.ws.mailer.js +113 -32
- package/src/ws/core/channels/core.ws.stream.js +90 -31
- package/src/ws/core/core.ws.connection.js +12 -33
- package/src/ws/core/core.ws.emit.js +10 -26
- package/src/ws/core/core.ws.server.js +25 -58
- package/src/ws/default/channels/default.ws.main.js +53 -12
- package/src/ws/default/default.ws.connection.js +26 -13
- package/src/ws/default/default.ws.server.js +30 -12
- package/src/client/components/default/ElementsDefault.js +0 -38
- package/src/ws/core/management/core.ws.chat.js +0 -8
- package/src/ws/core/management/core.ws.mailer.js +0 -16
- package/src/ws/core/management/core.ws.stream.js +0 -8
- package/src/ws/default/management/default.ws.main.js +0 -8
|
@@ -1,113 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side WebRTC stream manager backed by PeerJS.
|
|
3
|
+
* Handles peer creation, media capture, and room-based A/V streaming.
|
|
4
|
+
*
|
|
5
|
+
* @module client/core/Stream
|
|
6
|
+
* @see https://peerjs.com/docs/
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import { loggerFactory } from './Logger.js';
|
|
2
10
|
import { getProxyPath } from './Router.js';
|
|
3
11
|
|
|
4
|
-
// https://peerjs.com/docs/
|
|
5
|
-
|
|
6
12
|
const logger = loggerFactory(import.meta);
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
/**
|
|
15
|
+
* @class Stream
|
|
16
|
+
* @classdesc Static manager for PeerJS connections and MediaStream lifecycle.
|
|
17
|
+
* Supports multiple concurrent peer sessions keyed by an arbitrary `id`.
|
|
18
|
+
*/
|
|
19
|
+
class Stream {
|
|
20
|
+
/** @type {Object.<string, { peer: Peer, options: Object }>} Active peer sessions keyed by session id. */
|
|
21
|
+
static #sessions = {};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Builds PeerJS connection options from current page location.
|
|
25
|
+
* @returns {{ host: string, port: number, path: string, secure: boolean }}
|
|
26
|
+
*/
|
|
27
|
+
static #buildPeerOptions() {
|
|
28
|
+
return {
|
|
29
|
+
host: location.hostname,
|
|
13
30
|
port: location.protocol === 'https:' ? 443 : location.port ? parseInt(location.port) + 1 : 80,
|
|
14
31
|
path: `${getProxyPath()}peer`,
|
|
15
32
|
secure: location.protocol === 'https:',
|
|
16
33
|
};
|
|
17
|
-
|
|
18
|
-
this.Data[id] = {
|
|
19
|
-
peer: {
|
|
20
|
-
peerOptions,
|
|
21
|
-
server: new Peer(undefined, peerOptions),
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
return this.Data[id].peer;
|
|
25
|
-
},
|
|
26
|
-
connectToNewUser: function (
|
|
27
|
-
mediaType,
|
|
28
|
-
id,
|
|
29
|
-
userId,
|
|
30
|
-
stream,
|
|
31
|
-
onConnectStream = (mediaElement) => null,
|
|
32
|
-
onDisconnectStream = (mediaElement) => null,
|
|
33
|
-
) {
|
|
34
|
-
// This runs when someone joins our room
|
|
35
|
-
const call = this.Data[id].peer.server.call(userId, stream); // Call the user who just joined
|
|
36
|
-
const mediaElement = this.createMediaElement(mediaType);
|
|
34
|
+
}
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Creates a PeerJS client for the given session id.
|
|
38
|
+
* @param {string} id - Unique session identifier.
|
|
39
|
+
* @returns {{ peer: Peer, options: Object }} The Peer instance and its options.
|
|
40
|
+
*/
|
|
41
|
+
static createPeer(id) {
|
|
42
|
+
this.destroyPeer(id);
|
|
43
|
+
const options = this.#buildPeerOptions();
|
|
44
|
+
logger.info('peerOptions', options);
|
|
45
|
+
const peer = new Peer(undefined, options);
|
|
46
|
+
this.#sessions[id] = { peer, options };
|
|
47
|
+
return this.#sessions[id];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Returns an existing session or `undefined`.
|
|
52
|
+
* @param {string} id
|
|
53
|
+
* @returns {{ peer: Peer, options: Object }|undefined}
|
|
54
|
+
*/
|
|
55
|
+
static getSession(id) {
|
|
56
|
+
return this.#sessions[id];
|
|
57
|
+
}
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Destroys a peer session — closes all connections and the peer itself.
|
|
61
|
+
* @param {string} id - Session identifier.
|
|
62
|
+
*/
|
|
63
|
+
static destroyPeer(id) {
|
|
64
|
+
const session = this.#sessions[id];
|
|
65
|
+
if (!session) return;
|
|
66
|
+
const { peer } = session;
|
|
67
|
+
if (peer) {
|
|
68
|
+
for (const key in peer.connections) {
|
|
69
|
+
for (const conn of peer.connections[key]) {
|
|
70
|
+
if (conn.peerConnection?.close) conn.peerConnection.close();
|
|
71
|
+
if (conn.close) conn.close();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (!peer.destroyed) peer.destroy();
|
|
57
75
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
.then((stream) => resolve(stream))
|
|
80
|
-
.catch((error) => {
|
|
81
|
-
logger.error(error);
|
|
82
|
-
resolve(undefined);
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
},
|
|
86
|
-
removeMediaStream: function (stream) {
|
|
87
|
-
// later you can do below
|
|
88
|
-
// stop both video and audio
|
|
89
|
-
stream.getTracks().forEach((track) => {
|
|
90
|
-
track.stop();
|
|
76
|
+
delete this.#sessions[id];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Calls a remote peer and streams local media to them.
|
|
81
|
+
* @param {string} id - Session identifier.
|
|
82
|
+
* @param {string} remotePeerId - The remote peer's ID.
|
|
83
|
+
* @param {MediaStream} localStream - Local media stream to send.
|
|
84
|
+
* @param {Object} [callbacks]
|
|
85
|
+
* @param {function(HTMLMediaElement): void} [callbacks.onStream] - Called when remote stream arrives.
|
|
86
|
+
* @param {function(HTMLMediaElement): void} [callbacks.onClose] - Called when the call closes.
|
|
87
|
+
* @returns {{ call: import('peerjs').MediaConnection, element: HTMLVideoElement }}
|
|
88
|
+
*/
|
|
89
|
+
static callPeer(id, remotePeerId, localStream, { onStream, onClose } = {}) {
|
|
90
|
+
const session = this.#sessions[id];
|
|
91
|
+
if (!session) throw new Error(`No peer session "${id}"`);
|
|
92
|
+
const call = session.peer.call(remotePeerId, localStream);
|
|
93
|
+
const element = this.createVideoElement();
|
|
94
|
+
call.on('stream', (remoteStream) => {
|
|
95
|
+
this.attachStream(element, remoteStream);
|
|
96
|
+
onStream?.(element);
|
|
91
97
|
});
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
createMediaElement: function (mediaType) {
|
|
98
|
-
let mediaElement;
|
|
99
|
-
switch (mediaType) {
|
|
100
|
-
case 'audio-video':
|
|
101
|
-
mediaElement = document.createElement('video'); // Create a new audio/video tag to show our audio/video
|
|
102
|
-
// mediaElement.muted = true; // Mute ourselves on our end so there is no feedback loop
|
|
98
|
+
call.on('close', () => onClose?.(element));
|
|
99
|
+
return { call, element };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ── Media helpers ────────────────────────────────────────────────
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Requests user media (camera / microphone) with graceful fallback.
|
|
106
|
+
* Falls back to video-only if audio is unavailable (NotReadableError).
|
|
107
|
+
* @param {{ video?: boolean|MediaTrackConstraints, audio?: boolean|MediaTrackConstraints }} [constraints]
|
|
108
|
+
* @returns {Promise<MediaStream|undefined>}
|
|
109
|
+
*/
|
|
110
|
+
static async getMediaStream(constraints = { video: true, audio: true }) {
|
|
111
|
+
const fallbacks = [
|
|
112
|
+
constraints,
|
|
113
|
+
constraints.audio ? { video: constraints.video, audio: false } : null,
|
|
114
|
+
constraints.video ? { video: false, audio: constraints.audio } : null,
|
|
115
|
+
].filter(Boolean);
|
|
105
116
|
|
|
106
|
-
|
|
107
|
-
|
|
117
|
+
for (const c of fallbacks) {
|
|
118
|
+
try {
|
|
119
|
+
return await navigator.mediaDevices.getUserMedia(c);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
logger.warn(`getUserMedia failed (${err.name}): ${err.message}`, c);
|
|
122
|
+
}
|
|
108
123
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
124
|
+
logger.error('All media capture attempts failed');
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Stops all tracks of a MediaStream.
|
|
130
|
+
* @param {MediaStream} stream
|
|
131
|
+
*/
|
|
132
|
+
static stopStream(stream) {
|
|
133
|
+
if (!stream) return;
|
|
134
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Creates a `<video>` element pre-configured for inline autoplay.
|
|
139
|
+
* @returns {HTMLVideoElement}
|
|
140
|
+
*/
|
|
141
|
+
static createVideoElement() {
|
|
142
|
+
const video = document.createElement('video');
|
|
143
|
+
video.playsInline = true;
|
|
144
|
+
video.autoplay = true;
|
|
145
|
+
return video;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Attaches a MediaStream to a media element and starts playback.
|
|
150
|
+
* @param {HTMLMediaElement} element
|
|
151
|
+
* @param {MediaStream} stream
|
|
152
|
+
* @returns {HTMLMediaElement}
|
|
153
|
+
*/
|
|
154
|
+
static attachStream(element, stream) {
|
|
155
|
+
element.srcObject = stream;
|
|
156
|
+
element.addEventListener('loadedmetadata', () => element.play());
|
|
157
|
+
return element;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
112
160
|
|
|
113
161
|
export { Stream };
|
|
@@ -1,7 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket session registration bridge.
|
|
3
|
+
* Registers and unregisters the authenticated user's identity with the server-side
|
|
4
|
+
* WebSocket management layer, enabling targeted real-time pushes (e.g. email confirmation).
|
|
5
|
+
*
|
|
6
|
+
* @module client/core/Webhook
|
|
7
|
+
* @namespace WebhookProvider
|
|
8
|
+
*/
|
|
1
9
|
import { SocketIo } from './SocketIo.js';
|
|
2
10
|
|
|
3
|
-
|
|
4
|
-
|
|
11
|
+
/**
|
|
12
|
+
* @class WebhookProvider
|
|
13
|
+
* @classdesc Provides static methods to register/unregister the authenticated user
|
|
14
|
+
* with the server-side WebSocket session management channels.
|
|
15
|
+
* @memberof WebhookProvider
|
|
16
|
+
*/
|
|
17
|
+
class WebhookProvider {
|
|
18
|
+
/**
|
|
19
|
+
* Registers the authenticated user with the server-side WebSocket channels.
|
|
20
|
+
* Creates a user↔socket mapping on the server, enabling targeted events.
|
|
21
|
+
*
|
|
22
|
+
* @static
|
|
23
|
+
* @async
|
|
24
|
+
* @param {Object} options - Registration options.
|
|
25
|
+
* @param {Object} options.user - The authenticated user object to register.
|
|
26
|
+
* @returns {Promise<void>}
|
|
27
|
+
*/
|
|
28
|
+
static async register(options = { user: {} }) {
|
|
5
29
|
const { user } = options;
|
|
6
30
|
SocketIo.Emit('mailer', {
|
|
7
31
|
status: 'register-user',
|
|
@@ -11,15 +35,24 @@ const Webhook = {
|
|
|
11
35
|
status: 'register-user',
|
|
12
36
|
user,
|
|
13
37
|
});
|
|
14
|
-
}
|
|
15
|
-
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Unregisters the current user from server-side WebSocket channels.
|
|
42
|
+
* Cleans up the user↔socket mapping on the server.
|
|
43
|
+
*
|
|
44
|
+
* @static
|
|
45
|
+
* @async
|
|
46
|
+
* @returns {Promise<void>}
|
|
47
|
+
*/
|
|
48
|
+
static async unregister() {
|
|
16
49
|
SocketIo.Emit('mailer', {
|
|
17
50
|
status: 'unregister-user',
|
|
18
51
|
});
|
|
19
52
|
SocketIo.Emit('user', {
|
|
20
53
|
status: 'unregister-user',
|
|
21
54
|
});
|
|
22
|
-
}
|
|
23
|
-
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
24
57
|
|
|
25
|
-
export {
|
|
58
|
+
export { WebhookProvider };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Auth } from '../core/Auth.js';
|
|
2
2
|
import { LogIn } from '../core/LogIn.js';
|
|
3
|
-
import {
|
|
3
|
+
import { AppStoreDefault } from './AppStoreDefault.js';
|
|
4
4
|
|
|
5
5
|
const LogInDefault = async function () {
|
|
6
6
|
LogIn.Event['LogInDefault'] = async (options) => {
|
|
7
7
|
const { token, user } = options;
|
|
8
|
-
|
|
8
|
+
AppStoreDefault.Data.user.main.model.user = user;
|
|
9
9
|
};
|
|
10
10
|
const { user } = await Auth.sessionIn();
|
|
11
|
-
|
|
11
|
+
AppStoreDefault.Data.user.main.model.user = user;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export { LogInDefault };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { LogOut } from '../core/LogOut.js';
|
|
2
|
-
import {
|
|
2
|
+
import { AppStoreDefault } from './AppStoreDefault.js';
|
|
3
3
|
|
|
4
4
|
const LogOutDefault = async function () {
|
|
5
5
|
LogOut.Event['LogOutDefault'] = async (result = { user: { _id: '' } }) => {
|
|
6
|
-
|
|
6
|
+
AppStoreDefault.Data.user.main.model.user = result.user;
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
9
|
|
|
@@ -10,7 +10,7 @@ import { SignUp } from '../core/SignUp.js';
|
|
|
10
10
|
import { Translate } from '../core/Translate.js';
|
|
11
11
|
import { htmls, s } from '../core/VanillaJs.js';
|
|
12
12
|
import { extractUsernameFromPath, getProxyPath, getQueryParams } from '../core/Router.js';
|
|
13
|
-
import {
|
|
13
|
+
import { AppStoreDefault } from './AppStoreDefault.js';
|
|
14
14
|
import Sortable from 'sortablejs';
|
|
15
15
|
import { RouterDefault, BannerAppTemplate } from './RoutesDefault.js';
|
|
16
16
|
import { SettingsDefault } from './SettingsDefault.js';
|
|
@@ -551,7 +551,7 @@ const MenuDefault = {
|
|
|
551
551
|
html: async () =>
|
|
552
552
|
await Account.Render({
|
|
553
553
|
idModal: 'modal-account',
|
|
554
|
-
user:
|
|
554
|
+
user: AppStoreDefault.Data.user.main.model.user,
|
|
555
555
|
disabled: [],
|
|
556
556
|
}),
|
|
557
557
|
handleType: 'bar',
|
|
@@ -565,7 +565,7 @@ const MenuDefault = {
|
|
|
565
565
|
EventsUI.onClick(`.main-btn-public-profile`, async () => {
|
|
566
566
|
const { barConfig } = await Themes[Css.currentTheme]();
|
|
567
567
|
const idModal = 'modal-public-profile';
|
|
568
|
-
const user =
|
|
568
|
+
const user = AppStoreDefault.Data.user.main.model.user;
|
|
569
569
|
|
|
570
570
|
// Check if modal already exists
|
|
571
571
|
const existingModal = s(`.${idModal}`);
|
|
@@ -635,7 +635,7 @@ const MenuDefault = {
|
|
|
635
635
|
text: Translate.Render('recover'),
|
|
636
636
|
}),
|
|
637
637
|
html: async () =>
|
|
638
|
-
await Recover.Render({ idModal: 'modal-recover', user:
|
|
638
|
+
await Recover.Render({ idModal: 'modal-recover', user: AppStoreDefault.Data.user.main.model.user }),
|
|
639
639
|
handleType: 'bar',
|
|
640
640
|
maximize: true,
|
|
641
641
|
mode: 'view',
|
|
@@ -723,7 +723,7 @@ const MenuDefault = {
|
|
|
723
723
|
await PanelForm.instance({
|
|
724
724
|
idPanel: 'default-blog',
|
|
725
725
|
defaultUrlImage: `${getProxyPath()}android-chrome-96x96.png`,
|
|
726
|
-
|
|
726
|
+
appStore: AppStoreDefault,
|
|
727
727
|
parentIdModal: idModal,
|
|
728
728
|
scrollClassContainer: `html-${idModal}`,
|
|
729
729
|
route: routeModal,
|
|
@@ -1,54 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { s4 } from '../core/CommonJs.js';
|
|
4
|
-
import { loggerFactory } from '../core/Logger.js';
|
|
5
|
-
import { SocketIo } from '../core/SocketIo.js';
|
|
6
|
-
import { s } from '../core/VanillaJs.js';
|
|
7
|
-
import { ElementsDefault } from './ElementsDefault.js';
|
|
1
|
+
import { SocketIoHandlerProvider } from '../core/SocketIoHandler.js';
|
|
2
|
+
import { AppStoreDefault } from './AppStoreDefault.js';
|
|
8
3
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const SocketIoDefault = {
|
|
12
|
-
Init: function () {
|
|
13
|
-
return new Promise((resolve) => {
|
|
14
|
-
for (const type of Object.keys(ElementsDefault.Data)) {
|
|
15
|
-
SocketIo.Event[type][s4()] = async (args) => {
|
|
16
|
-
args = JSON.parse(args[0]);
|
|
17
|
-
switch (type) {
|
|
18
|
-
case 'chat':
|
|
19
|
-
{
|
|
20
|
-
const idModal = 'modal-chat';
|
|
21
|
-
if (s(`.${idModal}-chat-box`)) Chat.appendChatBox({ idModal, ...args });
|
|
22
|
-
}
|
|
23
|
-
break;
|
|
24
|
-
|
|
25
|
-
default:
|
|
26
|
-
break;
|
|
27
|
-
}
|
|
28
|
-
const { status } = args;
|
|
29
|
-
|
|
30
|
-
switch (status) {
|
|
31
|
-
case 'email-confirmed': {
|
|
32
|
-
const newUser = { ...ElementsDefault.Data.user.main.model.user, emailConfirmed: true };
|
|
33
|
-
Account.renderVerifyEmailStatus(newUser);
|
|
34
|
-
Account.triggerUpdateEvent({ user: newUser });
|
|
35
|
-
break;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
default:
|
|
39
|
-
break;
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
SocketIo.Event.connect[s4()] = async (reason) => {
|
|
44
|
-
// ElementsDefault.Init({ type, id, element });
|
|
45
|
-
};
|
|
46
|
-
SocketIo.Event.disconnect[s4()] = async (reason) => {
|
|
47
|
-
// ElementsDefault.removeAll();
|
|
48
|
-
};
|
|
49
|
-
return resolve();
|
|
50
|
-
});
|
|
51
|
-
},
|
|
52
|
-
};
|
|
4
|
+
const SocketIoDefault = SocketIoHandlerProvider.create(AppStoreDefault);
|
|
53
5
|
|
|
54
6
|
export { SocketIoDefault };
|
|
@@ -17,6 +17,19 @@ const endpoint = 'core';
|
|
|
17
17
|
|
|
18
18
|
// https://developer.mozilla.org/en-US/docs/Web/API/AbortController
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Returns the normalized proxy path from renderPayload (always trailing `/`).
|
|
22
|
+
* Falls back to `null` when no apiBaseProxyPath is set.
|
|
23
|
+
* @memberof CoreServiceClient
|
|
24
|
+
* @return {string|null}
|
|
25
|
+
*/
|
|
26
|
+
const getApiBaseProxyPath = () =>
|
|
27
|
+
window.renderPayload?.apiBaseProxyPath
|
|
28
|
+
? window.renderPayload.apiBaseProxyPath === '/'
|
|
29
|
+
? window.renderPayload.apiBaseProxyPath
|
|
30
|
+
: `${window.renderPayload.apiBaseProxyPath}/`
|
|
31
|
+
: null;
|
|
32
|
+
|
|
20
33
|
/**
|
|
21
34
|
* Gets the base host for API requests.
|
|
22
35
|
* Uses the apiBaseHost from renderPayload if available, otherwise falls back to location.host.
|
|
@@ -35,13 +48,7 @@ const getBaseHost = () => (window.renderPayload?.apiBaseHost ? window.renderPayl
|
|
|
35
48
|
*/
|
|
36
49
|
const getApiBasePath = (options) =>
|
|
37
50
|
`${
|
|
38
|
-
options?.proxyPath
|
|
39
|
-
? `/${options.proxyPath}/`
|
|
40
|
-
: window.renderPayload?.apiBaseProxyPath
|
|
41
|
-
? window.renderPayload.apiBaseProxyPath == '/'
|
|
42
|
-
? window.renderPayload.apiBaseProxyPath
|
|
43
|
-
: `${window.renderPayload.apiBaseProxyPath}/`
|
|
44
|
-
: getProxyPath()
|
|
51
|
+
options?.proxyPath ? `/${options.proxyPath}/` : getApiBaseProxyPath() || getProxyPath()
|
|
45
52
|
}${window.renderPayload?.apiBasePath ? window.renderPayload.apiBasePath : 'api'}/`;
|
|
46
53
|
|
|
47
54
|
/**
|
|
@@ -65,7 +72,11 @@ const getApiBaseUrl = (options = { id: '', endpoint: '', proxyPath: '' }) =>
|
|
|
65
72
|
* @memberof CoreServiceClient
|
|
66
73
|
* @return {string} The WebSocket base path.
|
|
67
74
|
*/
|
|
68
|
-
const getWsBasePath = () =>
|
|
75
|
+
const getWsBasePath = () => {
|
|
76
|
+
const proxyPath = getApiBaseProxyPath();
|
|
77
|
+
if (proxyPath) return proxyPath !== '/' ? `${proxyPath}socket.io/` : '/socket.io/';
|
|
78
|
+
return getProxyPath() !== '/' ? `${getProxyPath()}socket.io/` : '/socket.io/';
|
|
79
|
+
};
|
|
69
80
|
|
|
70
81
|
/**
|
|
71
82
|
* Constructs the full WebSocket base URL for connections.
|
|
@@ -321,6 +332,7 @@ export {
|
|
|
321
332
|
payloadFactory,
|
|
322
333
|
buildQueryUrl,
|
|
323
334
|
getBaseHost,
|
|
335
|
+
getApiBaseProxyPath,
|
|
324
336
|
getApiBasePath,
|
|
325
337
|
getApiBaseUrl,
|
|
326
338
|
getWsBasePath,
|
|
@@ -2,8 +2,8 @@ import { DefaultManagement } from '../default/default.management.js';
|
|
|
2
2
|
import { UserService } from './user.service.js';
|
|
3
3
|
|
|
4
4
|
const UserManagement = {
|
|
5
|
-
RenderTable: async ({
|
|
6
|
-
const user =
|
|
5
|
+
RenderTable: async ({ appStore }) => {
|
|
6
|
+
const user = appStore.Data.user.main.model.user;
|
|
7
7
|
const { role } = user;
|
|
8
8
|
return await DefaultManagement.RenderTable({
|
|
9
9
|
idModal: 'modal-user-management',
|
package/src/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import UnderpostKickStart from './cli/kickstart.js';
|
|
|
10
10
|
import UnderpostCluster from './cli/cluster.js';
|
|
11
11
|
import UnderpostDB from './cli/db.js';
|
|
12
12
|
import UnderpostDeploy from './cli/deploy.js';
|
|
13
|
+
import UnderpostKubectl from './cli/kubectl.js';
|
|
13
14
|
import UnderpostRootEnv from './cli/env.js';
|
|
14
15
|
import UnderpostFileStorage from './cli/fs.js';
|
|
15
16
|
import UnderpostIPFS from './cli/ipfs.js';
|
|
@@ -22,6 +23,7 @@ import UnderpostSecret from './cli/secrets.js';
|
|
|
22
23
|
import UnderpostSSH from './cli/ssh.js';
|
|
23
24
|
import UnderpostStatic from './cli/static.js';
|
|
24
25
|
import UnderpostTest from './cli/test.js';
|
|
26
|
+
import UnderpostRelease from './cli/release.js';
|
|
25
27
|
import UnderpostSystemProvisionig from './cli/system.js';
|
|
26
28
|
|
|
27
29
|
import UnderpostDns from './server/dns.js';
|
|
@@ -42,7 +44,7 @@ class Underpost {
|
|
|
42
44
|
* @type {String}
|
|
43
45
|
* @memberof Underpost
|
|
44
46
|
*/
|
|
45
|
-
static version = 'v3.
|
|
47
|
+
static version = 'v3.2.0';
|
|
46
48
|
|
|
47
49
|
/**
|
|
48
50
|
* Required Node.js major version
|
|
@@ -126,6 +128,15 @@ class Underpost {
|
|
|
126
128
|
static get db() {
|
|
127
129
|
return UnderpostDB.API;
|
|
128
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Kubectl cli API
|
|
133
|
+
* @static
|
|
134
|
+
* @type {UnderpostKubectl.API}
|
|
135
|
+
* @memberof Underpost
|
|
136
|
+
*/
|
|
137
|
+
static get kubectl() {
|
|
138
|
+
return UnderpostKubectl.API;
|
|
139
|
+
}
|
|
129
140
|
/**
|
|
130
141
|
* Deployment cli API
|
|
131
142
|
* @static
|
|
@@ -280,6 +291,16 @@ class Underpost {
|
|
|
280
291
|
static get tls() {
|
|
281
292
|
return UnderpostTLS.API;
|
|
282
293
|
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Release orchestrator cli API
|
|
297
|
+
* @static
|
|
298
|
+
* @type {UnderpostRelease.API}
|
|
299
|
+
* @memberof Underpost
|
|
300
|
+
*/
|
|
301
|
+
static get release() {
|
|
302
|
+
return UnderpostRelease.API;
|
|
303
|
+
}
|
|
283
304
|
}
|
|
284
305
|
|
|
285
306
|
if (!process.version || !process.version.startsWith(`${Underpost.majorNodejsVersion}.`))
|
|
@@ -300,6 +321,7 @@ export {
|
|
|
300
321
|
UnderpostCluster,
|
|
301
322
|
UnderpostDB,
|
|
302
323
|
UnderpostDeploy,
|
|
324
|
+
UnderpostKubectl,
|
|
303
325
|
UnderpostRootEnv,
|
|
304
326
|
UnderpostFileStorage,
|
|
305
327
|
UnderpostImage,
|
|
@@ -317,6 +339,7 @@ export {
|
|
|
317
339
|
UnderpostBackup,
|
|
318
340
|
UnderpostCron,
|
|
319
341
|
UnderpostStartUp,
|
|
342
|
+
UnderpostRelease,
|
|
320
343
|
UnderpostTLS,
|
|
321
344
|
};
|
|
322
345
|
|
|
@@ -79,6 +79,7 @@ class ExpressService {
|
|
|
79
79
|
peer,
|
|
80
80
|
valkey,
|
|
81
81
|
apiBaseHost,
|
|
82
|
+
grpc,
|
|
82
83
|
redirectTarget,
|
|
83
84
|
rootHostPath,
|
|
84
85
|
confSSR,
|
|
@@ -135,7 +136,17 @@ class ExpressService {
|
|
|
135
136
|
});
|
|
136
137
|
|
|
137
138
|
// Static file serving
|
|
138
|
-
app.use(
|
|
139
|
+
app.use(
|
|
140
|
+
'/',
|
|
141
|
+
express.static(directory ? directory : `.${rootHostPath}`, {
|
|
142
|
+
setHeaders: (res, filePath) => {
|
|
143
|
+
if (filePath.includes('/assets/')) {
|
|
144
|
+
res.set('Access-Control-Allow-Origin', '*');
|
|
145
|
+
res.set('Cross-Origin-Resource-Policy', 'cross-origin');
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
}),
|
|
149
|
+
);
|
|
139
150
|
|
|
140
151
|
// Handle redirection-only instances
|
|
141
152
|
if (redirect) {
|
|
@@ -198,6 +209,12 @@ class ExpressService {
|
|
|
198
209
|
});
|
|
199
210
|
}
|
|
200
211
|
|
|
212
|
+
// gRPC server
|
|
213
|
+
if (path === '/' && grpc && grpc.module) {
|
|
214
|
+
const { GrpcServer } = await import(`../../grpc/${grpc.module}/grpc-server.js`);
|
|
215
|
+
await GrpcServer.start({ host, path, port: grpc.port || 50051 });
|
|
216
|
+
}
|
|
217
|
+
|
|
201
218
|
// API router loading
|
|
202
219
|
if (apis && apis.length > 0) {
|
|
203
220
|
const authMiddleware = authMiddlewareFactory({ host, path });
|
|
@@ -20,8 +20,8 @@ RUN dnf -y update && \
|
|
|
20
20
|
perl && \
|
|
21
21
|
dnf clean all
|
|
22
22
|
|
|
23
|
-
# --- Download and install XAMPP
|
|
24
|
-
RUN curl -L -o /tmp/xampp-linux-installer.run "https://sourceforge.net/projects/xampp/files/XAMPP%20Linux/
|
|
23
|
+
# --- Download and install XAMPP (PHP 8.2)
|
|
24
|
+
RUN curl -L -o /tmp/xampp-linux-installer.run "https://sourceforge.net/projects/xampp/files/XAMPP%20Linux/8.2.12/xampp-linux-x64-8.2.12-0-installer.run" && \
|
|
25
25
|
chmod +x /tmp/xampp-linux-installer.run && \
|
|
26
26
|
bash -c "/tmp/xampp-linux-installer.run --mode unattended" && \
|
|
27
27
|
ln -sf /opt/lampp/lampp /usr/bin/lampp
|
|
@@ -31,6 +31,13 @@ RUN mkdir -p /opt/lampp/htdocs && \
|
|
|
31
31
|
chown -R root:root /opt/lampp/htdocs && \
|
|
32
32
|
chmod -R a+rX /opt/lampp/htdocs
|
|
33
33
|
|
|
34
|
+
# Add XAMPP binaries and /usr/local/bin to PATH for all shells
|
|
35
|
+
ENV PATH="/opt/lampp/bin:/usr/local/bin:${PATH}"
|
|
36
|
+
RUN echo 'export PATH="/opt/lampp/bin:/usr/local/bin:${PATH}"' > /etc/profile.d/lampp.sh
|
|
37
|
+
|
|
38
|
+
# Provide a no-op sendmail so PHP plugins don't error on mail calls
|
|
39
|
+
RUN printf '#!/bin/sh\ncat > /dev/null\n' > /usr/sbin/sendmail && chmod +x /usr/sbin/sendmail
|
|
40
|
+
|
|
34
41
|
# Install Node.js
|
|
35
42
|
RUN curl -fsSL https://rpm.nodesource.com/setup_24.x | bash -
|
|
36
43
|
RUN dnf install nodejs -y
|