cyberia 3.1.3 → 3.2.5

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 (208) hide show
  1. package/.env.example +0 -2
  2. package/.github/workflows/engine-cyberia.cd.yml +10 -8
  3. package/.github/workflows/engine-cyberia.ci.yml +12 -29
  4. package/.github/workflows/ghpkg.ci.yml +4 -4
  5. package/.github/workflows/npmpkg.ci.yml +28 -11
  6. package/.github/workflows/publish.ci.yml +21 -2
  7. package/.github/workflows/pwa-microservices-template-page.cd.yml +4 -5
  8. package/.github/workflows/pwa-microservices-template-test.ci.yml +3 -3
  9. package/.github/workflows/release.cd.yml +13 -8
  10. package/CHANGELOG.md +433 -1
  11. package/CLI-HELP.md +57 -7
  12. package/Dockerfile +4 -2
  13. package/README.md +347 -22
  14. package/bin/build.js +5 -2
  15. package/bin/cyberia.js +1789 -112
  16. package/bin/deploy.js +177 -124
  17. package/bin/file.js +3 -0
  18. package/bin/index.js +1789 -112
  19. package/conf.js +64 -8
  20. package/deployment.yaml +92 -20
  21. package/hardhat/hardhat.config.js +13 -13
  22. package/hardhat/ignition/modules/ObjectLayerToken.js +1 -1
  23. package/hardhat/package-lock.json +2554 -5859
  24. package/hardhat/package.json +13 -22
  25. package/hardhat/scripts/deployObjectLayerToken.js +1 -1
  26. package/hardhat/test/ObjectLayerToken.js +4 -2
  27. package/hardhat/types/ethers-contracts/ObjectLayerToken.ts +690 -0
  28. package/hardhat/types/ethers-contracts/common.ts +92 -0
  29. package/hardhat/types/ethers-contracts/factories/ObjectLayerToken__factory.ts +1055 -0
  30. package/hardhat/types/ethers-contracts/factories/index.ts +4 -0
  31. package/hardhat/types/ethers-contracts/hardhat.d.ts +47 -0
  32. package/hardhat/types/ethers-contracts/index.ts +6 -0
  33. package/jsdoc.dd-cyberia.json +64 -55
  34. package/jsdoc.json +64 -55
  35. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +5 -4
  36. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +5 -4
  37. package/manifests/deployment/dd-cyberia-development/deployment.yaml +92 -20
  38. package/manifests/deployment/dd-cyberia-development/proxy.yaml +54 -18
  39. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  40. package/manifests/deployment/dd-test-development/deployment.yaml +88 -74
  41. package/manifests/deployment/dd-test-development/proxy.yaml +13 -4
  42. package/manifests/deployment/playwright/deployment.yaml +1 -1
  43. package/nodemon.json +1 -1
  44. package/package.json +22 -16
  45. package/proxy.yaml +54 -18
  46. package/scripts/rhel-grpc-setup.sh +56 -0
  47. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +44 -0
  48. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +16 -0
  49. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
  50. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +80 -7
  51. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +93 -0
  52. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +36 -0
  53. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +29 -0
  54. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +51 -0
  55. package/src/api/cyberia-entity/cyberia-entity.controller.js +74 -0
  56. package/src/api/cyberia-entity/cyberia-entity.model.js +24 -0
  57. package/src/api/cyberia-entity/cyberia-entity.router.js +27 -0
  58. package/src/api/cyberia-entity/cyberia-entity.service.js +42 -0
  59. package/src/api/cyberia-instance/cyberia-fallback-world.js +368 -0
  60. package/src/api/cyberia-instance/cyberia-instance.controller.js +92 -0
  61. package/src/api/cyberia-instance/cyberia-instance.model.js +84 -0
  62. package/src/api/cyberia-instance/cyberia-instance.router.js +63 -0
  63. package/src/api/cyberia-instance/cyberia-instance.service.js +191 -0
  64. package/src/api/cyberia-instance/cyberia-portal-connector.js +486 -0
  65. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +74 -0
  66. package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +413 -0
  67. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +228 -0
  68. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +27 -0
  69. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +42 -0
  70. package/src/api/cyberia-map/cyberia-map.controller.js +79 -0
  71. package/src/api/cyberia-map/cyberia-map.model.js +30 -0
  72. package/src/api/cyberia-map/cyberia-map.router.js +40 -0
  73. package/src/api/cyberia-map/cyberia-map.service.js +74 -0
  74. package/src/api/file/file.ref.json +18 -0
  75. package/src/api/ipfs/ipfs.controller.js +4 -25
  76. package/src/api/ipfs/ipfs.model.js +43 -34
  77. package/src/api/ipfs/ipfs.router.js +8 -13
  78. package/src/api/ipfs/ipfs.service.js +54 -102
  79. package/src/api/object-layer/README.md +347 -22
  80. package/src/api/object-layer/object-layer.router.js +30 -0
  81. package/src/api/object-layer/object-layer.service.js +114 -31
  82. package/src/api/user/user.service.js +8 -7
  83. package/src/cli/cluster.js +7 -7
  84. package/src/cli/db.js +710 -827
  85. package/src/cli/deploy.js +151 -93
  86. package/src/cli/env.js +29 -0
  87. package/src/cli/fs.js +5 -2
  88. package/src/cli/index.js +48 -2
  89. package/src/cli/kubectl.js +211 -0
  90. package/src/cli/release.js +284 -0
  91. package/src/cli/repository.js +438 -75
  92. package/src/cli/run.js +195 -35
  93. package/src/cli/secrets.js +73 -0
  94. package/src/cli/test.js +3 -3
  95. package/src/client/Cryptokoyn.index.js +3 -4
  96. package/src/client/CyberiaPortal.index.js +3 -4
  97. package/src/client/Default.index.js +3 -4
  98. package/src/client/Itemledger.index.js +3 -4
  99. package/src/client/Underpost.index.js +3 -4
  100. package/src/client/components/core/AppStore.js +69 -0
  101. package/src/client/components/core/CalendarCore.js +2 -2
  102. package/src/client/components/core/DropDown.js +137 -17
  103. package/src/client/components/core/Keyboard.js +2 -2
  104. package/src/client/components/core/LogIn.js +2 -2
  105. package/src/client/components/core/LogOut.js +2 -2
  106. package/src/client/components/core/Modal.js +0 -1
  107. package/src/client/components/core/Panel.js +0 -1
  108. package/src/client/components/core/PanelForm.js +19 -19
  109. package/src/client/components/core/SocketIo.js +82 -29
  110. package/src/client/components/core/SocketIoHandler.js +75 -0
  111. package/src/client/components/core/Stream.js +143 -95
  112. package/src/client/components/core/Webhook.js +40 -7
  113. package/src/client/components/cryptokoyn/AppStoreCryptokoyn.js +5 -0
  114. package/src/client/components/cryptokoyn/LogInCryptokoyn.js +3 -3
  115. package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +2 -2
  116. package/src/client/components/cryptokoyn/MenuCryptokoyn.js +3 -3
  117. package/src/client/components/cryptokoyn/SocketIoCryptokoyn.js +3 -51
  118. package/src/client/components/cyberia/InstanceEngineCyberia.js +700 -0
  119. package/src/client/components/cyberia/MapEngineCyberia.js +1359 -2
  120. package/src/client/components/cyberia/ObjectLayerEngineModal.js +17 -6
  121. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +92 -54
  122. package/src/client/components/cyberia-portal/AppStoreCyberiaPortal.js +5 -0
  123. package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +216 -30
  124. package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +3 -3
  125. package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +2 -2
  126. package/src/client/components/cyberia-portal/MenuCyberiaPortal.js +40 -7
  127. package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +4 -0
  128. package/src/client/components/cyberia-portal/SocketIoCyberiaPortal.js +3 -49
  129. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
  130. package/src/client/components/default/AppStoreDefault.js +5 -0
  131. package/src/client/components/default/LogInDefault.js +3 -3
  132. package/src/client/components/default/LogOutDefault.js +2 -2
  133. package/src/client/components/default/MenuDefault.js +5 -5
  134. package/src/client/components/default/SocketIoDefault.js +3 -51
  135. package/src/client/components/itemledger/AppStoreItemledger.js +5 -0
  136. package/src/client/components/itemledger/LogInItemledger.js +3 -3
  137. package/src/client/components/itemledger/LogOutItemledger.js +2 -2
  138. package/src/client/components/itemledger/MenuItemledger.js +3 -3
  139. package/src/client/components/itemledger/SocketIoItemledger.js +3 -51
  140. package/src/client/components/underpost/AppStoreUnderpost.js +5 -0
  141. package/src/client/components/underpost/LogInUnderpost.js +3 -3
  142. package/src/client/components/underpost/LogOutUnderpost.js +2 -2
  143. package/src/client/components/underpost/MenuUnderpost.js +5 -5
  144. package/src/client/components/underpost/SocketIoUnderpost.js +3 -51
  145. package/src/client/services/core/core.service.js +20 -8
  146. package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +105 -0
  147. package/src/client/services/cyberia-entity/cyberia-entity.management.js +57 -0
  148. package/src/client/services/cyberia-entity/cyberia-entity.service.js +105 -0
  149. package/src/client/services/cyberia-instance/cyberia-instance.management.js +194 -0
  150. package/src/client/services/cyberia-instance/cyberia-instance.service.js +122 -0
  151. package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +105 -0
  152. package/src/client/services/cyberia-map/cyberia-map.management.js +193 -0
  153. package/src/client/services/cyberia-map/cyberia-map.service.js +126 -0
  154. package/src/client/services/instance/instance.management.js +2 -2
  155. package/src/client/services/ipfs/ipfs.service.js +3 -23
  156. package/src/client/services/object-layer/object-layer.management.js +3 -3
  157. package/src/client/services/object-layer/object-layer.service.js +21 -0
  158. package/src/client/services/user/user.management.js +2 -2
  159. package/src/client/ssr/pages/CyberiaServerMetrics.js +1 -1
  160. package/src/grpc/cyberia/OFF_CHAIN_ECONOMY.md +305 -0
  161. package/src/grpc/cyberia/README.md +326 -0
  162. package/src/grpc/cyberia/grpc-server.js +530 -0
  163. package/src/index.js +24 -1
  164. package/src/runtime/express/Dockerfile +4 -0
  165. package/src/runtime/express/Express.js +18 -1
  166. package/src/runtime/lampp/Dockerfile +13 -2
  167. package/src/runtime/lampp/Lampp.js +27 -4
  168. package/src/runtime/wp/Dockerfile +68 -0
  169. package/src/runtime/wp/Wp.js +639 -0
  170. package/src/server/auth.js +24 -1
  171. package/src/server/backup.js +37 -9
  172. package/src/server/client-build-docs.js +9 -2
  173. package/src/server/client-build.js +31 -31
  174. package/src/server/client-formatted.js +109 -57
  175. package/src/server/conf.js +24 -9
  176. package/src/server/cron.js +25 -23
  177. package/src/server/dns.js +2 -1
  178. package/src/server/ipfs-client.js +24 -1
  179. package/src/server/object-layer.js +149 -108
  180. package/src/server/peer.js +8 -0
  181. package/src/server/runtime.js +25 -1
  182. package/src/server/semantic-layer-generator-floor.js +359 -0
  183. package/src/server/semantic-layer-generator-skin.js +1294 -0
  184. package/src/server/semantic-layer-generator.js +116 -555
  185. package/src/server/start.js +2 -2
  186. package/src/ws/IoInterface.js +1 -10
  187. package/src/ws/IoServer.js +14 -33
  188. package/src/ws/core/channels/core.ws.chat.js +65 -20
  189. package/src/ws/core/channels/core.ws.mailer.js +113 -32
  190. package/src/ws/core/channels/core.ws.stream.js +90 -31
  191. package/src/ws/core/core.ws.connection.js +12 -33
  192. package/src/ws/core/core.ws.emit.js +10 -26
  193. package/src/ws/core/core.ws.server.js +25 -58
  194. package/src/ws/default/channels/default.ws.main.js +53 -12
  195. package/src/ws/default/default.ws.connection.js +26 -13
  196. package/src/ws/default/default.ws.server.js +30 -12
  197. package/src/client/components/cryptokoyn/CommonCryptokoyn.js +0 -29
  198. package/src/client/components/cryptokoyn/ElementsCryptokoyn.js +0 -38
  199. package/src/client/components/cyberia-portal/ElementsCyberiaPortal.js +0 -38
  200. package/src/client/components/default/ElementsDefault.js +0 -38
  201. package/src/client/components/itemledger/CommonItemledger.js +0 -29
  202. package/src/client/components/itemledger/ElementsItemledger.js +0 -38
  203. package/src/client/components/underpost/CommonUnderpost.js +0 -29
  204. package/src/client/components/underpost/ElementsUnderpost.js +0 -38
  205. package/src/ws/core/management/core.ws.chat.js +0 -8
  206. package/src/ws/core/management/core.ws.mailer.js +0 -16
  207. package/src/ws/core/management/core.ws.stream.js +0 -8
  208. package/src/ws/default/management/default.ws.main.js +0 -8
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Shared factory for app-specific WebSocket event handlers.
3
+ * Eliminates duplication across per-app SocketIo*.js modules by providing
4
+ * common channel event handling (chat, email-confirmed, etc.).
5
+ *
6
+ * @module client/core/SocketIoHandler
7
+ * @namespace SocketIoHandlerProvider
8
+ */
9
+ import { Account } from './Account.js';
10
+ import { Chat } from './Chat.js';
11
+ import { s4 } from './CommonJs.js';
12
+ import { loggerFactory } from './Logger.js';
13
+ import { SocketIo } from './SocketIo.js';
14
+ import { s } from './VanillaJs.js';
15
+
16
+ const logger = loggerFactory(import.meta);
17
+
18
+ /**
19
+ * @class SocketIoHandlerProvider
20
+ * @classdesc Provides a static factory method to create app-specific SocketIo event handlers
21
+ * from an {@link AppStore} instance. Handles common channel events (chat, email-confirmed)
22
+ * and wires connect/disconnect lifecycle.
23
+ * @memberof SocketIoHandlerProvider
24
+ */
25
+ class SocketIoHandlerProvider {
26
+ /**
27
+ * Creates a standard SocketIo event initialization object for an app module.
28
+ *
29
+ * @static
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.
32
+ */
33
+ static create(appStore) {
34
+ return {
35
+ Init() {
36
+ return new Promise((resolve) => {
37
+ for (const type of Object.keys(appStore.Data)) {
38
+ SocketIo.Event[type][s4()] = async (args) => {
39
+ args = JSON.parse(args[0]);
40
+ switch (type) {
41
+ case 'chat':
42
+ {
43
+ const idModal = 'modal-chat';
44
+ if (s(`.${idModal}-chat-box`)) Chat.appendChatBox({ idModal, ...args });
45
+ }
46
+ break;
47
+
48
+ default:
49
+ break;
50
+ }
51
+ const { status } = args;
52
+
53
+ switch (status) {
54
+ case 'email-confirmed': {
55
+ const newUser = { ...appStore.Data.user.main.model.user, emailConfirmed: true };
56
+ Account.renderVerifyEmailStatus(newUser);
57
+ Account.triggerUpdateEvent({ user: newUser });
58
+ break;
59
+ }
60
+
61
+ default:
62
+ break;
63
+ }
64
+ };
65
+ }
66
+ SocketIo.Event.connect[s4()] = async (reason) => {};
67
+ SocketIo.Event.disconnect[s4()] = async (reason) => {};
68
+ return resolve();
69
+ });
70
+ },
71
+ };
72
+ }
73
+ }
74
+
75
+ export { SocketIoHandlerProvider };
@@ -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
- const Stream = {
9
- Data: {},
10
- createPeerServer: function ({ id }) {
11
- const peerOptions = {
12
- host: location.hostname, // '/'
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
- logger.info('peerOptions', peerOptions);
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
- call.on('stream', (userMediaStream) => {
39
- onConnectStream(this.renderElementStream(mediaElement, userMediaStream));
40
- });
41
- // If they leave, remove their video
42
- call.on('close', () => {
43
- onDisconnectStream(mediaElement);
44
- });
45
- return { call, mediaElement };
46
- },
47
- handlePeerDisconnect({ id }) {
48
- // manually close the peer connections
49
- for (let conns in this.Data[id].peer.server.connections) {
50
- this.Data[id].peer.server.connections[conns].forEach((conn, index, array) => {
51
- console.log(`closing ${conn.connectionId} peerConnection (${index + 1}/${array.length})`, conn.peerConnection);
52
- if (conn.peerConnection && conn.peerConnection.close) conn.peerConnection.close();
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
- // close it using peerjs methods
55
- if (conn.close) conn.close();
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
- renderElementStream: function (mediaElement, stream) {
60
- mediaElement.srcObject = stream;
61
- mediaElement.addEventListener('loadedmetadata', () => {
62
- // Play the video as it loads
63
- mediaElement.play();
64
- });
65
- return mediaElement;
66
- // use example:
67
- // videoGrid.append(mediaElement); // Append video element to videoGrid
68
- },
69
- // Access the user's video and audio
70
- getMediaStream: function (
71
- options = {
72
- video: true,
73
- audio: true,
74
- },
75
- ) {
76
- return new Promise((resolve) => {
77
- navigator.mediaDevices
78
- .getUserMedia(options)
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
- // stop only audio
93
- // stream.getAudioTracks()[0].stop();
94
- // stop only video
95
- // stream.getVideoTracks()[0].stop();
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
- break;
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
- default:
107
- break;
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
- return mediaElement;
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
- const Webhook = {
4
- register: async function (options = { user: {} }) {
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
- unregister: async function () {
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 { Webhook };
58
+ export { WebhookProvider };
@@ -0,0 +1,5 @@
1
+ import { AppStore } from '../core/AppStore.js';
2
+
3
+ const AppStoreCryptokoyn = AppStore.create();
4
+
5
+ export { AppStoreCryptokoyn };
@@ -1,14 +1,14 @@
1
1
  import { Auth } from '../core/Auth.js';
2
2
  import { LogIn } from '../core/LogIn.js';
3
- import { ElementsCryptokoyn } from './ElementsCryptokoyn.js';
3
+ import { AppStoreCryptokoyn } from './AppStoreCryptokoyn.js';
4
4
 
5
5
  const LogInCryptokoyn = async function () {
6
6
  LogIn.Event['LogInCryptokoyn'] = async (options) => {
7
7
  const { token, user } = options;
8
- ElementsCryptokoyn.Data.user.main.model.user = user;
8
+ AppStoreCryptokoyn.Data.user.main.model.user = user;
9
9
  };
10
10
  const { user } = await Auth.sessionIn();
11
- ElementsCryptokoyn.Data.user.main.model.user = user;
11
+ AppStoreCryptokoyn.Data.user.main.model.user = user;
12
12
  };
13
13
 
14
14
  export { LogInCryptokoyn };
@@ -1,9 +1,9 @@
1
1
  import { LogOut } from '../core/LogOut.js';
2
- import { ElementsCryptokoyn } from './ElementsCryptokoyn.js';
2
+ import { AppStoreCryptokoyn } from './AppStoreCryptokoyn.js';
3
3
 
4
4
  const LogOutCryptokoyn = async function () {
5
5
  LogOut.Event['LogOutCryptokoyn'] = async (result = { user: { _id: '' } }) => {
6
- ElementsCryptokoyn.Data.user.main.model.user = result.user;
6
+ AppStoreCryptokoyn.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 { getProxyPath } from '../core/Router.js';
13
- import { ElementsCryptokoyn } from './ElementsCryptokoyn.js';
13
+ import { AppStoreCryptokoyn } from './AppStoreCryptokoyn.js';
14
14
  import Sortable from 'sortablejs';
15
15
  import { RouterCryptokoyn, BannerAppTemplate } from './RoutesCryptokoyn.js';
16
16
  import { Wallet } from '../core/Wallet.js';
@@ -274,7 +274,7 @@ const MenuCryptokoyn = {
274
274
  html: async () =>
275
275
  await Account.Render({
276
276
  idModal: 'modal-account',
277
- user: ElementsCryptokoyn.Data.user.main.model.user,
277
+ user: AppStoreCryptokoyn.Data.user.main.model.user,
278
278
  disabled: [],
279
279
  }),
280
280
  handleType: 'bar',
@@ -338,7 +338,7 @@ const MenuCryptokoyn = {
338
338
  text: Translate.Render('recover'),
339
339
  }),
340
340
  html: async () =>
341
- await Recover.Render({ idModal: 'modal-recover', user: ElementsCryptokoyn.Data.user.main.model.user }),
341
+ await Recover.Render({ idModal: 'modal-recover', user: AppStoreCryptokoyn.Data.user.main.model.user }),
342
342
  handleType: 'bar',
343
343
  maximize: true,
344
344
  mode: 'view',
@@ -1,54 +1,6 @@
1
- import { Account } from '../core/Account.js';
2
- import { Chat } from '../core/Chat.js';
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 { ElementsCryptokoyn } from './ElementsCryptokoyn.js';
1
+ import { SocketIoHandlerProvider } from '../core/SocketIoHandler.js';
2
+ import { AppStoreCryptokoyn } from './AppStoreCryptokoyn.js';
8
3
 
9
- const logger = loggerFactory(import.meta);
10
-
11
- const SocketIoCryptokoyn = {
12
- Init: function () {
13
- return new Promise((resolve) => {
14
- for (const type of Object.keys(ElementsCryptokoyn.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 = { ...ElementsCryptokoyn.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
- // ElementsCryptokoyn.Init({ type, id, element });
45
- };
46
- SocketIo.Event.disconnect[s4()] = async (reason) => {
47
- // ElementsCryptokoyn.removeAll();
48
- };
49
- return resolve();
50
- });
51
- },
52
- };
4
+ const SocketIoCryptokoyn = SocketIoHandlerProvider.create(AppStoreCryptokoyn);
53
5
 
54
6
  export { SocketIoCryptokoyn };