@underpostnet/cyberia 3.3.0 → 3.3.76

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 (568) hide show
  1. package/.dockerignore +1 -0
  2. package/.env.example +17 -5
  3. package/.github/workflows/coverall.cyberia.ci.yml +39 -14
  4. package/.github/workflows/cyberia-client.cd.yml +5 -0
  5. package/.github/workflows/cyberia-server.cd.yml +5 -0
  6. package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
  7. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
  8. package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
  9. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
  10. package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
  11. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
  12. package/.github/workflows/engine-cyberia.cd.yml +3 -0
  13. package/.github/workflows/engine-cyberia.ci.yml +4 -5
  14. package/.github/workflows/ghpkg.ci.yml +35 -20
  15. package/.github/workflows/hardhat.ci.yml +12 -11
  16. package/.github/workflows/npmpkg.ci.yml +17 -15
  17. package/.github/workflows/publish.cyberia.ci.yml +44 -0
  18. package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
  19. package/.github/workflows/release.cd.yml +1 -0
  20. package/.prettierignore +1 -0
  21. package/AGENTS.md +96 -0
  22. package/CHANGELOG.md +653 -2513
  23. package/CLI-HELP.md +323 -157
  24. package/Dockerfile +25 -9
  25. package/Dockerfile.dev +25 -9
  26. package/Dockerfile.test +5 -5
  27. package/README.md +48 -28
  28. package/bin/build.js +86 -41
  29. package/bin/build.template.js +8 -3
  30. package/bin/cyberia.js +1494 -1403
  31. package/bin/deploy.js +18 -104
  32. package/bin/index.js +1494 -1403
  33. package/compose.env +17 -5
  34. package/conf.js +98 -7
  35. package/deploy/cyberia-client/deploy.sh +46 -0
  36. package/deploy/cyberia-client/package.sh +17 -0
  37. package/deploy/cyberia-client/state.sh +15 -0
  38. package/deploy/cyberia-server/deploy.sh +46 -0
  39. package/deploy/cyberia-server/package.sh +17 -0
  40. package/deploy/cyberia-server/state.sh +15 -0
  41. package/deploy/dd-cyberia/deploy.sh +9 -29
  42. package/deploy/dd-cyberia/init.sh +38 -45
  43. package/deploy/dd-cyberia/package.sh +16 -0
  44. package/deploy/dd-cyberia/state.sh +14 -0
  45. package/deploy/dd-cyberia/sync-deploy.sh +133 -147
  46. package/deploy/lib/config.sh +29 -0
  47. package/deploy/lib/github-actions-logging.sh +610 -0
  48. package/deploy/lib/host.sh +194 -0
  49. package/deploy/lib/state.sh +65 -0
  50. package/deploy/pwa-microservices-template/deploy.sh +17 -42
  51. package/deploy/release/deploy.sh +9 -41
  52. package/deployment.yaml +7 -2
  53. package/docker-compose.yml +23 -17
  54. package/examples/static-page/README.md +19 -19
  55. package/examples/static-page/ssr-components/CustomPage.js +2 -2
  56. package/hardhat/hardhat.config.js +1 -6
  57. package/hardhat/package-lock.json +101 -40
  58. package/hardhat/package.json +2 -2
  59. package/manifests/alertmanager/deployment.yaml +81 -0
  60. package/manifests/blackbox-exporter/deployment.yaml +75 -0
  61. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +32 -7
  62. package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +32 -7
  63. package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
  64. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  65. package/manifests/deployment/mongo-express/deployment.yaml +46 -27
  66. package/manifests/deployment/mongo-express/kustomization.yaml +9 -0
  67. package/manifests/deployment/mongo-express/mongo-express-nodeport.yaml +18 -0
  68. package/manifests/deployment/mongo-express/service.yaml +16 -0
  69. package/manifests/deployment/mongo-express-no-auth/disable-mongodb-auth.yaml +16 -0
  70. package/manifests/deployment/mongo-express-no-auth/kustomization.yaml +16 -0
  71. package/manifests/grafana/deployment.yaml +26 -7
  72. package/manifests/grafana/kustomization.yaml +1 -0
  73. package/manifests/grafana/service.yaml +6 -1
  74. package/manifests/mariadb/pv.yaml +1 -0
  75. package/manifests/mongodb/statefulset.yaml +9 -2
  76. package/manifests/mysql/pv-pvc.yaml +14 -1
  77. package/manifests/postgresql/pv.yaml +12 -1
  78. package/manifests/postgresql/pvc.yaml +1 -0
  79. package/manifests/prometheus/deployment.yaml +18 -22
  80. package/package.json +87 -12
  81. package/scripts/event-monitor.sh +56 -0
  82. package/scripts/k3s-node-setup.sh +27 -14
  83. package/scripts/kubeadm-node-setup.sh +31 -11
  84. package/scripts/maas-setup.sh +8 -8
  85. package/scripts/selinux-normalize.sh +907 -0
  86. package/scripts/shutdown-machine.sh +843 -0
  87. package/scripts/test-monitor.sh +5 -5
  88. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +15 -10
  89. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
  90. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +7 -2
  91. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +90 -186
  92. package/src/api/core/core.controller.js +1 -1
  93. package/src/api/core/core.router.js +2 -2
  94. package/src/api/core/core.service.js +2 -2
  95. package/src/api/crypto/crypto.controller.js +1 -1
  96. package/src/api/crypto/crypto.service.js +1 -1
  97. package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
  98. package/src/api/cyberia-action/cyberia-action.router.js +3 -3
  99. package/src/api/cyberia-action/cyberia-action.service.js +5 -6
  100. package/src/api/cyberia-audio/cyberia-audio.controller.js +6 -0
  101. package/src/api/cyberia-audio/cyberia-audio.model.js +61 -0
  102. package/src/api/cyberia-audio/cyberia-audio.router.js +21 -0
  103. package/src/api/cyberia-audio/cyberia-audio.service.js +220 -0
  104. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +2 -4
  105. package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
  106. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +13 -35
  107. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +17 -34
  108. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
  109. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
  110. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +2 -2
  111. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
  112. package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
  113. package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
  114. package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
  115. package/src/api/cyberia-entity/cyberia-entity.service.js +3 -3
  116. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +8 -2
  117. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +31 -20
  118. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +17 -2
  119. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +468 -5
  120. package/src/api/cyberia-instance/cyberia-fallback-capture.js +502 -0
  121. package/src/api/cyberia-instance/cyberia-fallback-world.js +29 -40
  122. package/src/api/cyberia-instance/cyberia-instance-boot.service.js +5 -5
  123. package/src/api/cyberia-instance/cyberia-instance-items.js +98 -0
  124. package/src/api/cyberia-instance/cyberia-instance-map.service.js +35 -142
  125. package/src/api/cyberia-instance/cyberia-instance.controller.js +2 -5
  126. package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
  127. package/src/api/cyberia-instance/cyberia-instance.router.js +5 -18
  128. package/src/api/cyberia-instance/cyberia-instance.service.js +5 -45
  129. package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
  130. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
  131. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
  132. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
  133. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +76 -3
  134. package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
  135. package/src/api/cyberia-map/cyberia-map.router.js +1 -1
  136. package/src/api/cyberia-map/cyberia-map.service.js +8 -4
  137. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.controller.js +31 -0
  138. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.model.js +56 -0
  139. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.router.js +33 -0
  140. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +189 -0
  141. package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
  142. package/src/api/cyberia-quest/cyberia-quest.router.js +4 -4
  143. package/src/api/cyberia-quest/cyberia-quest.service.js +5 -5
  144. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
  145. package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
  146. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
  147. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
  148. package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
  149. package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
  150. package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
  151. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -214
  152. package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
  153. package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
  154. package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
  155. package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
  156. package/src/api/default/default.controller.js +1 -1
  157. package/src/api/default/default.router.js +1 -1
  158. package/src/api/default/default.service.js +2 -2
  159. package/src/api/document/document.controller.js +1 -1
  160. package/src/api/document/document.router.js +1 -1
  161. package/src/api/document/document.service.js +2 -2
  162. package/src/api/file/file.controller.js +1 -1
  163. package/src/api/file/file.ref.js +153 -0
  164. package/src/api/file/file.ref.json +11 -2
  165. package/src/api/file/file.router.js +1 -1
  166. package/src/api/file/file.service.js +2 -2
  167. package/src/api/instance/instance.controller.js +1 -1
  168. package/src/api/instance/instance.router.js +1 -1
  169. package/src/api/instance/instance.service.js +2 -2
  170. package/src/api/ipfs/ipfs.controller.js +1 -1
  171. package/src/api/ipfs/ipfs.router.js +2 -2
  172. package/src/api/ipfs/ipfs.service.js +2 -2
  173. package/src/api/object-layer/object-layer.controller.js +1 -1
  174. package/src/api/object-layer/object-layer.model.js +47 -12
  175. package/src/api/object-layer/object-layer.router.js +12 -5
  176. package/src/api/object-layer/object-layer.service.js +116 -123
  177. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
  178. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
  179. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
  180. package/src/api/test/test.controller.js +1 -1
  181. package/src/api/test/test.service.js +1 -1
  182. package/src/api/user/guest.service.js +3 -3
  183. package/src/api/user/user.controller.js +1 -1
  184. package/src/api/user/user.router.js +2 -2
  185. package/src/api/user/user.service.js +4 -4
  186. package/src/api.js +5 -9
  187. package/src/cli/app.js +402 -0
  188. package/src/cli/baremetal.js +30 -35
  189. package/src/cli/client.js +306 -0
  190. package/src/cli/cloud-init.js +3 -3
  191. package/src/cli/cluster.js +191 -82
  192. package/src/cli/db.js +120 -68
  193. package/src/cli/deploy.js +157 -75
  194. package/src/cli/docker-compose.js +5 -5
  195. package/src/cli/domains.js +184 -0
  196. package/src/cli/dotenv-store.js +143 -0
  197. package/src/cli/event.js +2281 -0
  198. package/src/cli/fs-selection.js +115 -0
  199. package/src/cli/fs.js +159 -343
  200. package/src/cli/host.js +672 -0
  201. package/src/cli/image.js +4 -6
  202. package/src/cli/index.js +343 -151
  203. package/src/cli/ipfs.js +34 -30
  204. package/src/cli/kickstart.js +1 -1
  205. package/src/cli/kubectl.js +218 -41
  206. package/src/cli/lxd.js +3 -3
  207. package/src/cli/monitor.js +1359 -26
  208. package/src/cli/package.js +90 -0
  209. package/src/cli/release.js +16 -12
  210. package/src/cli/repository.js +586 -363
  211. package/src/cli/run.js +398 -843
  212. package/src/cli/secrets.js +2158 -964
  213. package/src/cli/ssh.js +478 -279
  214. package/src/cli/state.js +394 -0
  215. package/src/cli/static.js +2 -2
  216. package/src/cli/system.js +1 -1
  217. package/src/cli/test.js +203 -125
  218. package/src/cli/vultr.js +61 -21
  219. package/src/cli/wireguard.js +1112 -306
  220. package/src/client/components/core/CalendarCore.js +53 -96
  221. package/src/client/components/core/Docs.js +327 -303
  222. package/src/client/components/core/FileExplorer.js +0 -21
  223. package/src/client/components/core/Modal.js +56 -1
  224. package/src/client/components/core/PanelForm.js +4 -4
  225. package/src/client/components/core/Repository.js +56 -0
  226. package/src/client/components/core/Translate.js +7 -0
  227. package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
  228. package/src/client/components/core/Wallet.js +0 -11
  229. package/src/client/components/core/Worker.js +7 -1
  230. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
  231. package/src/client/components/cyberia/ActionEngineCyberia.js +12 -36
  232. package/src/client/components/cyberia/EntityEngineCyberia.js +492 -121
  233. package/src/client/components/cyberia/InstanceEngineCyberia.js +129 -160
  234. package/src/client/components/cyberia/InstanceSelectionView.js +7 -1
  235. package/src/client/components/cyberia/MapEngineCyberia.js +175 -69
  236. package/src/client/components/cyberia/ObjectLayerEngine.js +1011 -97
  237. package/src/client/components/cyberia/ObjectLayerEngineModal.js +81 -155
  238. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +113 -98
  239. package/src/client/components/cyberia/SharedDefaultsCyberia.js +215 -56
  240. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +2 -35
  241. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +1 -1
  242. package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +712 -76
  243. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
  244. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
  245. package/src/client/components/default/AppShellDefault.js +1 -1
  246. package/src/client/components/default/SettingsDefault.js +2 -2
  247. package/src/client/components/itemledger/SettingsItemledger.js +2 -2
  248. package/src/client/components/underpost/AppShellUnderpost.js +3 -2
  249. package/src/client/components/underpost/SettingsUnderpost.js +2 -2
  250. package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
  251. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +313 -30
  252. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +51 -29
  253. package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +52 -53
  254. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +16 -11
  255. package/src/client/public/cyberia-docs/CYBERIA.md +48 -28
  256. package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
  257. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
  258. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  259. package/src/client/public/cyberia-docs/STATS-PROGRESSION.md +217 -0
  260. package/src/client/public/cyberia-docs/WHITE-PAPER.md +20 -12
  261. package/src/client/public/default/android-chrome-144x144.png +0 -0
  262. package/src/client/public/default/android-chrome-192x192.png +0 -0
  263. package/src/client/public/default/android-chrome-256x256.png +0 -0
  264. package/src/client/public/default/android-chrome-36x36.png +0 -0
  265. package/src/client/public/default/android-chrome-384x384.png +0 -0
  266. package/src/client/public/default/android-chrome-48x48.png +0 -0
  267. package/src/client/public/default/android-chrome-512x512.png +0 -0
  268. package/src/client/public/default/android-chrome-72x72.png +0 -0
  269. package/src/client/public/default/android-chrome-96x96.png +0 -0
  270. package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
  271. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  272. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  273. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  274. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  275. package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
  276. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  277. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  278. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  279. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  280. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  281. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  282. package/src/client/public/default/apple-touch-icon.png +0 -0
  283. package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
  284. package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
  285. package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
  286. package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
  287. package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
  288. package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
  289. package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
  290. package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
  291. package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
  292. package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
  293. package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
  294. package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
  295. package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
  296. package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
  297. package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
  298. package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
  299. package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
  300. package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
  301. package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
  302. package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
  303. package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
  304. package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
  305. package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
  306. package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
  307. package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
  308. package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
  309. package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
  310. package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
  311. package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
  312. package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
  313. package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
  314. package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
  315. package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
  316. package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
  317. package/src/client/public/default/assets/background/white.jpg +0 -0
  318. package/src/client/public/default/browserconfig.xml +1 -1
  319. package/src/client/public/default/favicon-16x16.png +0 -0
  320. package/src/client/public/default/favicon-32x32.png +0 -0
  321. package/src/client/public/default/favicon-48x48.png +0 -0
  322. package/src/client/public/default/favicon.ico +0 -0
  323. package/src/client/public/default/manifest.webmanifest +5 -5
  324. package/src/client/public/default/mstile-144x144.png +0 -0
  325. package/src/client/public/default/mstile-150x150.png +0 -0
  326. package/src/client/public/default/mstile-310x150.png +0 -0
  327. package/src/client/public/default/mstile-310x310.png +0 -0
  328. package/src/client/public/default/mstile-70x70.png +0 -0
  329. package/src/client/public/default/yandex-browser-50x50.png +0 -0
  330. package/src/client/public/default/yandex-browser-manifest.json +1 -1
  331. package/src/client/services/cyberia-audio/cyberia-audio.service.js +99 -0
  332. package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +38 -0
  333. package/src/client/services/cyberia-instance/cyberia-instance.management.js +5 -4
  334. package/src/client/services/cyberia-instance/cyberia-instance.service.js +0 -40
  335. package/src/client/services/cyberia-map/cyberia-map.management.js +5 -4
  336. package/src/client/services/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +138 -0
  337. package/src/client/services/object-layer/object-layer.management.js +6 -10
  338. package/src/client/services/object-layer/object-layer.service.js +3 -1
  339. package/src/client/ssr/RootDocument.js +1 -1
  340. package/src/client/ssr/body/404.js +1 -1
  341. package/src/client/ssr/body/500.js +1 -1
  342. package/src/client/ssr/body/CacheControl.js +1 -1
  343. package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
  344. package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
  345. package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
  346. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
  347. package/src/client/ssr/head/CryptokoynScripts.js +1 -1
  348. package/src/client/ssr/head/Css.js +1 -1
  349. package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
  350. package/src/client/ssr/head/DefaultScripts.js +1 -1
  351. package/src/client/ssr/head/ItemledgerScripts.js +1 -1
  352. package/src/client/ssr/head/Microdata.js +1 -1
  353. package/src/client/ssr/head/Production.js +1 -1
  354. package/src/client/ssr/head/Pwa.js +1 -1
  355. package/src/client/ssr/head/PwaItemledger.js +1 -1
  356. package/src/client/ssr/head/Seo.js +1 -1
  357. package/src/client/ssr/head/UnderpostScripts.js +1 -1
  358. package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
  359. package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
  360. package/src/client/ssr/views/Cyberia404.js +7 -5
  361. package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
  362. package/src/client/ssr/views/Maintenance.js +1 -1
  363. package/src/client/ssr/views/NoNetworkConnection.js +1 -1
  364. package/src/client/ssr/views/Test.js +1 -1
  365. package/src/client/sw/core.sw.js +20 -14
  366. package/src/client-builder/client-build-docs.js +92 -77
  367. package/src/client-builder/client-build-live.js +2 -2
  368. package/src/client-builder/client-build.js +105 -74
  369. package/src/client-builder/client-bundle.js +347 -0
  370. package/src/client-builder/client-dev-server.js +3 -3
  371. package/src/client-builder/client-icons.js +2 -2
  372. package/src/client-builder/ssr.js +3 -3
  373. package/src/client.build.js +3 -6
  374. package/src/client.dev.js +3 -6
  375. package/src/db/DataBaseProvider.js +186 -3
  376. package/src/db/mariadb/MariaDB.js +3 -2
  377. package/src/db/mongo/MongoBootstrap.js +273 -101
  378. package/src/db/mongo/MongoExpress.js +187 -0
  379. package/src/db/mongo/MongooseDB.js +7 -8
  380. package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
  381. package/src/grpc/cyberia/grpc-server.js +6 -8
  382. package/src/index.js +79 -23
  383. package/src/mailer/EmailRender.js +2 -2
  384. package/src/mailer/MailerInterceptor.js +87 -0
  385. package/src/mailer/MailerProvider.js +50 -6
  386. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +144 -147
  387. package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
  388. package/src/projects/cyberia/besu-genesis-generator.js +8 -17
  389. package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
  390. package/src/projects/cyberia/catalog-cyberia.js +54 -10
  391. package/src/projects/cyberia/gemini-client.js +4 -4
  392. package/src/projects/cyberia/generate-saga.js +5 -12
  393. package/src/projects/cyberia/hot-reload-trigger.js +18 -29
  394. package/src/projects/cyberia/instance-backup.js +210 -0
  395. package/src/projects/cyberia/instance-data.js +178 -258
  396. package/src/projects/cyberia/ipfs-client.js +4 -4
  397. package/src/projects/cyberia/map-preview-generator.js +33 -69
  398. package/src/projects/cyberia/object-layer.js +153 -320
  399. package/src/projects/cyberia/seed-audio.js +139 -0
  400. package/src/projects/cyberia/semantic-layer-generator-skin.js +2 -8
  401. package/src/projects/cyberia/semantic-layer-generator.js +3 -19
  402. package/src/projects/cyberia/stat-balance.js +81 -0
  403. package/src/projects/cyberia/stat-commands.js +23 -0
  404. package/src/projects/cyberia/stat-contract-generator.js +101 -0
  405. package/src/projects/underpost/catalog-underpost.js +9 -1
  406. package/src/proxy.js +4 -7
  407. package/src/runtime/cyberia-client/Dockerfile +17 -8
  408. package/src/runtime/cyberia-client/Dockerfile.dev +13 -4
  409. package/src/runtime/cyberia-server/Dockerfile +18 -6
  410. package/src/runtime/cyberia-server/Dockerfile.dev +16 -3
  411. package/src/runtime/engine-cyberia/Dockerfile +25 -9
  412. package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
  413. package/src/runtime/engine-cyberia/Dockerfile.test +5 -5
  414. package/src/runtime/engine-cyberia/compose.env +17 -5
  415. package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
  416. package/src/runtime/express/Express.js +32 -27
  417. package/src/runtime/lampp/Lampp.js +22 -70
  418. package/src/runtime/nginx/Nginx.js +1 -1
  419. package/src/runtime/wp/Wp.js +16 -48
  420. package/src/server/{catalog.js → build/catalog.js} +15 -5
  421. package/src/server/build/coverage.js +188 -0
  422. package/src/server/build/execution.js +402 -0
  423. package/src/server/build/package.js +508 -0
  424. package/src/server/build/testing.js +578 -0
  425. package/src/server/{dns.js → network/dns.js} +144 -11
  426. package/src/server/{forward-proxy.js → network/forward-proxy.js} +10 -18
  427. package/src/server/{middlewares.js → network/middlewares.js} +11 -5
  428. package/src/server/network/node-capability.js +98 -0
  429. package/src/server/{peer.js → network/peer.js} +3 -3
  430. package/src/server/{proxy.js → network/proxy.js} +7 -13
  431. package/src/server/network/router.js +356 -0
  432. package/src/server/{tls.js → network/tls.js} +2 -2
  433. package/src/server/{underpost-compression.js → network/underpost-compression.js} +1 -1
  434. package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +7 -7
  435. package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +2 -2
  436. package/src/server/{cri.js → ops/cri.js} +2 -2
  437. package/src/server/{cron.js → ops/cron.js} +349 -74
  438. package/src/server/ops/event-notification.js +284 -0
  439. package/src/server/{logger.js → ops/logger.js} +143 -23
  440. package/src/server/ops/monitoring.js +1724 -0
  441. package/src/server/{systemd.js → ops/systemd.js} +55 -1
  442. package/src/server/{conf.js → runtime/conf.js} +516 -423
  443. package/src/server/runtime/config-scope.js +215 -0
  444. package/src/server/runtime/environment.js +149 -0
  445. package/src/server/{process.js → runtime/process.js} +153 -12
  446. package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
  447. package/src/server/{runtime.js → runtime/runtime.js} +12 -8
  448. package/src/server/{start.js → runtime/start.js} +128 -39
  449. package/src/server/{auth.js → security/auth.js} +7 -8
  450. package/src/server/security/container-storage.js +382 -0
  451. package/src/server/{crypto.js → security/crypto.js} +1 -1
  452. package/src/server/{selinux.js → security/selinux.js} +1 -1
  453. package/src/server/{backup.js → storage/backup.js} +17 -8
  454. package/src/server/{data-query.js → storage/data-query.js} +17 -1
  455. package/src/server/storage/downloader.js +121 -0
  456. package/src/server/storage/repository.js +68 -0
  457. package/src/server/storage/zip.js +153 -0
  458. package/src/server.js +4 -7
  459. package/src/ws/IoInterface.js +1 -1
  460. package/src/ws/IoServer.js +1 -1
  461. package/src/ws/core/core.ws.connection.js +1 -1
  462. package/src/ws/core/core.ws.emit.js +1 -1
  463. package/src/ws/core/core.ws.server.js +1 -1
  464. package/src/ws/default/default.ws.connection.js +1 -1
  465. package/src/ws/default/default.ws.emit.js +1 -1
  466. package/src/ws/default/default.ws.server.js +1 -1
  467. package/test/e2e/event-e2e-public-ingress-down.js +45 -0
  468. package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
  469. package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
  470. package/test/{api.test.js → integration/app/api.test.js} +33 -14
  471. package/test/integration/app/cyberia/atlas-sprite-sheet-store.test.js +402 -0
  472. package/test/integration/app/cyberia/atlas-sprite-sheet.test.js +86 -0
  473. package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +64 -0
  474. package/test/integration/app/cyberia/cyberia-entity-type-default.test.js +842 -0
  475. package/test/integration/app/cyberia/cyberia-instance-conf-coerce.test.js +53 -0
  476. package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +17 -23
  477. package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
  478. package/test/integration/app/cyberia/cyberia-load.test.js +466 -0
  479. package/test/integration/app/cyberia/cyberia-map-audio-conf.test.js +256 -0
  480. package/test/integration/app/cyberia/cyberia-stats.test.js +150 -0
  481. package/test/integration/app/cyberia/fallback-world-capture.test.js +338 -0
  482. package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
  483. package/test/integration/app/cyberia/object-layer-item-selection.test.js +56 -0
  484. package/test/integration/app/cyberia/object-layer-natural-key.test.js +32 -0
  485. package/test/integration/app/cyberia/seed-audio.test.js +275 -0
  486. package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
  487. package/test/integration/infra/1-security/config-scope.test.js +305 -0
  488. package/test/integration/infra/1-security/container-storage.test.js +356 -0
  489. package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
  490. package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
  491. package/test/{selinux.test.js → integration/infra/1-security/selinux.test.js} +2 -4
  492. package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
  493. package/test/integration/infra/1-security/systemd-service.test.js +70 -0
  494. package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
  495. package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
  496. package/test/integration/infra/2-network/node-capability.test.js +182 -0
  497. package/test/integration/infra/2-network/wireguard-cli.test.js +1187 -0
  498. package/test/{wireguard-edge.test.js → integration/infra/2-network/wireguard-edge.test.js} +649 -55
  499. package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
  500. package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
  501. package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
  502. package/test/integration/infra/3-cluster/mongo-express-deploy.test.js +156 -0
  503. package/test/integration/infra/4-ingress/api-cross-origin.test.js +79 -0
  504. package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
  505. package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
  506. package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
  507. package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +6 -6
  508. package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +4 -4
  509. package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
  510. package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
  511. package/test/integration/infra/5-observability/event-notification.test.js +197 -0
  512. package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
  513. package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
  514. package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
  515. package/test/support/shell-harness.js +73 -0
  516. package/test/unit/build-template.test.js +97 -0
  517. package/test/unit/build-workflow-offline.test.js +132 -0
  518. package/test/unit/catalog.test.js +71 -0
  519. package/test/unit/client-build-docs.test.js +361 -0
  520. package/test/unit/client-bundle.test.js +313 -0
  521. package/test/unit/conf-loading.test.js +303 -0
  522. package/test/unit/conf-resolution.test.js +996 -0
  523. package/test/unit/coverage-artifact.test.js +221 -0
  524. package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
  525. package/test/unit/cyberia/instance-backup.test.js +183 -0
  526. package/test/unit/cyberia/instance-object-layer-items.test.js +46 -0
  527. package/test/unit/cyberia/publish-workflow.test.js +22 -0
  528. package/test/unit/cyberia/stat-balance.test.js +69 -0
  529. package/test/unit/deploy-env-resolution.test.js +38 -0
  530. package/test/unit/deploy-log-table.test.js +518 -0
  531. package/test/unit/downloader-integrity.test.js +98 -0
  532. package/test/unit/execution-profiles.test.js +219 -0
  533. package/test/unit/file-reference-registry.test.js +141 -0
  534. package/test/unit/fleet-sync-source.test.js +149 -0
  535. package/test/unit/fs-storage-paths.test.js +596 -0
  536. package/test/unit/logger-redaction.test.js +141 -0
  537. package/test/unit/package.test.js +457 -0
  538. package/test/unit/prepare-host.test.js +382 -0
  539. package/test/unit/process-environment.test.js +18 -0
  540. package/test/unit/propagation-message.test.js +78 -0
  541. package/test/unit/redeploy-plan.test.js +24 -0
  542. package/test/unit/release-bump.test.js +474 -0
  543. package/test/unit/ssh-output-redaction.test.js +28 -0
  544. package/test/unit/start-options.test.js +46 -0
  545. package/test/unit/test-tiers.test.js +220 -0
  546. package/test/unit/zip-archive.test.js +142 -0
  547. package/vitest.config.js +66 -0
  548. package/.nycrc +0 -9
  549. package/deploy/lib/logging.sh +0 -96
  550. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
  551. package/manifests/mongodb/pv-pvc.yaml +0 -59
  552. package/scripts/coverall-test-cyberia.sh +0 -24
  553. package/scripts/coverall-test.sh +0 -24
  554. package/scripts/link-local-underpost-cli.sh +0 -6
  555. package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
  556. package/src/api/user/user.build.js +0 -16
  557. package/src/cli/env.js +0 -177
  558. package/src/client/components/core/Blockchain.js +0 -41
  559. package/src/client/components/core/Blog.js +0 -9
  560. package/src/client/components/core/KeyboardAvoidance.js +0 -145
  561. package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
  562. package/src/client/public/default/assets/background/dark.jpg +0 -0
  563. package/src/client/public/default/assets/background/white0-min.jpg +0 -0
  564. package/src/client/public/default/assets/background/white0.jpg +0 -0
  565. package/src/client/public/doc/favicon.ico +0 -0
  566. package/src/client/public/doc/sitemap +0 -148
  567. package/src/server/downloader.js +0 -73
  568. package/src/server/environment.js +0 -98
