@underpostnet/cyberia 3.3.73 → 3.3.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +17 -5
- package/.github/workflows/coverall.cyberia.ci.yml +10 -0
- package/.github/workflows/docker-image.cyberia-client.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-server.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +1 -1
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +1 -1
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +1 -1
- package/.github/workflows/engine-cyberia.ci.yml +1 -1
- package/.github/workflows/publish.cyberia.ci.yml +44 -0
- package/AGENTS.md +61 -12
- package/CHANGELOG.md +159 -161
- package/CLI-HELP.md +20 -13
- package/Dockerfile +1 -1
- package/Dockerfile.dev +1 -1
- package/Dockerfile.test +2 -2
- package/README.md +28 -28
- package/bin/build.js +96 -21
- package/bin/cyberia.js +1247 -1373
- package/bin/index.js +1247 -1373
- package/compose.env +17 -5
- package/conf.js +7 -4
- package/deploy/cyberia-client/deploy.sh +10 -11
- package/deploy/cyberia-client/package.sh +0 -1
- package/deploy/cyberia-client/state.sh +3 -2
- package/deploy/cyberia-server/deploy.sh +10 -11
- package/deploy/cyberia-server/package.sh +0 -1
- package/deploy/cyberia-server/state.sh +3 -2
- package/deploy/dd-cyberia/deploy.sh +5 -5
- package/deploy/dd-cyberia/init.sh +15 -14
- package/deploy/dd-cyberia/package.sh +0 -1
- package/deploy/dd-cyberia/state.sh +2 -2
- package/deploy/dd-cyberia/sync-deploy.sh +139 -75
- package/deploy/lib/config.sh +29 -0
- package/deploy/lib/github-actions-logging.sh +92 -76
- package/deploy/lib/host.sh +28 -19
- package/deploy/lib/state.sh +4 -1
- package/deploy/pwa-microservices-template/deploy.sh +10 -8
- package/deploy/release/deploy.sh +0 -2
- package/deployment.yaml +1 -1
- package/docker-compose.yml +23 -17
- package/docs/coverage/cyberia/api/cyberia-instance/cyberia-fallback-capture.js.html +1591 -0
- package/docs/coverage/cyberia/api/cyberia-instance/index.html +116 -0
- package/docs/coverage/cyberia/api/cyberia-server-defaults/cyberia-server-defaults.js.html +4138 -0
- package/docs/coverage/cyberia/api/cyberia-server-defaults/index.html +116 -0
- package/docs/coverage/cyberia/api/object-layer/index.html +116 -0
- package/docs/coverage/cyberia/api/object-layer/object-layer.model.js.html +1393 -0
- package/docs/coverage/cyberia/base.css +362 -0
- package/docs/coverage/cyberia/block-navigation.js +82 -0
- package/docs/coverage/cyberia/favicon.png +0 -0
- package/docs/coverage/cyberia/index.html +161 -0
- package/docs/coverage/cyberia/prettify.css +101 -0
- package/docs/coverage/cyberia/prettify.js +937 -0
- package/docs/coverage/cyberia/projects/cyberia/atlas-sprite-sheet-generator.js.html +1315 -0
- package/docs/coverage/cyberia/projects/cyberia/index.html +176 -0
- package/docs/coverage/cyberia/projects/cyberia/instance-backup.js.html +715 -0
- package/docs/coverage/cyberia/projects/cyberia/instance-data.js.html +2182 -0
- package/docs/coverage/cyberia/projects/cyberia/shape-generator.js.html +3265 -0
- package/docs/coverage/cyberia/projects/cyberia/stat-balance.js.html +328 -0
- package/docs/coverage/cyberia/sort-arrow-sprite.png +0 -0
- package/docs/coverage/cyberia/sorter.js +205 -0
- package/hardhat/package-lock.json +2 -2
- package/hardhat/package.json +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +1 -1
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/mongo-express/deployment.yaml +46 -27
- package/manifests/deployment/mongo-express/kustomization.yaml +9 -0
- package/manifests/deployment/mongo-express/mongo-express-nodeport.yaml +18 -0
- package/manifests/deployment/mongo-express/service.yaml +16 -0
- package/manifests/deployment/mongo-express-no-auth/disable-mongodb-auth.yaml +16 -0
- package/manifests/deployment/mongo-express-no-auth/kustomization.yaml +16 -0
- package/package.json +19 -17
- package/scripts/test-monitor.sh +3 -3
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +14 -9
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +88 -184
- package/src/api/cyberia-action/cyberia-action.router.js +2 -2
- package/src/api/cyberia-action/cyberia-action.service.js +3 -4
- package/src/api/cyberia-audio/cyberia-audio.controller.js +6 -0
- package/src/api/cyberia-audio/cyberia-audio.model.js +61 -0
- package/src/api/cyberia-audio/cyberia-audio.router.js +21 -0
- package/src/api/cyberia-audio/cyberia-audio.service.js +220 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -3
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +12 -34
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +15 -32
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
- package/src/api/cyberia-entity/cyberia-entity.service.js +1 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +8 -2
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +31 -20
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +16 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +466 -3
- package/src/api/cyberia-instance/cyberia-fallback-capture.js +87 -51
- package/src/api/cyberia-instance/cyberia-fallback-world.js +21 -40
- package/src/api/cyberia-instance/cyberia-instance-boot.service.js +5 -5
- package/src/api/cyberia-instance/cyberia-instance-items.js +98 -0
- package/src/api/cyberia-instance/cyberia-instance-map.service.js +34 -141
- package/src/api/cyberia-instance/cyberia-instance.controller.js +1 -4
- package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
- package/src/api/cyberia-instance/cyberia-instance.router.js +3 -16
- package/src/api/cyberia-instance/cyberia-instance.service.js +3 -43
- package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +74 -1
- package/src/api/cyberia-map/cyberia-map.service.js +6 -2
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.controller.js +31 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.model.js +56 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.router.js +33 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +189 -0
- package/src/api/cyberia-quest/cyberia-quest.router.js +3 -3
- package/src/api/cyberia-quest/cyberia-quest.service.js +3 -3
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -188
- package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
- package/src/api/file/file.ref.js +153 -0
- package/src/api/file/file.ref.json +11 -2
- package/src/api/object-layer/object-layer.model.js +47 -12
- package/src/api/object-layer/object-layer.router.js +10 -3
- package/src/api/object-layer/object-layer.service.js +113 -120
- package/src/cli/app.js +12 -1
- package/src/cli/client.js +2 -2
- package/src/cli/cluster.js +80 -18
- package/src/cli/deploy.js +215 -34
- package/src/cli/docker-compose.js +1 -1
- package/src/cli/fs-selection.js +115 -0
- package/src/cli/fs.js +158 -342
- package/src/cli/index.js +22 -10
- package/src/cli/release.js +3 -1
- package/src/cli/repository.js +35 -9
- package/src/cli/run.js +80 -199
- package/src/cli/test.js +4 -0
- package/src/cli/wireguard.js +32 -31
- package/src/client/components/core/Badge.js +0 -1
- package/src/client/components/core/CssCore.js +8 -1
- package/src/client/components/core/Docs.js +77 -100
- package/src/client/components/core/Modal.js +77 -23
- package/src/client/components/core/ToolTip.js +15 -0
- package/src/client/components/cryptokoyn/AppShellCryptokoyn.js +0 -2
- package/src/client/components/cyberia/ActionEngineCyberia.js +12 -36
- package/src/client/components/cyberia/EntityEngineCyberia.js +492 -121
- package/src/client/components/cyberia/InstanceEngineCyberia.js +129 -160
- package/src/client/components/cyberia/InstanceSelectionView.js +7 -1
- package/src/client/components/cyberia/MapEngineCyberia.js +175 -69
- package/src/client/components/cyberia/ObjectLayerEngine.js +1011 -97
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +81 -155
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +113 -98
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +215 -56
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +0 -34
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +1 -1
- package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +712 -76
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +0 -4
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
- package/src/client/components/default/AppShellDefault.js +1 -4
- package/src/client/components/itemledger/AppShellItemledger.js +0 -2
- package/src/client/components/underpost/AppShellUnderpost.js +1 -1
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +280 -24
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +51 -29
- package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +52 -53
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +16 -11
- package/src/client/public/cyberia-docs/CYBERIA.md +28 -28
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/STATS-PROGRESSION.md +217 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +20 -12
- package/src/client/services/cyberia-audio/cyberia-audio.service.js +99 -0
- package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +38 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +5 -4
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +0 -40
- package/src/client/services/cyberia-map/cyberia-map.management.js +5 -4
- package/src/client/services/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +138 -0
- package/src/client/services/object-layer/object-layer.management.js +6 -10
- package/src/client/services/object-layer/object-layer.service.js +3 -1
- package/src/client/ssr/views/Cyberia404.js +3 -3
- package/src/client-builder/client-build-docs.js +52 -52
- package/src/client-builder/client-build.js +67 -44
- package/src/client-builder/client-bundle.js +347 -0
- package/src/db/mongo/MongoExpress.js +187 -0
- package/src/grpc/cyberia/grpc-server.js +5 -7
- package/src/index.js +1 -1
- package/src/projects/cyberia/atlas-sprite-sheet-generator.js +143 -146
- package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
- package/src/projects/cyberia/besu-genesis-generator.js +5 -14
- package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
- package/src/projects/cyberia/catalog-cyberia.js +3 -2
- package/src/projects/cyberia/gemini-client.js +3 -3
- package/src/projects/cyberia/generate-saga.js +4 -11
- package/src/projects/cyberia/hot-reload-trigger.js +17 -28
- package/src/projects/cyberia/instance-backup.js +210 -0
- package/src/projects/cyberia/instance-data.js +177 -257
- package/src/projects/cyberia/map-preview-generator.js +32 -68
- package/src/projects/cyberia/object-layer.js +152 -319
- package/src/projects/cyberia/seed-audio.js +139 -0
- package/src/projects/cyberia/semantic-layer-generator-skin.js +2 -8
- package/src/projects/cyberia/semantic-layer-generator.js +2 -18
- package/src/projects/cyberia/stat-balance.js +81 -0
- package/src/projects/cyberia/stat-commands.js +23 -0
- package/src/projects/cyberia/stat-contract-generator.js +101 -0
- package/src/runtime/cyberia-client/Dockerfile +8 -4
- package/src/runtime/cyberia-client/Dockerfile.dev +5 -2
- package/src/runtime/cyberia-server/Dockerfile +9 -2
- package/src/runtime/cyberia-server/Dockerfile.dev +8 -1
- package/src/runtime/engine-cyberia/Dockerfile +1 -1
- package/src/runtime/engine-cyberia/Dockerfile.dev +1 -1
- package/src/runtime/engine-cyberia/Dockerfile.test +2 -2
- package/src/runtime/engine-cyberia/compose.env +17 -5
- package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
- package/src/server/build/coverage.js +113 -42
- package/src/server/build/package.js +55 -12
- package/src/server/build/testing.js +59 -9
- package/src/server/network/middlewares.js +8 -2
- package/src/server/network/underpost-gateway.js +113 -14
- package/src/server/ops/logger.js +70 -35
- package/src/server/runtime/conf.js +40 -9
- package/src/server/runtime/start.js +11 -2
- package/src/server/storage/data-query.js +16 -0
- package/src/server/storage/downloader.js +62 -14
- package/src/server/storage/zip.js +153 -0
- package/test/integration/app/cyberia/atlas-sprite-sheet-store.test.js +402 -0
- package/test/integration/app/cyberia/atlas-sprite-sheet.test.js +86 -0
- package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +34 -0
- package/test/integration/app/cyberia/cyberia-entity-type-default.test.js +842 -0
- package/test/integration/app/cyberia/cyberia-instance-conf-coerce.test.js +53 -0
- package/test/integration/app/cyberia/cyberia-instance-conf-defaults.test.js +16 -22
- package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
- package/test/integration/app/cyberia/cyberia-load.test.js +6 -7
- package/test/integration/app/cyberia/cyberia-map-audio-conf.test.js +256 -0
- package/test/integration/app/cyberia/cyberia-stats.test.js +150 -0
- package/test/integration/app/cyberia/fallback-world-capture.test.js +87 -2
- package/test/integration/app/cyberia/object-layer-item-selection.test.js +56 -0
- package/test/integration/app/cyberia/object-layer-natural-key.test.js +32 -0
- package/test/integration/app/cyberia/seed-audio.test.js +275 -0
- package/test/integration/infra/2-network/wireguard-cli.test.js +33 -9
- package/test/integration/infra/2-network/wireguard-edge.test.js +58 -18
- package/test/integration/infra/3-cluster/mongo-express-deploy.test.js +156 -0
- package/test/integration/infra/4-ingress/api-cross-origin.test.js +79 -0
- package/test/integration/infra/4-ingress/underpost-ingress.test.js +1 -1
- package/test/unit/catalog.test.js +13 -2
- package/test/unit/client-build-docs.test.js +97 -70
- package/test/unit/client-bundle.test.js +313 -0
- package/test/unit/conf-resolution.test.js +58 -7
- package/test/unit/coverage-artifact.test.js +120 -29
- package/test/unit/cyberia/instance-backup.test.js +183 -0
- package/test/unit/cyberia/instance-data.test.js +314 -0
- package/test/unit/cyberia/instance-object-layer-items.test.js +46 -0
- package/test/unit/cyberia/publish-workflow.test.js +22 -0
- package/test/unit/cyberia/stat-balance.test.js +69 -0
- package/test/unit/deploy-legacy-gateway-sweep.test.js +63 -0
- package/test/unit/deploy-log-table.test.js +76 -5
- package/test/unit/downloader-integrity.test.js +98 -0
- package/test/unit/file-reference-registry.test.js +141 -0
- package/test/unit/fs-storage-paths.test.js +596 -0
- package/test/unit/gateway-pod-fetch.test.js +95 -0
- package/test/unit/letsencrypt-issuer.test.js +101 -0
- package/test/unit/logger-redaction.test.js +29 -0
- package/test/unit/package.test.js +70 -16
- package/test/unit/prepare-host.test.js +84 -1
- package/test/unit/release-bump.test.js +3 -1
- package/test/unit/start-options.test.js +12 -0
- package/test/unit/test-tiers.test.js +27 -0
- package/test/unit/zip-archive.test.js +142 -0
- package/vitest.config.js +11 -3
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
- package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
|
@@ -26,7 +26,7 @@ class ObjectLayerManagement {
|
|
|
26
26
|
this.eGui = document.createElement('div');
|
|
27
27
|
const { data } = params;
|
|
28
28
|
|
|
29
|
-
if (!data
|
|
29
|
+
if (!data?.data?.item?.id) {
|
|
30
30
|
this.eGui.innerHTML = '';
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
@@ -43,10 +43,8 @@ class ObjectLayerManagement {
|
|
|
43
43
|
if (btn)
|
|
44
44
|
btn.onclick = async () =>
|
|
45
45
|
setTimeout(async () => {
|
|
46
|
-
// Navigate to viewer route first
|
|
47
46
|
setPath(`${getProxyPath()}object-layer-engine-viewer`);
|
|
48
|
-
|
|
49
|
-
setQueryParams({ id: data._id }, { replace: true });
|
|
47
|
+
setQueryParams({ id: null, itemId: data.data.item.id }, { replace: true });
|
|
50
48
|
if (s(`.modal-object-layer-engine-viewer`)) {
|
|
51
49
|
await ObjectLayerEngineViewer.Reload({ appStore, force: true });
|
|
52
50
|
}
|
|
@@ -72,7 +70,7 @@ class ObjectLayerManagement {
|
|
|
72
70
|
this.eGui = document.createElement('div');
|
|
73
71
|
const { data } = params;
|
|
74
72
|
|
|
75
|
-
if (!data
|
|
73
|
+
if (!data?.data?.item?.id) {
|
|
76
74
|
this.eGui.innerHTML = '';
|
|
77
75
|
return;
|
|
78
76
|
}
|
|
@@ -89,10 +87,8 @@ class ObjectLayerManagement {
|
|
|
89
87
|
if (btn)
|
|
90
88
|
btn.onclick = async () =>
|
|
91
89
|
setTimeout(async () => {
|
|
92
|
-
// Navigate to editor route first
|
|
93
90
|
setPath(`${getProxyPath()}object-layer-engine`);
|
|
94
|
-
|
|
95
|
-
setQueryParams({ id: data._id }, { replace: true });
|
|
91
|
+
setQueryParams({ id: null, itemId: data.data.item.id }, { replace: true });
|
|
96
92
|
if (s(`.modal-object-layer-engine`)) await ObjectLayerEngineModal.Reload();
|
|
97
93
|
else s(`.main-btn-object-layer-engine`).click();
|
|
98
94
|
});
|
|
@@ -121,8 +117,8 @@ class ObjectLayerManagement {
|
|
|
121
117
|
return;
|
|
122
118
|
}
|
|
123
119
|
|
|
124
|
-
const {
|
|
125
|
-
const imagePath = `${getProxyPath()}
|
|
120
|
+
const { id } = data.data.item;
|
|
121
|
+
const imagePath = `${getProxyPath()}api/atlas-sprite-sheet/idle-preview/${id}`;
|
|
126
122
|
|
|
127
123
|
// Container with both image and fallback
|
|
128
124
|
this.eGui.innerHTML = html`
|
|
@@ -183,9 +183,11 @@ class ObjectLayerService {
|
|
|
183
183
|
}),
|
|
184
184
|
);
|
|
185
185
|
};
|
|
186
|
-
|
|
186
|
+
/** Item identity ({ id, type }) by id prefix (`q`) or by an exact id list (`ids`). */
|
|
187
|
+
static searchItemIds = (options = { q: '', ids: [] }) => {
|
|
187
188
|
const url = new URL(getApiBaseUrl({ id: `search-item-ids`, endpoint }));
|
|
188
189
|
if (options.q) url.searchParams.set('q', options.q);
|
|
190
|
+
if (options.ids?.length) url.searchParams.set('ids', options.ids.join(','));
|
|
189
191
|
return new Promise((resolve, reject) =>
|
|
190
192
|
fetch(url.toString(), {
|
|
191
193
|
method: 'GET',
|
|
@@ -155,7 +155,7 @@ const main = () => {
|
|
|
155
155
|
text-align: center;
|
|
156
156
|
padding: 24px;
|
|
157
157
|
}
|
|
158
|
-
.badge {
|
|
158
|
+
.status-badge {
|
|
159
159
|
display: inline-flex;
|
|
160
160
|
align-items: center;
|
|
161
161
|
gap: 8px;
|
|
@@ -168,7 +168,7 @@ const main = () => {
|
|
|
168
168
|
margin-bottom: 26px;
|
|
169
169
|
box-shadow: 0 0 12px rgba(34, 211, 238, 0.35);
|
|
170
170
|
}
|
|
171
|
-
.badge .dot {
|
|
171
|
+
.status-badge .dot {
|
|
172
172
|
width: 8px;
|
|
173
173
|
height: 8px;
|
|
174
174
|
background: var(--green);
|
|
@@ -296,7 +296,7 @@ const main = () => {
|
|
|
296
296
|
</style>
|
|
297
297
|
<div class="grid"></div>
|
|
298
298
|
<main class="wrap">
|
|
299
|
-
<span class="badge"><span class="dot"></span> INSTANCE ${instanceLabel()}</span>
|
|
299
|
+
<span class="status-badge"><span class="dot"></span> INSTANCE ${instanceLabel()}</span>
|
|
300
300
|
<div class="code" data-text="404">404</div>
|
|
301
301
|
<div class="headline">SIGNAL LOST</div>
|
|
302
302
|
<p class="sub">
|
|
@@ -11,6 +11,7 @@ import { shellExec } from '../server/runtime/process.js';
|
|
|
11
11
|
import { loggerFactory } from '../server/ops/logger.js';
|
|
12
12
|
import {
|
|
13
13
|
coverageReportCandidates,
|
|
14
|
+
coverageReportsFactory,
|
|
14
15
|
coverageUnavailablePage,
|
|
15
16
|
resolveCoverageReportPath,
|
|
16
17
|
} from '../server/build/coverage.js';
|
|
@@ -296,43 +297,41 @@ const buildApiDocs = async ({
|
|
|
296
297
|
),
|
|
297
298
|
'utf8',
|
|
298
299
|
);
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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
|
+
}
|
|
306
309
|
|
|
307
|
-
|
|
310
|
+
await swaggerAutoGen({ openapi: '3.0.0' })(outputFile, routes, doc);
|
|
308
311
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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;
|
|
314
317
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
326
|
-
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
|
+
);
|
|
327
328
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
if (patched) {
|
|
331
|
-
fs.writeFileSync(outputFile, JSON.stringify(swaggerJson, null, 2), 'utf8');
|
|
332
|
-
// logger.warn('swagger post-process: requestBody injected', Object.keys(requestBodies));
|
|
329
|
+
patched = true;
|
|
333
330
|
}
|
|
334
331
|
}
|
|
335
|
-
|
|
332
|
+
|
|
333
|
+
if (patched) fs.writeFileSync(outputFile, JSON.stringify(swaggerJson, null, 2), 'utf8');
|
|
334
|
+
}
|
|
336
335
|
};
|
|
337
336
|
|
|
338
337
|
/**
|
|
@@ -401,9 +400,9 @@ const buildJsDocs = async ({ host, path, metadata = {}, publicClientId, docs, do
|
|
|
401
400
|
};
|
|
402
401
|
|
|
403
402
|
/**
|
|
404
|
-
* Publishes
|
|
403
|
+
* Publishes every coverage HTML report the deploy declares, each at `docs/coverage/<id>`.
|
|
405
404
|
*
|
|
406
|
-
* Never generates
|
|
405
|
+
* Never generates one: a report belongs to the test stage, which bundles it into the
|
|
407
406
|
* deploy artifact (see {@link module:src/server/build/coverage.js}). A client build that
|
|
408
407
|
* shelled out to `npm test` here spent minutes of a pod's build phase on a runner the
|
|
409
408
|
* workload has no business holding, and every expected non-zero exit of that suite latched
|
|
@@ -412,31 +411,32 @@ const buildJsDocs = async ({ host, path, metadata = {}, publicClientId, docs, do
|
|
|
412
411
|
* @memberof clientBuildDocs
|
|
413
412
|
* @param {Object} options - Coverage build options
|
|
414
413
|
* @param {Object} options.docs - Documentation config from server conf
|
|
415
|
-
* @param {string} options.docs.
|
|
416
|
-
* @param {string} [options.docs.coverageOutputDir] - Route directory under the docs path
|
|
414
|
+
* @param {Array<{id: string, label?: string, suite?: string, path?: string}>} [options.docs.coverage] - Declared reports
|
|
417
415
|
* @param {string} options.docsDestination - Resolved output path where docs were built
|
|
418
416
|
*/
|
|
419
417
|
const buildCoverage = async ({ docs, docsDestination }) => {
|
|
420
418
|
const logger = loggerFactory(import.meta);
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
|
|
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);
|
|
424
426
|
|
|
425
|
-
|
|
426
|
-
|
|
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;
|
|
435
|
+
}
|
|
427
436
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
logger.warn('no coverage report bundled, publishing the unavailable page', {
|
|
431
|
-
searched: coverageReportCandidates(coveragePath),
|
|
432
|
-
published: coverageBuildPath,
|
|
433
|
-
});
|
|
434
|
-
return;
|
|
437
|
+
fs.copySync(reportPath, coverageBuildPath);
|
|
438
|
+
logger.warn('build coverage', coverageBuildPath);
|
|
435
439
|
}
|
|
436
|
-
|
|
437
|
-
fs.emptyDirSync(coverageBuildPath);
|
|
438
|
-
fs.copySync(reportPath, coverageBuildPath);
|
|
439
|
-
logger.warn('build coverage', coverageBuildPath);
|
|
440
440
|
};
|
|
441
441
|
|
|
442
442
|
/**
|
|
@@ -473,7 +473,7 @@ const buildDocs = async ({
|
|
|
473
473
|
// TypeDoc output is versioned: served at /docs/engine/{version}/
|
|
474
474
|
const version = (packageData?.version || '').replace(/^v/, '');
|
|
475
475
|
const jsDocsDestination = `./public/${host}${pathPrefix}docs/engine/${version}/`;
|
|
476
|
-
// Coverage
|
|
476
|
+
// Coverage reports at /docs/coverage/<id>/
|
|
477
477
|
const coverageBaseDestination = `./public/${host}${pathPrefix}docs/`;
|
|
478
478
|
await buildJsDocs({ host, path, metadata, publicClientId, docs, docsDestination: jsDocsDestination });
|
|
479
479
|
await buildCoverage({ docs, docsDestination: coverageBaseDestination });
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from '../client/components/core/CommonJs.js';
|
|
18
18
|
import { readConfJson } from '../server/runtime/conf.js';
|
|
19
19
|
import { minify } from 'html-minifier-terser';
|
|
20
|
-
import
|
|
20
|
+
import { extractZipTo, findZipEntry, isZipBuffer, loadZip, zipFromLocalFiles } from '../server/storage/zip.js';
|
|
21
21
|
import * as dir from 'path';
|
|
22
22
|
import { shellExec } from '../server/runtime/process.js';
|
|
23
23
|
import { SitemapStream, streamToPromise } from 'sitemap';
|
|
@@ -27,6 +27,7 @@ import { statusPageBuildSegment } from '../server/network/underpost-gateway.js';
|
|
|
27
27
|
import { repositoryIdentityFactory } from '../server/storage/repository.js';
|
|
28
28
|
import Underpost from '../index.js';
|
|
29
29
|
import { buildDocs } from './client-build-docs.js';
|
|
30
|
+
import { coverageReportsFactory } from '../server/build/coverage.js';
|
|
30
31
|
import { ssrFactory } from './ssr.js';
|
|
31
32
|
|
|
32
33
|
// Static Site Generation (SSG)
|
|
@@ -180,6 +181,17 @@ const splitFileByMb = ({ filePath, partSizeMb, logger }) => {
|
|
|
180
181
|
return partPaths;
|
|
181
182
|
};
|
|
182
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
|
+
|
|
183
195
|
const getZipPartPaths = (zipPath) => {
|
|
184
196
|
const zipDir = dir.dirname(zipPath);
|
|
185
197
|
const zipBase = dir.basename(zipPath);
|
|
@@ -269,9 +281,9 @@ const resolveClientBuildZip = (buildPrefix) => {
|
|
|
269
281
|
* @param {object} options
|
|
270
282
|
* @param {string} options.buildPrefix - The build prefix path (e.g. build/underpost.net/underpost.net-).
|
|
271
283
|
* @param {object} options.logger - Logger instance.
|
|
272
|
-
* @returns {{ zipPath: string, partPaths: string[], mergedBytes: number }}
|
|
284
|
+
* @returns {Promise<{ zipPath: string, partPaths: string[], mergedBytes: number }>}
|
|
273
285
|
*/
|
|
274
|
-
const mergeClientBuildZip = ({ buildPrefix, logger }) => {
|
|
286
|
+
const mergeClientBuildZip = async ({ buildPrefix, logger }) => {
|
|
275
287
|
// Normalize to get the zip path, then look for parts directly (bypassing resolveClientBuildZip
|
|
276
288
|
// which prefers an existing monolithic zip over parts).
|
|
277
289
|
const normalizedPrefix = buildPrefix.replace(/\.zip(?:[.-]part\d+)?$/, '').replace(/[-.]$/, '') + '-';
|
|
@@ -301,31 +313,41 @@ const mergeClientBuildZip = ({ buildPrefix, logger }) => {
|
|
|
301
313
|
// For each part, extract raw bytes: if the part file is a Cloudinary wrapper zip
|
|
302
314
|
// (downloaded via pull without --omit-unzip or with --omit-unzip keeping the .zip),
|
|
303
315
|
// extract the inner entry rather than using the wrapper bytes.
|
|
304
|
-
const readPartBytes = (partPath) => {
|
|
316
|
+
const readPartBytes = async (partPath) => {
|
|
305
317
|
const rawBytes = fs.readFileSync(partPath);
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
return entry.getData();
|
|
316
|
-
}
|
|
317
|
-
// Fallback: single-entry archive
|
|
318
|
-
if (entries.length === 1) {
|
|
319
|
-
return entries[0].getData();
|
|
320
|
-
}
|
|
321
|
-
} catch (_) {
|
|
322
|
-
// Not a valid zip or extraction failed — use raw bytes
|
|
323
|
-
}
|
|
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;
|
|
324
327
|
}
|
|
325
|
-
|
|
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');
|
|
326
335
|
};
|
|
327
336
|
|
|
328
|
-
const
|
|
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
|
+
});
|
|
329
351
|
fs.writeFileSync(zipPath, mergedBuffer);
|
|
330
352
|
|
|
331
353
|
logger.warn('merge-zip: merged split parts into zip', {
|
|
@@ -337,19 +359,16 @@ const mergeClientBuildZip = ({ buildPrefix, logger }) => {
|
|
|
337
359
|
return { zipPath, partPaths, mergedBytes: mergedBuffer.length };
|
|
338
360
|
};
|
|
339
361
|
|
|
340
|
-
const unzipClientBuild = ({ buildPrefix, logger }) => {
|
|
362
|
+
const unzipClientBuild = async ({ buildPrefix, logger }) => {
|
|
341
363
|
const { zipPath, partPaths, buildPrefix: resolvedBuildPrefix } = resolveClientBuildZip(buildPrefix);
|
|
342
364
|
const outputPath = resolvedBuildPrefix.replace(/-$/, '');
|
|
343
365
|
|
|
344
366
|
fs.removeSync(outputPath);
|
|
345
|
-
fs.mkdirSync(outputPath, { recursive: true });
|
|
346
|
-
|
|
347
|
-
const zip =
|
|
348
|
-
partPaths.length > 0
|
|
349
|
-
? new AdmZip(Buffer.concat(partPaths.map((partPath) => fs.readFileSync(partPath))))
|
|
350
|
-
: new AdmZip(zipPath);
|
|
351
367
|
|
|
352
|
-
|
|
368
|
+
await extractZipTo(
|
|
369
|
+
partPaths.length > 0 ? Buffer.concat(partPaths.map((partPath) => fs.readFileSync(partPath))) : zipPath,
|
|
370
|
+
outputPath,
|
|
371
|
+
);
|
|
353
372
|
|
|
354
373
|
logger.warn('unzip build', {
|
|
355
374
|
source: partPaths.length > 0 ? partPaths : [zipPath],
|
|
@@ -704,6 +723,8 @@ const buildClient = async (
|
|
|
704
723
|
apiBasePath: process.env.BASE_API,
|
|
705
724
|
version: Underpost.version,
|
|
706
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 })),
|
|
707
728
|
...(isDevelopment ? { dev: true } : undefined),
|
|
708
729
|
};
|
|
709
730
|
|
|
@@ -833,14 +854,12 @@ const buildClient = async (
|
|
|
833
854
|
}
|
|
834
855
|
|
|
835
856
|
if (!ssrOnly && views) {
|
|
836
|
-
if (
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
(p) => p.srcBuildPath.startsWith(`./src/client/ssr`) || p.srcBuildPath.slice(-9) === '.index.js',
|
|
841
|
-
)
|
|
857
|
+
if (!(
|
|
858
|
+
enableLiveRebuild &&
|
|
859
|
+
!options.liveClientBuildPaths.find(
|
|
860
|
+
(p) => p.srcBuildPath.startsWith(`./src/client/ssr`) || p.srcBuildPath.slice(-9) === '.index.js',
|
|
842
861
|
)
|
|
843
|
-
)
|
|
862
|
+
))
|
|
844
863
|
for (const view of views) {
|
|
845
864
|
const buildPath = `${
|
|
846
865
|
rootClientPath[rootClientPath.length - 1] === '/' ? rootClientPath.slice(0, -1) : rootClientPath
|
|
@@ -1147,23 +1166,25 @@ ${swTransformedJs}`,
|
|
|
1147
1166
|
|
|
1148
1167
|
if (!fs.existsSync('./build')) fs.mkdirSync('./build');
|
|
1149
1168
|
|
|
1150
|
-
const zip = new AdmZip();
|
|
1151
1169
|
const files = await fs.readdir(rootClientPath, { recursive: true });
|
|
1170
|
+
const zipEntries = [];
|
|
1152
1171
|
|
|
1153
1172
|
for (const relativePath of files) {
|
|
1154
1173
|
const filePath = dir.resolve(`${rootClientPath}/${relativePath}`);
|
|
1155
1174
|
if (!fs.lstatSync(filePath).isDirectory()) {
|
|
1156
1175
|
const folder = dir.relative(`public/${host}${path}`, dir.dirname(filePath));
|
|
1157
|
-
|
|
1176
|
+
zipEntries.push({
|
|
1177
|
+
localPath: filePath,
|
|
1178
|
+
entryName: folder ? `${folder}/${dir.basename(filePath)}` : dir.basename(filePath),
|
|
1179
|
+
});
|
|
1158
1180
|
}
|
|
1159
1181
|
}
|
|
1160
1182
|
|
|
1161
|
-
const
|
|
1162
|
-
const zipPath = `./build/${buildId}.zip`;
|
|
1183
|
+
const zipPath = `./build/${clientBundleIdFactory(host, path)}.zip`;
|
|
1163
1184
|
|
|
1164
1185
|
logger.warn('write zip', zipPath);
|
|
1165
1186
|
|
|
1166
|
-
|
|
1187
|
+
fs.writeFileSync(zipPath, await zipFromLocalFiles(zipEntries));
|
|
1167
1188
|
|
|
1168
1189
|
if (options.split) {
|
|
1169
1190
|
splitFileByMb({
|
|
@@ -1181,7 +1202,9 @@ ${swTransformedJs}`,
|
|
|
1181
1202
|
|
|
1182
1203
|
export {
|
|
1183
1204
|
buildClient,
|
|
1205
|
+
clientBundleIdFactory,
|
|
1184
1206
|
copyNonExistingFiles,
|
|
1207
|
+
getZipPartPaths,
|
|
1185
1208
|
unzipClientBuild,
|
|
1186
1209
|
mergeClientBuildZip,
|
|
1187
1210
|
staticContextRoutesFactory,
|