@@ -7,8 +7,14 @@
7
7
  */
8
8
 
9
9
  import fs from 'fs-extra';
10
- import { shellExec } from '../server/process.js';
11
- import { loggerFactory } from '../server/logger.js';
10
+ import { shellExec } from '../server/runtime/process.js';
11
+ import { loggerFactory } from '../server/ops/logger.js';
12
+ import {
13
+ coverageReportCandidates,
14
+ coverageReportsFactory,
15
+ coverageUnavailablePage,
16
+ resolveCoverageReportPath,
17
+ } from '../server/build/coverage.js';
12
18
  import { JSONweb } from './client-formatted.js';
13
19
  import { ssrFactory } from './ssr.js';
14
20
 
@@ -20,6 +26,8 @@ import { ssrFactory } from './ssr.js';
20
26
  * @param {string} options.host - The hostname for the API
21
27
  * @param {string} options.path - The base path for the API
22
28
  * @param {number} options.port - The port number for the API
29
+ * @param {string} [options.apiBaseHost] - Host serving the API when it is split from the client
30
+ * @param {string} [options.apiBaseProxyPath] - Proxy path of the API runtime when it is split from the client
23
31
  * @param {Object} options.metadata - Metadata for the API documentation
24
32
  * @param {Array<string>} options.apis - List of API modules to document
25
33
  * @param {string} options.publicClientId - Client ID for the public documentation
@@ -30,6 +38,8 @@ const buildApiDocs = async ({
30
38
  host,
31
39
  path,
32
40
  port,
41
+ apiBaseHost,
42
+ apiBaseProxyPath,
33
43
  metadata = {},
34
44
  apis = [],
35
45
  publicClientId,
@@ -37,7 +47,10 @@ const buildApiDocs = async ({
37
47
  packageData,
38
48
  }) => {
39
49
  const logger = loggerFactory(import.meta);
40
- const basePath = path === '/' ? `${process.env.BASE_API}` : `/${process.env.BASE_API}`;
50
+ // The spec is rendered by the client instance but exercised against the API runtime;
51
+ // when the two are split the server url must follow the API, not the docs page.
52
+ const apiPath = apiBaseProxyPath ? apiBaseProxyPath : path;
53
+ const basePath = apiPath === '/' ? `${process.env.BASE_API}` : `/${process.env.BASE_API}`;
41
54
 
42
55
  const doc = {
43
56
  info: {
@@ -49,8 +62,8 @@ const buildApiDocs = async ({
49
62
  {
50
63
  url:
51
64
  process.env.NODE_ENV === 'development'
52
- ? `http://localhost:${port}${path}${basePath}`
53
- : `https://${host}${path}${basePath}`,
65
+ ? `http://${apiBaseHost ? apiBaseHost : `localhost:${port}`}${apiPath}${basePath}`
66
+ : `https://${apiBaseHost ? apiBaseHost : host}${apiPath}${basePath}`,
54
67
  description: `${process.env.NODE_ENV} server`,
55
68
  },
56
69
  ],
@@ -284,43 +297,41 @@ const buildApiDocs = async ({
284
297
  ),
285
298
  'utf8',
286
299
  );
287
- setTimeout(async () => {
288
- const { default: swaggerAutoGen } = await import('swagger-autogen');
289
- const outputFile = `./public/${host}${path === '/' ? path : `${path}/`}swagger-output.json`;
290
- const routes = [];
291
- for (const api of apis) {
292
- if (['user', 'object-layer'].includes(api)) routes.push(`./src/api/${api}/${api}.router.js`);
293
- }
300
+ // Imported after the patch above, and awaited: the spec is part of the client build
301
+ // output, so a bundle zipped before it landed shipped without one and the pod that
302
+ // restored that bundle served no `api-docs`.
303
+ const { default: swaggerAutoGen } = await import('swagger-autogen');
304
+ const outputFile = `./public/${host}${path === '/' ? path : `${path}/`}swagger-output.json`;
305
+ const routes = [];
306
+ for (const api of apis) {
307
+ if (['user', 'object-layer'].includes(api)) routes.push(`./src/api/${api}/${api}.router.js`);
308
+ }
294
309
 
295
- await swaggerAutoGen({ openapi: '3.0.0' })(outputFile, routes, doc);
310
+ await swaggerAutoGen({ openapi: '3.0.0' })(outputFile, routes, doc);
296
311
 
297
- // Post-process: inject requestBody into operations — swagger-autogen silently
298
- // ignores #swagger.requestBody annotations and has no internal OAS-3 body support.
299
- if (fs.existsSync(outputFile)) {
300
- const swaggerJson = JSON.parse(fs.readFileSync(outputFile, 'utf8'));
301
- let patched = false;
312
+ // Post-process: inject requestBody into operations — swagger-autogen silently
313
+ // ignores #swagger.requestBody annotations and has no internal OAS-3 body support.
314
+ if (fs.existsSync(outputFile)) {
315
+ const swaggerJson = JSON.parse(fs.readFileSync(outputFile, 'utf8'));
316
+ let patched = false;
302
317
 
303
- for (const [key, requestBody] of Object.entries(requestBodies)) {
304
- const [method, ...pathParts] = key.split(' ');
305
- const opPath = pathParts.join(' ');
306
- if (swaggerJson.paths?.[opPath]?.[method]) {
307
- swaggerJson.paths[opPath][method].requestBody = requestBody;
308
- // Remove any stale in:body entry from parameters (OAS 3.0 doesn't allow it)
309
- if (Array.isArray(swaggerJson.paths[opPath][method].parameters)) {
310
- swaggerJson.paths[opPath][method].parameters = swaggerJson.paths[opPath][method].parameters.filter(
311
- (p) => p.in !== 'body',
312
- );
313
- }
314
- patched = true;
318
+ for (const [key, requestBody] of Object.entries(requestBodies)) {
319
+ const [method, ...pathParts] = key.split(' ');
320
+ const opPath = pathParts.join(' ');
321
+ if (swaggerJson.paths?.[opPath]?.[method]) {
322
+ swaggerJson.paths[opPath][method].requestBody = requestBody;
323
+ // Remove any stale in:body entry from parameters (OAS 3.0 doesn't allow it)
324
+ if (Array.isArray(swaggerJson.paths[opPath][method].parameters)) {
325
+ swaggerJson.paths[opPath][method].parameters = swaggerJson.paths[opPath][method].parameters.filter(
326
+ (p) => p.in !== 'body',
327
+ );
315
328
  }
316
- }
317
-
318
- if (patched) {
319
- fs.writeFileSync(outputFile, JSON.stringify(swaggerJson, null, 2), 'utf8');
320
- // logger.warn('swagger post-process: requestBody injected', Object.keys(requestBodies));
329
+ patched = true;
321
330
  }
322
331
  }
323
- });
332
+
333
+ if (patched) fs.writeFileSync(outputFile, JSON.stringify(swaggerJson, null, 2), 'utf8');
334
+ }
324
335
  };
325
336
 
326
337
  /**
@@ -371,62 +382,60 @@ const buildJsDocs = async ({ host, path, metadata = {}, publicClientId, docs, do
371
382
  fs.writeFileSync(tmpConfigPath, JSON.stringify(runtimeConfig, null, 2), 'utf8');
372
383
  logger.warn('build typedoc view', docsDestination);
373
384
 
374
- shellExec(`node_modules/.bin/typedoc --options ${tmpConfigPath}`, { silent: true });
385
+ // Non-fatal like every other docs surface: a typedoc failure leaves the reference site
386
+ // unpublished, it does not take a rollout down with it.
387
+ const result = shellExec(`node_modules/.bin/typedoc --options ${tmpConfigPath}`, {
388
+ silent: true,
389
+ silentOnError: true,
390
+ });
375
391
 
376
392
  fs.removeSync(tmpConfigPath);
393
+
394
+ if (fs.existsSync(`${docsDestination}index.html`)) return;
395
+ logger.warn('typedoc produced no HTML index', {
396
+ docsDestination,
397
+ code: result?.code,
398
+ stderr: `${result?.stderr ?? ''}`.trim().split('\n').slice(-1)[0],
399
+ });
377
400
  };
378
401
 
379
402
  /**
380
- * Builds test coverage documentation
403
+ * Publishes every coverage HTML report the deploy declares, each at `docs/coverage/<id>`.
404
+ *
405
+ * Never generates one: a report belongs to the test stage, which bundles it into the
406
+ * deploy artifact (see {@link module:src/server/build/coverage.js}). A client build that
407
+ * shelled out to `npm test` here spent minutes of a pod's build phase on a runner the
408
+ * workload has no business holding, and every expected non-zero exit of that suite latched
409
+ * `container-status=error`, failing the deployment monitor on a healthy rollout.
381
410
  * @function buildCoverage
382
411
  * @memberof clientBuildDocs
383
412
  * @param {Object} options - Coverage build options
384
413
  * @param {Object} options.docs - Documentation config from server conf
385
- * @param {string} options.docs.coveragePath - Directory where coverage reports are generated
414
+ * @param {Array<{id: string, label?: string, suite?: string, path?: string}>} [options.docs.coverage] - Declared reports
386
415
  * @param {string} options.docsDestination - Resolved output path where docs were built
387
416
  */
388
417
  const buildCoverage = async ({ docs, docsDestination }) => {
389
418
  const logger = loggerFactory(import.meta);
390
- const { coveragePath, coverageOutputDir = 'coverage' } = docs;
419
+ const reports = coverageReportsFactory(docs);
420
+ if (reports.length === 0) return;
421
+ // The route holds exactly the declared reports: one dropped from the conf leaves with it.
422
+ fs.emptyDirSync(`${docsDestination}coverage`);
423
+ for (const report of reports) {
424
+ const coverageBuildPath = `${docsDestination}coverage/${report.id}`;
425
+ const reportPath = resolveCoverageReportPath(report);
391
426
 
392
- const coverageOutputPath = `${coveragePath}/coverage`;
393
- if (!fs.existsSync(coverageOutputPath)) {
394
- const pkgPath = `${coveragePath}/package.json`;
395
- if (fs.existsSync(pkgPath)) {
396
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
397
- if (pkg.scripts && pkg.scripts.coverage) {
398
- logger.info('generating coverage report', coveragePath);
399
- try {
400
- await shellExec(`cd ${coveragePath} && npm run coverage`, { silent: true });
401
- } catch (err) {
402
- logger.warn('coverage generation failed (non-fatal), skipping:', err.message);
403
- return;
404
- }
405
- } else if (pkg.scripts && pkg.scripts.test) {
406
- logger.info('generating coverage via test', coveragePath);
407
- try {
408
- await shellExec(`cd ${coveragePath} && npm test`, { silent: true, silentOnError: true });
409
- } catch (err) {
410
- logger.warn('coverage generation failed (non-fatal), skipping:', err.message);
411
- return;
412
- }
413
- }
427
+ if (!reportPath) {
428
+ fs.outputFileSync(`${coverageBuildPath}/index.html`, coverageUnavailablePage(report), 'utf8');
429
+ logger.warn('no coverage report bundled, publishing the unavailable page', {
430
+ id: report.id,
431
+ searched: coverageReportCandidates(report),
432
+ published: coverageBuildPath,
433
+ });
434
+ continue;
414
435
  }
415
- }
416
436
 
417
- if (fs.existsSync(coverageOutputPath) && fs.readdirSync(coverageOutputPath).length > 0) {
418
- const coverageBuildPath = `${docsDestination}${coverageOutputDir}`;
419
- fs.mkdirSync(coverageBuildPath, { recursive: true });
420
- // Hardhat 3 outputs HTML to coverage/html/; Hardhat 2 / c8 output directly to coverage/
421
- const coverageHtmlSubdir = `${coverageOutputPath}/html`;
422
- if (fs.existsSync(coverageHtmlSubdir) && fs.existsSync(`${coverageHtmlSubdir}/index.html`)) {
423
- fs.copySync(coverageHtmlSubdir, coverageBuildPath);
424
- } else {
425
- fs.copySync(coverageOutputPath, coverageBuildPath);
426
- }
437
+ fs.copySync(reportPath, coverageBuildPath);
427
438
  logger.warn('build coverage', coverageBuildPath);
428
- } else {
429
- logger.warn('no coverage output found, skipping', coverageOutputPath);
430
439
  }
431
440
  };
432
441
 
@@ -438,6 +447,8 @@ const buildCoverage = async ({ docs, docsDestination }) => {
438
447
  * @param {string} options.host - The hostname
439
448
  * @param {string} options.path - The base path
440
449
  * @param {number} options.port - The port number
450
+ * @param {string} [options.apiBaseHost] - Host serving the API when it is split from the client
451
+ * @param {string} [options.apiBaseProxyPath] - Proxy path of the API runtime when it is split from the client
441
452
  * @param {Object} options.metadata - Metadata for the documentation
442
453
  * @param {Array<string>} options.apis - List of API modules to document
443
454
  * @param {string} options.publicClientId - Client ID for the public documentation
@@ -449,6 +460,8 @@ const buildDocs = async ({
449
460
  host,
450
461
  path,
451
462
  port,
463
+ apiBaseHost,
464
+ apiBaseProxyPath,
452
465
  metadata = {},
453
466
  apis = [],
454
467
  publicClientId,
@@ -460,7 +473,7 @@ const buildDocs = async ({
460
473
  // TypeDoc output is versioned: served at /docs/engine/{version}/
461
474
  const version = (packageData?.version || '').replace(/^v/, '');
462
475
  const jsDocsDestination = `./public/${host}${pathPrefix}docs/engine/${version}/`;
463
- // Coverage output at /docs/coverage/ (or /docs/{coverageOutputDir}/)
476
+ // Coverage reports at /docs/coverage/<id>/
464
477
  const coverageBaseDestination = `./public/${host}${pathPrefix}docs/`;
465
478
  await buildJsDocs({ host, path, metadata, publicClientId, docs, docsDestination: jsDocsDestination });
466
479
  await buildCoverage({ docs, docsDestination: coverageBaseDestination });
@@ -468,6 +481,8 @@ const buildDocs = async ({
468
481
  host,
469
482
  path,
470
483
  port,
484
+ apiBaseHost,
485
+ apiBaseProxyPath,
471
486
  metadata,
472
487
  apis,
473
488
  publicClientId,
@@ -490,4 +505,4 @@ const buildSwaggerUiOptions = async () => {
490
505
  return { customCss: css, customJsStr: js };
491
506
  };
492
507
 
493
- export { buildDocs, buildSwaggerUiOptions };
508
+ export { buildCoverage, buildDocs, buildSwaggerUiOptions };
@@ -5,8 +5,8 @@
5
5
  */
6
6
 
7
7
  import fs from 'fs-extra';
8
- import { Config, loadConf, readConfJson } from '../server/conf.js';
9
- import { loggerFactory } from '../server/logger.js';
8
+ import { Config, loadConf, readConfJson } from '../server/runtime/conf.js';
9
+ import { loggerFactory } from '../server/ops/logger.js';
10
10
  import { buildClient } from './client-build.js';
11
11
 
12
12
  const logger = loggerFactory(import.meta);
@@ -8,24 +8,26 @@
8
8
 
9
9
  import fs from 'fs-extra';
10
10
  import { transformClientJs, JSONweb } from './client-formatted.js';
11
- import { loggerFactory } from '../server/logger.js';
11
+ import { loggerFactory } from '../server/ops/logger.js';
12
12
  import {
13
13
  getCapVariableName,
14
14
  newInstance,
15
15
  orderArrayFromAttrInt,
16
16
  uniqueArray,
17
17
  } from '../client/components/core/CommonJs.js';
18
- import { readConfJson } from '../server/conf.js';
18
+ import { readConfJson } from '../server/runtime/conf.js';
19
19
  import { minify } from 'html-minifier-terser';
20
- import AdmZip from 'adm-zip';
20
+ import { extractZipTo, findZipEntry, isZipBuffer, loadZip, zipFromLocalFiles } from '../server/storage/zip.js';
21
21
  import * as dir from 'path';
22
- import { shellExec } from '../server/process.js';
22
+ import { shellExec } from '../server/runtime/process.js';
23
23
  import { SitemapStream, streamToPromise } from 'sitemap';
24
24
  import { Readable } from 'stream';
25
25
  import { buildIcons } from './client-icons.js';
26
- import { statusPageBuildSegment } from '../server/underpost-gateway.js';
26
+ import { statusPageBuildSegment } from '../server/network/underpost-gateway.js';
27
+ import { repositoryIdentityFactory } from '../server/storage/repository.js';
27
28
  import Underpost from '../index.js';
28
29
  import { buildDocs } from './client-build-docs.js';
30
+ import { coverageReportsFactory } from '../server/build/coverage.js';
29
31
  import { ssrFactory } from './ssr.js';
30
32
 
31
33
  // Static Site Generation (SSG)
@@ -179,6 +181,17 @@ const splitFileByMb = ({ filePath, partSizeMb, logger }) => {
179
181
  return partPaths;
180
182
  };
181
183
 
184
+ /**
185
+ * Names the zip artifact a served route builds to. Single source of truth for the bundle
186
+ * identity: the build writes `<id>.zip`, and push/pull address the same file by this name.
187
+ * @function clientBundleIdFactory
188
+ * @param {string} host - The served host.
189
+ * @param {string} routePath - The route's proxy sub-path (`/`, `/peer`, ...).
190
+ * @returns {string} The bundle id, e.g. `underpost.net-` for `/` or `underpost.net-peer`.
191
+ * @memberof clientBuild
192
+ */
193
+ const clientBundleIdFactory = (host, routePath) => `${host}-${`${routePath ?? ''}`.replaceAll('/', '')}`;
194
+
182
195
  const getZipPartPaths = (zipPath) => {
183
196
  const zipDir = dir.dirname(zipPath);
184
197
  const zipBase = dir.basename(zipPath);
@@ -268,9 +281,9 @@ const resolveClientBuildZip = (buildPrefix) => {
268
281
  * @param {object} options
269
282
  * @param {string} options.buildPrefix - The build prefix path (e.g. build/underpost.net/underpost.net-).
270
283
  * @param {object} options.logger - Logger instance.
271
- * @returns {{ zipPath: string, partPaths: string[], mergedBytes: number }}
284
+ * @returns {Promise<{ zipPath: string, partPaths: string[], mergedBytes: number }>}
272
285
  */
273
- const mergeClientBuildZip = ({ buildPrefix, logger }) => {
286
+ const mergeClientBuildZip = async ({ buildPrefix, logger }) => {
274
287
  // Normalize to get the zip path, then look for parts directly (bypassing resolveClientBuildZip
275
288
  // which prefers an existing monolithic zip over parts).
276
289
  const normalizedPrefix = buildPrefix.replace(/\.zip(?:[.-]part\d+)?$/, '').replace(/[-.]$/, '') + '-';
@@ -300,31 +313,41 @@ const mergeClientBuildZip = ({ buildPrefix, logger }) => {
300
313
  // For each part, extract raw bytes: if the part file is a Cloudinary wrapper zip
301
314
  // (downloaded via pull without --omit-unzip or with --omit-unzip keeping the .zip),
302
315
  // extract the inner entry rather than using the wrapper bytes.
303
- const readPartBytes = (partPath) => {
316
+ const readPartBytes = async (partPath) => {
304
317
  const rawBytes = fs.readFileSync(partPath);
305
- // Check for ZIP magic bytes (PK\x03\x04)
306
- if (rawBytes[0] === 0x50 && rawBytes[1] === 0x4b && rawBytes[2] === 0x03 && rawBytes[3] === 0x04) {
307
- try {
308
- const wrapperZip = new AdmZip(rawBytes);
309
- const entries = wrapperZip.getEntries();
310
- // The inner entry is the original part file (without the outer .zip wrapper)
311
- const partBase = dir.basename(partPath).replace(/\.zip$/i, '');
312
- const entry = entries.find((e) => e.entryName === partBase || e.entryName.endsWith('/' + partBase));
313
- if (entry) {
314
- return entry.getData();
315
- }
316
- // Fallback: single-entry archive
317
- if (entries.length === 1) {
318
- return entries[0].getData();
319
- }
320
- } catch (_) {
321
- // Not a valid zip or extraction failed — use raw bytes
322
- }
318
+ if (!isZipBuffer(rawBytes)) return rawBytes;
319
+
320
+ let wrapper;
321
+ try {
322
+ wrapper = await loadZip(rawBytes);
323
+ } catch (_) {
324
+ // A raw split part carries the zip signature but no central directory, so failing to load
325
+ // is how a part that was never wrapped identifies itself.
326
+ return rawBytes;
323
327
  }
324
- return rawBytes;
328
+
329
+ // A part pulled from storage arrives inside the archive the download produced. Falling back
330
+ // to that wrapper's own bytes merges compressed data into the bundle and surfaces much later
331
+ // as a corrupt archive, so a wrapper whose part cannot be found fails here and names itself.
332
+ const entry = findZipEntry(wrapper, dir.basename(partPath).replace(/\.zip$/i, ''));
333
+ if (!entry) throw new Error(`Bundle part wrapper holds no matching entry: ${partPath}`);
334
+ return await entry.async('nodebuffer');
325
335
  };
326
336
 
327
- const mergedBuffer = Buffer.concat(partPaths.map(readPartBytes));
337
+ const partBuffers = [];
338
+ for (const partPath of partPaths) partBuffers.push(await readPartBytes(partPath));
339
+ const mergedBuffer = Buffer.concat(partBuffers);
340
+
341
+ // A short part anywhere in the sequence only shows up as a byte count against the assembled
342
+ // archive, which names nothing. Reporting each part's contribution is what makes the one that
343
+ // came up short identifiable.
344
+ logger.info('merge-zip: part sizes', {
345
+ zipPath,
346
+ parts: partPaths.map((partPath, index) => ({
347
+ part: dir.basename(partPath),
348
+ bytes: partBuffers[index].length,
349
+ })),
350
+ });
328
351
  fs.writeFileSync(zipPath, mergedBuffer);
329
352
 
330
353
  logger.warn('merge-zip: merged split parts into zip', {
@@ -336,19 +359,16 @@ const mergeClientBuildZip = ({ buildPrefix, logger }) => {
336
359
  return { zipPath, partPaths, mergedBytes: mergedBuffer.length };
337
360
  };
338
361
 
339
- const unzipClientBuild = ({ buildPrefix, logger }) => {
362
+ const unzipClientBuild = async ({ buildPrefix, logger }) => {
340
363
  const { zipPath, partPaths, buildPrefix: resolvedBuildPrefix } = resolveClientBuildZip(buildPrefix);
341
364
  const outputPath = resolvedBuildPrefix.replace(/-$/, '');
342
365
 
343
366
  fs.removeSync(outputPath);
344
- fs.mkdirSync(outputPath, { recursive: true });
345
-
346
- const zip =
347
- partPaths.length > 0
348
- ? new AdmZip(Buffer.concat(partPaths.map((partPath) => fs.readFileSync(partPath))))
349
- : new AdmZip(zipPath);
350
367
 
351
- zip.extractAllTo(outputPath, true);
368
+ await extractZipTo(
369
+ partPaths.length > 0 ? Buffer.concat(partPaths.map((partPath) => fs.readFileSync(partPath))) : zipPath,
370
+ outputPath,
371
+ );
352
372
 
353
373
  logger.warn('unzip build', {
354
374
  source: partPaths.length > 0 ? partPaths : [zipPath],
@@ -533,6 +553,7 @@ const defaultSitemapXsl = `<?xml version="1.0" encoding="UTF-8"?>
533
553
  const buildClient = async (
534
554
  options = {
535
555
  deployId: '',
556
+ subConf: '',
536
557
  liveClientBuildPaths: [],
537
558
  instances: [],
538
559
  buildZip: false,
@@ -543,9 +564,13 @@ const buildClient = async (
543
564
  ) => {
544
565
  const logger = loggerFactory(import.meta);
545
566
  const deployId = options.deployId || process.env.DEPLOY_ID;
546
- const confClient = readConfJson(deployId, 'client');
547
- const confServer = readConfJson(deployId, 'server', { loadReplicas: true });
548
- const confSSR = readConfJson(deployId, 'ssr');
567
+ // Carried as an argument rather than re-derived from DEPLOY_SUB_CONF: the caller already
568
+ // resolved which sub-configuration this build is for, and a build that reads a different
569
+ // conf.server than the one its caller loaded renders the wrong set of hosts.
570
+ const subConf = `${options.subConf ?? ''}`.trim();
571
+ const confClient = readConfJson(deployId, 'client', { subConf });
572
+ const confServer = readConfJson(deployId, 'server', { subConf, loadReplicas: true });
573
+ const confSSR = readConfJson(deployId, 'ssr', { subConf });
549
574
  const packageData = JSON.parse(fs.readFileSync(`./package.json`, 'utf8'));
550
575
  const acmeChallengePath = `/.well-known/acme-challenge`;
551
576
  const publicPath = `./public`;
@@ -689,6 +714,20 @@ const buildClient = async (
689
714
  // ''; // process.env.NODE_ENV === 'production' ? `https://${host}` : ``;
690
715
  currentPort++;
691
716
 
717
+ // Every document this instance emits carries the same payload; the SSR
718
+ // views and the client index must never disagree about which repository
719
+ // published them.
720
+ const renderPayload = {
721
+ apiBaseProxyPath,
722
+ apiBaseHost,
723
+ apiBasePath: process.env.BASE_API,
724
+ version: Underpost.version,
725
+ repository: repositoryIdentityFactory(),
726
+ // The reports the docs menu offers, each published at /docs/coverage/<id>.
727
+ coverage: coverageReportsFactory(docs).map(({ id, label }) => ({ id, label })),
728
+ ...(isDevelopment ? { dev: true } : undefined),
729
+ };
730
+
692
731
  const acmeChallengeFullPath = directory
693
732
  ? `${directory}${acmeChallengePath}`
694
733
  : `${publicPath}/${host}${acmeChallengePath}`;
@@ -815,14 +854,12 @@ const buildClient = async (
815
854
  }
816
855
 
817
856
  if (!ssrOnly && views) {
818
- if (
819
- !(
820
- enableLiveRebuild &&
821
- !options.liveClientBuildPaths.find(
822
- (p) => p.srcBuildPath.startsWith(`./src/client/ssr`) || p.srcBuildPath.slice(-9) === '.index.js',
823
- )
857
+ if (!(
858
+ enableLiveRebuild &&
859
+ !options.liveClientBuildPaths.find(
860
+ (p) => p.srcBuildPath.startsWith(`./src/client/ssr`) || p.srcBuildPath.slice(-9) === '.index.js',
824
861
  )
825
- )
862
+ ))
826
863
  for (const view of views) {
827
864
  const buildPath = `${
828
865
  rootClientPath[rootClientPath.length - 1] === '/' ? rootClientPath.slice(0, -1) : rootClientPath
@@ -854,7 +891,7 @@ const buildClient = async (
854
891
  confSSR[view.ssr].head.unshift('Production');
855
892
 
856
893
  for (const ssrHeadComponent of confSSR[view.ssr].head) {
857
- const SrrComponent = await ssrFactory(`./src/client/ssr/head/${ssrHeadComponent}.js`);
894
+ const SSRComponent = await ssrFactory(`./src/client/ssr/head/${ssrHeadComponent}.js`);
858
895
 
859
896
  switch (ssrHeadComponent) {
860
897
  case 'Pwa':
@@ -909,11 +946,11 @@ const buildClient = async (
909
946
  // ],
910
947
  // "prefer_related_applications": true
911
948
  }
912
- if (validPwaBuild) ssrHeadComponents += SrrComponent({ title, ssrPath, canonicalURL, ...metadata });
949
+ if (validPwaBuild) ssrHeadComponents += SSRComponent({ title, ssrPath, canonicalURL, ...metadata });
913
950
  break;
914
951
  case 'Seo':
915
952
  if (metadata) {
916
- ssrHeadComponents += SrrComponent({ title, ssrPath, canonicalURL, ...metadata });
953
+ ssrHeadComponents += SSRComponent({ title, ssrPath, canonicalURL, ...metadata });
917
954
  }
918
955
  break;
919
956
  case 'Microdata':
@@ -925,18 +962,18 @@ const buildClient = async (
925
962
  const microdata = JSON.parse(
926
963
  fs.readFileSync(`./src/client/public/${publicClientId}/microdata.json`, 'utf8'),
927
964
  );
928
- ssrHeadComponents += SrrComponent({ microdata });
965
+ ssrHeadComponents += SSRComponent({ microdata });
929
966
  }
930
967
  break;
931
968
  default:
932
- ssrHeadComponents += SrrComponent({ ssrPath, host, path });
969
+ ssrHeadComponents += SSRComponent({ ssrPath, host, path });
933
970
  break;
934
971
  }
935
972
  }
936
973
 
937
974
  for (const ssrBodyComponent of confSSR[view.ssr].body) {
938
- const SrrComponent = await ssrFactory(`./src/client/ssr/body/${ssrBodyComponent}.js`);
939
- ssrBodyComponents += SrrComponent({
975
+ const SSRComponent = await ssrFactory(`./src/client/ssr/body/${ssrBodyComponent}.js`);
976
+ ssrBodyComponents += SSRComponent({
940
977
  ...metadata,
941
978
  ssrPath,
942
979
  host,
@@ -962,13 +999,7 @@ const buildClient = async (
962
999
  ssrPath,
963
1000
  ssrHeadComponents,
964
1001
  ssrBodyComponents,
965
- renderPayload: {
966
- apiBaseProxyPath,
967
- apiBaseHost,
968
- apiBasePath: process.env.BASE_API,
969
- version: Underpost.version,
970
- ...(isDevelopment ? { dev: true } : undefined),
971
- },
1002
+ renderPayload,
972
1003
  renderApi: {
973
1004
  JSONweb,
974
1005
  },
@@ -1031,6 +1062,8 @@ Sitemap: ${sitemapBaseUrl}/sitemap.xml`,
1031
1062
  host,
1032
1063
  path,
1033
1064
  port,
1065
+ apiBaseHost,
1066
+ apiBaseProxyPath,
1034
1067
  metadata,
1035
1068
  apis,
1036
1069
  publicClientId,
@@ -1064,13 +1097,7 @@ Sitemap: ${sitemapBaseUrl}/sitemap.xml`,
1064
1097
  ssrPath,
1065
1098
  ssrHeadComponents: '<base target="_top">',
1066
1099
  ssrBodyComponents: SsrComponent(),
1067
- renderPayload: {
1068
- apiBaseProxyPath,
1069
- apiBaseHost,
1070
- apiBasePath: process.env.BASE_API,
1071
- version: Underpost.version,
1072
- ...(isDevelopment ? { dev: true } : undefined),
1073
- },
1100
+ renderPayload,
1074
1101
  renderApi: { JSONweb },
1075
1102
  });
1076
1103
 
@@ -1116,7 +1143,7 @@ Sitemap: ${sitemapBaseUrl}/sitemap.xml`,
1116
1143
 
1117
1144
  if (swShouldRebuild) {
1118
1145
  const cacheScope = path === '/' ? 'root' : path.replaceAll('/', '_');
1119
- const renderPayload = {
1146
+ const swRenderPayload = {
1120
1147
  PRE_CACHED_RESOURCES: uniqueArray(PRE_CACHED_RESOURCES),
1121
1148
  PROXY_PATH: path,
1122
1149
  CACHE_PREFIX: `engine-core-${cacheScope}`,
@@ -1127,7 +1154,7 @@ Sitemap: ${sitemapBaseUrl}/sitemap.xml`,
1127
1154
  // Single write: prepend the payload prelude to the transformed SW JS.
1128
1155
  fs.writeFileSync(
1129
1156
  swPublicPath,
1130
- `self.renderPayload = ${JSONweb(renderPayload)};
1157
+ `self.renderPayload = ${JSONweb(swRenderPayload)};
1131
1158
  self.__WB_DISABLE_DEV_LOGS = true;
1132
1159
  ${swTransformedJs}`,
1133
1160
  'utf8',
@@ -1139,23 +1166,25 @@ ${swTransformedJs}`,
1139
1166
 
1140
1167
  if (!fs.existsSync('./build')) fs.mkdirSync('./build');
1141
1168
 
1142
- const zip = new AdmZip();
1143
1169
  const files = await fs.readdir(rootClientPath, { recursive: true });
1170
+ const zipEntries = [];
1144
1171
 
1145
1172
  for (const relativePath of files) {
1146
1173
  const filePath = dir.resolve(`${rootClientPath}/${relativePath}`);
1147
1174
  if (!fs.lstatSync(filePath).isDirectory()) {
1148
1175
  const folder = dir.relative(`public/${host}${path}`, dir.dirname(filePath));
1149
- zip.addLocalFile(filePath, folder);
1176
+ zipEntries.push({
1177
+ localPath: filePath,
1178
+ entryName: folder ? `${folder}/${dir.basename(filePath)}` : dir.basename(filePath),
1179
+ });
1150
1180
  }
1151
1181
  }
1152
1182
 
1153
- const buildId = `${host}-${path.replaceAll('/', '')}`;
1154
- const zipPath = `./build/${buildId}.zip`;
1183
+ const zipPath = `./build/${clientBundleIdFactory(host, path)}.zip`;
1155
1184
 
1156
1185
  logger.warn('write zip', zipPath);
1157
1186
 
1158
- zip.writeZip(zipPath);
1187
+ fs.writeFileSync(zipPath, await zipFromLocalFiles(zipEntries));
1159
1188
 
1160
1189
  if (options.split) {
1161
1190
  splitFileByMb({
@@ -1173,7 +1202,9 @@ ${swTransformedJs}`,
1173
1202
 
1174
1203
  export {
1175
1204
  buildClient,
1205
+ clientBundleIdFactory,
1176
1206
  copyNonExistingFiles,
1207
+ getZipPartPaths,
1177
1208
  unzipClientBuild,
1178
1209
  mergeClientBuildZip,
1179
1210
  staticContextRoutesFactory,