@underpostnet/cyberia 3.2.80 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +50 -15
- package/.github/workflows/coverall.cyberia.ci.yml +87 -0
- package/.github/workflows/cyberia-client.cd.yml +2 -7
- package/.github/workflows/cyberia-server.cd.yml +2 -7
- package/.github/workflows/docker-image.cyberia-client.ci.yml +4 -4
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +4 -4
- package/.github/workflows/docker-image.cyberia-server.ci.yml +4 -4
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +4 -4
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +3 -3
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +3 -3
- package/.github/workflows/engine-cyberia.cd.yml +3 -67
- package/.github/workflows/ghpkg.ci.yml +7 -1
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -16
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +1 -9
- package/CHANGELOG.md +291 -1
- package/CLI-HELP.md +174 -23
- package/Dockerfile +1 -1
- package/Dockerfile.dev +1 -1
- package/Dockerfile.test +1 -1
- package/bin/build.js +7 -5
- package/bin/cyberia.js +272 -98
- package/bin/deploy.js +19 -17
- package/bin/index.js +272 -98
- package/compose.env +50 -15
- package/conf.js +2 -0
- package/deploy/dd-cyberia/deploy.sh +42 -0
- package/deploy/dd-cyberia/init.sh +63 -0
- package/deploy/dd-cyberia/sync-deploy.sh +194 -0
- package/deploy/lib/logging.sh +96 -0
- package/deploy/pwa-microservices-template/deploy.sh +72 -0
- package/deploy/release/deploy.sh +62 -0
- package/deployment.yaml +1 -210
- package/docker-compose.yml +90 -85
- package/hardhat/package-lock.json +139 -131
- package/hardhat/package.json +4 -4
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +5 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +52 -0
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +1 -210
- package/manifests/deployment/dd-cyberia-development/gateway.yaml +80 -0
- package/manifests/deployment/dd-cyberia-development/httproute.yaml +504 -0
- package/manifests/deployment/dd-cyberia-development/proxy.yaml +12 -12
- package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +0 -82
- package/manifests/deployment/dd-cyberia-development/traffic-service.yaml +121 -0
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/playwright/deployment.yaml +1 -1
- package/manifests/mongodb/kustomization.yaml +4 -1
- package/manifests/mongodb/statefulset.yaml +4 -0
- package/manifests/mongodb/storage-class.yaml +9 -2
- package/nginx.conf +86 -16
- package/package.json +2 -2
- package/proxy.yaml +12 -12
- package/pv-pvc.yaml +0 -82
- package/scripts/audit-selinux.sh +64 -0
- package/scripts/coverall-test-cyberia.sh +24 -0
- package/scripts/coverall-test.sh +24 -0
- package/scripts/gpu-diag.sh +0 -0
- package/scripts/ip-info.sh +0 -0
- package/scripts/k3s-node-setup.sh +18 -15
- package/scripts/kubeadm-node-setup.sh +12 -23
- package/scripts/link-local-underpost-cli.sh +0 -0
- package/scripts/lxd-vm-setup.sh +0 -0
- package/scripts/maas-nat-firewalld.sh +0 -0
- package/scripts/nat-iptables.sh +12 -4
- package/scripts/rhel-grpc-setup.sh +0 -0
- package/scripts/rocky-kickstart.sh +25 -9
- package/scripts/test-monitor.sh +4 -3
- package/src/api/cyberia-action/cyberia-action.model.js +1 -0
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +63 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +49 -15
- package/src/api/cyberia-instance/cyberia-instance-map.service.js +8 -12
- package/src/api/cyberia-instance/cyberia-instance.controller.js +3 -0
- package/src/api/cyberia-instance/cyberia-instance.router.js +13 -0
- package/src/api/cyberia-instance/cyberia-instance.service.js +43 -0
- package/src/api/cyberia-instance/cyberia-portal-connector.js +7 -5
- package/src/api/cyberia-instance/cyberia-random-source.js +80 -0
- package/src/api/cyberia-instance/cyberia-world-generator.js +4 -3
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +1 -0
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +87 -1
- package/src/api/object-layer/object-layer.model.js +204 -3
- package/src/api/object-layer/object-layer.service.js +1 -14
- package/src/cli/baremetal.js +1 -2
- package/src/cli/cloud-init.js +1 -1
- package/src/cli/cluster.js +786 -96
- package/src/cli/db.js +11 -4
- package/src/cli/deploy.js +1698 -177
- package/src/cli/docker-compose.js +19 -178
- package/src/cli/env.js +1 -1
- package/src/cli/image.js +15 -7
- package/src/cli/index.js +245 -44
- package/src/cli/ipfs.js +82 -11
- package/src/cli/lxd.js +1 -1
- package/src/cli/monitor.js +2 -2
- package/src/cli/release.js +57 -22
- package/src/cli/repository.js +12 -10
- package/src/cli/run.js +2195 -427
- package/src/cli/secrets.js +969 -0
- package/src/cli/ssh.js +206 -105
- package/src/cli/system.js +26 -13
- package/src/cli/test.js +1 -1
- package/src/cli/vultr.js +583 -0
- package/src/cli/wireguard.js +2125 -0
- package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +368 -0
- package/src/client/components/cyberia/InstanceSelectionView.js +11 -8
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +5 -0
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +33 -0
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +4 -0
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
- package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +106 -39
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +35 -3
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +44 -7
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +1 -1
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +40 -0
- package/src/client/services/object-layer/object-layer.management.js +4 -4
- package/src/client-builder/client-build.js +102 -13
- package/src/client-builder/ssr.js +27 -73
- package/src/db/mongo/MongoBootstrap.js +295 -54
- package/src/db/mongo/MongooseDB.js +51 -32
- package/src/index.js +25 -1
- package/src/projects/cyberia/besu-genesis-generator.js +3 -2
- package/src/projects/cyberia/catalog-cyberia.js +5 -0
- package/src/projects/cyberia/generate-saga.js +14 -23
- package/src/projects/cyberia/hot-reload-trigger.js +3 -3
- package/src/projects/cyberia/instance-data.js +63 -3
- package/src/projects/cyberia/object-layer.js +11 -21
- package/src/projects/underpost/catalog-underpost.js +4 -1
- package/src/runtime/cyberia-client/Dockerfile +1 -1
- package/src/runtime/cyberia-client/Dockerfile.dev +1 -1
- package/src/runtime/cyberia-server/Dockerfile +1 -1
- package/src/runtime/cyberia-server/Dockerfile.dev +1 -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 +1 -1
- package/src/runtime/engine-cyberia/compose.env +50 -15
- package/src/runtime/engine-cyberia/docker-compose.yml +90 -85
- package/src/runtime/engine-cyberia/nginx.conf +86 -16
- package/src/server/backup.js +1 -1
- package/src/server/conf.js +1216 -168
- package/src/server/cri.js +70 -0
- package/src/server/cron.js +249 -51
- package/src/server/dns.js +100 -6
- package/src/server/environment.js +98 -0
- package/src/server/forward-proxy.js +549 -0
- package/src/server/middlewares.js +56 -1
- package/src/server/process.js +0 -1
- package/src/server/selinux.js +185 -0
- package/src/server/systemd.js +205 -0
- package/src/server/underpost-compression.js +186 -0
- package/src/server/underpost-gateway.js +1083 -0
- package/src/server/underpost-ingress.js +380 -0
- package/test/cluster-instances.test.js +435 -0
- package/test/cyberia-instance-conf-defaults.test.js +1 -0
- package/test/deploy-node-placement.test.js +45 -0
- package/test/instance-traffic-plan.test.js +710 -0
- package/test/selinux.test.js +71 -0
- package/test/sops-secret-store.test.js +612 -0
- package/test/underpost-gateway.test.js +510 -0
- package/test/underpost-ingress.test.js +305 -0
- package/test/wireguard-edge.test.js +1177 -0
|
@@ -19,6 +19,7 @@ import path from 'path';
|
|
|
19
19
|
import { keccak256 as ethersKeccak256 } from 'ethers';
|
|
20
20
|
import { loggerFactory } from '../../server/logger.js';
|
|
21
21
|
import { shellExec } from '../../server/process.js';
|
|
22
|
+
import { crictlCommandFactory } from '../../server/cri.js';
|
|
22
23
|
|
|
23
24
|
const logger = loggerFactory(import.meta);
|
|
24
25
|
|
|
@@ -1394,8 +1395,8 @@ async function deployBesu(options = {}) {
|
|
|
1394
1395
|
// ── Step 2: Pull container images if requested ─────────────────────────
|
|
1395
1396
|
if (pullImage) {
|
|
1396
1397
|
logger.info('Pulling Besu images via crictl...');
|
|
1397
|
-
shellExec(`
|
|
1398
|
-
shellExec(`
|
|
1398
|
+
shellExec(crictlCommandFactory(`pull ${besuImage}`));
|
|
1399
|
+
shellExec(crictlCommandFactory(`pull ${curlImage}`));
|
|
1399
1400
|
}
|
|
1400
1401
|
|
|
1401
1402
|
// ── Step 3: Apply all besu resources via kustomize ─────────────────────
|
|
@@ -48,6 +48,8 @@ export default {
|
|
|
48
48
|
'/.github/workflows/docker-image.cyberia-server.dev.ci.yml',
|
|
49
49
|
'/.github/workflows/cyberia-client.cd.yml',
|
|
50
50
|
'/.github/workflows/cyberia-server.cd.yml',
|
|
51
|
+
'/.github/workflows/coverall.cyberia.ci.yml',
|
|
52
|
+
'/scripts/coverall-test-cyberia.sh',
|
|
51
53
|
],
|
|
52
54
|
stripPaths: [
|
|
53
55
|
'./src/projects/cyberia',
|
|
@@ -56,8 +58,11 @@ export default {
|
|
|
56
58
|
'./src/runtime/cyberia-client',
|
|
57
59
|
'./src/runtime/engine-cyberia',
|
|
58
60
|
'./test/cyberia-instance-conf-defaults.test.js',
|
|
61
|
+
'./test/cyberia-load.test.js',
|
|
62
|
+
'./test/object-layer-item-id.test.js',
|
|
59
63
|
'./test/shape-generator.test.js',
|
|
60
64
|
'./src/client/public/cyberia-docs',
|
|
65
|
+
'./scripts/coverall-test-cyberia.sh',
|
|
61
66
|
'bin/cyberia.js',
|
|
62
67
|
'./hardhat',
|
|
63
68
|
],
|
|
@@ -18,7 +18,6 @@ import fs from 'fs-extra';
|
|
|
18
18
|
import nodePath from 'path';
|
|
19
19
|
import crypto from 'crypto';
|
|
20
20
|
import { GeminiClient } from './gemini-client.js';
|
|
21
|
-
import { computeSha256 } from './object-layer.js';
|
|
22
21
|
import { loggerFactory } from '../../server/logger.js';
|
|
23
22
|
|
|
24
23
|
const logger = loggerFactory(import.meta);
|
|
@@ -1632,13 +1631,13 @@ function normalizeSagaPayload(raw, { theme }) {
|
|
|
1632
1631
|
|
|
1633
1632
|
/**
|
|
1634
1633
|
* Persist normalized object-layer items into the ObjectLayer collection so they
|
|
1635
|
-
* are editable in the viewer.
|
|
1636
|
-
*
|
|
1634
|
+
* are editable in the viewer. New items get an empty render and an `OFF_CHAIN`
|
|
1635
|
+
* ledger; both can be set later from the object-layer import or from
|
|
1637
1636
|
* `src/client/components/cyberia/ObjectLayerEngineViewer.js`.
|
|
1638
1637
|
*
|
|
1639
|
-
* Upserts
|
|
1640
|
-
*
|
|
1641
|
-
* refreshed
|
|
1638
|
+
* Upserts through `ObjectLayer.upsertByItemId`, so `data.item.id` stays unique
|
|
1639
|
+
* and an existing item's render, ledger and CIDs are PRESERVED — only the
|
|
1640
|
+
* textual stats/item fields are refreshed, and `sha256` is recomputed.
|
|
1642
1641
|
*
|
|
1643
1642
|
* @async
|
|
1644
1643
|
* @param {Object} params
|
|
@@ -1647,28 +1646,20 @@ function normalizeSagaPayload(raw, { theme }) {
|
|
|
1647
1646
|
* @returns {Promise<number>} Count of items created or updated.
|
|
1648
1647
|
*/
|
|
1649
1648
|
async function persistObjectLayers({ objectLayers, ObjectLayer }) {
|
|
1649
|
+
await ObjectLayer.ensureUniqueItemIdIndex();
|
|
1650
|
+
|
|
1650
1651
|
let count = 0;
|
|
1651
1652
|
for (const ol of objectLayers) {
|
|
1652
1653
|
const itemId = ol.item?.id;
|
|
1653
1654
|
if (!itemId) continue;
|
|
1654
1655
|
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
//
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
const data = { stats: ol.stats, item: ol.item, ledger, render };
|
|
1663
|
-
const sha256 = computeSha256(data);
|
|
1664
|
-
|
|
1665
|
-
if (existing) {
|
|
1666
|
-
existing.data = data;
|
|
1667
|
-
existing.sha256 = sha256;
|
|
1668
|
-
await existing.save();
|
|
1669
|
-
} else {
|
|
1670
|
-
await ObjectLayer.create({ data, sha256, cid: null });
|
|
1671
|
-
}
|
|
1656
|
+
// The saga only owns the textual/statistical fields. Ledger and render are
|
|
1657
|
+
// seeded on insert and never refreshed, so a re-import cannot clobber an
|
|
1658
|
+
// on-chain registration or a render produced by the object-layer import.
|
|
1659
|
+
await ObjectLayer.upsertByItemId(
|
|
1660
|
+
{ data: { stats: ol.stats, item: ol.item } },
|
|
1661
|
+
{ setOnInsert: { cid: null, data: { ledger: { type: 'OFF_CHAIN', tokenId: '' }, render: {} } } },
|
|
1662
|
+
);
|
|
1672
1663
|
count++;
|
|
1673
1664
|
}
|
|
1674
1665
|
return count;
|
|
@@ -51,9 +51,9 @@ const serverApiKey = () => process.env.CYBERIA_SERVER_API_KEY || '';
|
|
|
51
51
|
*
|
|
52
52
|
* The URL sub-path is preserved as `basePath` ("", "/FOREST", "/TEST") and kept
|
|
53
53
|
* on `restBaseUrl`: a path-based multi-instance proxy routes the REST trigger to
|
|
54
|
-
* the right variant
|
|
55
|
-
*
|
|
56
|
-
*
|
|
54
|
+
* the right variant, and cyberia-server consumes that same base path natively.
|
|
55
|
+
* Using `url.origin` alone would drop the sub-path and land every trigger on the
|
|
56
|
+
* default (root) deployment.
|
|
57
57
|
*/
|
|
58
58
|
const resolveTargets = (rawUrl, { grpcPort = DEFAULT_GRPC_PORT } = {}) => {
|
|
59
59
|
const trimmed = String(rawUrl || '').trim();
|
|
@@ -24,11 +24,38 @@ import {
|
|
|
24
24
|
DefaultCyberiaActions,
|
|
25
25
|
DefaultCyberiaQuests,
|
|
26
26
|
} from '../../api/cyberia-server-defaults/cyberia-server-defaults.js';
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
DEFAULT_INSTANCE_CODE,
|
|
29
|
+
DefaultCyberiaItems,
|
|
30
|
+
} from '../../client/components/cyberia/SharedDefaultsCyberia.js';
|
|
28
31
|
import { generateFallbackWorld } from '../../api/cyberia-instance/cyberia-fallback-world.js';
|
|
32
|
+
import { getFallbackDefaultItems } from '../../api/cyberia-instance/cyberia-fallback-default-items.js';
|
|
29
33
|
|
|
30
34
|
const logger = loggerFactory(import.meta);
|
|
31
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Builds the runtime env for one Cyberia MMO variant. The generic instance
|
|
38
|
+
* loader deliberately has no knowledge of these application-specific keys;
|
|
39
|
+
* Cyberia derives them from the normalized variant path/code here.
|
|
40
|
+
* @param {object} context - Instance env build context.
|
|
41
|
+
* @param {object} context.instance - Expanded instance descriptor.
|
|
42
|
+
* @param {Object<string,string>} context.env - Parsed canonical env values.
|
|
43
|
+
* @returns {Object<string,string>} Materialized Cyberia env values.
|
|
44
|
+
*/
|
|
45
|
+
function buildCyberiaMmoInstanceEnv({ instance = {}, env = {} }) {
|
|
46
|
+
const built = { ...env };
|
|
47
|
+
const instanceCode = instance.path === '/' ? DEFAULT_INSTANCE_CODE : instance.instanceCode;
|
|
48
|
+
if (instance.runtime === 'cyberia-server') {
|
|
49
|
+
built.INSTANCE_CODE = instanceCode;
|
|
50
|
+
built.CYBERIA_BASE_PATH = instance.path;
|
|
51
|
+
} else if (instance.runtime === 'cyberia-client') {
|
|
52
|
+
built.CYBERIA_INSTANCE_CODE = instanceCode;
|
|
53
|
+
built.CYBERIA_DEFAULT_INSTANCE = DEFAULT_INSTANCE_CODE;
|
|
54
|
+
built.CYBERIA_BASE_PATH = instance.path;
|
|
55
|
+
}
|
|
56
|
+
return built;
|
|
57
|
+
}
|
|
58
|
+
|
|
32
59
|
/**
|
|
33
60
|
* Resolves the mongoose model bag for a DB context.
|
|
34
61
|
* @param {{host?: string, path?: string}|string} context - RouterOptions-style
|
|
@@ -304,6 +331,8 @@ function toInstanceMsg(doc) {
|
|
|
304
331
|
};
|
|
305
332
|
}
|
|
306
333
|
|
|
334
|
+
const toCraftItemMsg = (i) => ({ itemId: i.itemId || '', qty: i.qty ?? 1 });
|
|
335
|
+
|
|
307
336
|
// CyberiaAction → CyberiaActionMessage (proto camelCase fields).
|
|
308
337
|
function toActionMsg(a) {
|
|
309
338
|
return {
|
|
@@ -317,6 +346,17 @@ function toActionMsg(a) {
|
|
|
317
346
|
questCode: qd.questCode || '',
|
|
318
347
|
dialogCode: qd.dialogCode || '',
|
|
319
348
|
})),
|
|
349
|
+
shopItems: (a.shopItems || []).map((si) => ({
|
|
350
|
+
itemId: si.itemId || '',
|
|
351
|
+
priceItemId: si.priceItemId || 'coin',
|
|
352
|
+
priceQty: si.priceQty ?? 1,
|
|
353
|
+
})),
|
|
354
|
+
craftRecipes: (a.craftRecipes || []).map((r) => ({
|
|
355
|
+
outputItems: (r.outputItems || []).map(toCraftItemMsg),
|
|
356
|
+
ingredients: (r.ingredients || []).map(toCraftItemMsg),
|
|
357
|
+
craftTimeMs: r.craftTimeMs ?? 0,
|
|
358
|
+
})),
|
|
359
|
+
storageSlots: a.storageSlots ?? 0,
|
|
320
360
|
};
|
|
321
361
|
}
|
|
322
362
|
|
|
@@ -382,6 +422,7 @@ function toInstanceConfig(gc) {
|
|
|
382
422
|
botAggroRange: gc.botAggroRange ?? fb.botAggroRange,
|
|
383
423
|
defaultPlayerWidth: gc.defaultPlayerWidth ?? fb.defaultPlayerWidth,
|
|
384
424
|
defaultPlayerHeight: gc.defaultPlayerHeight ?? fb.defaultPlayerHeight,
|
|
425
|
+
playerBaseSpeed: gc.playerBaseSpeed ?? fb.playerBaseSpeed,
|
|
385
426
|
playerBaseLifeRegenMin: gc.playerBaseLifeRegenMin ?? fb.playerBaseLifeRegenMin,
|
|
386
427
|
playerBaseLifeRegenMax: gc.playerBaseLifeRegenMax ?? fb.playerBaseLifeRegenMax,
|
|
387
428
|
sumStatsLimit: gc.sumStatsLimit ?? fb.sumStatsLimit,
|
|
@@ -514,7 +555,7 @@ async function fetchFullInstance(models, requestedInstanceCode) {
|
|
|
514
555
|
// ── Fallback: instance not found → return a multi-map procedural world ──
|
|
515
556
|
if (!inst) {
|
|
516
557
|
logger.info(`Instance "${instanceCode}" not found — returning fallback world.`);
|
|
517
|
-
const world = generateFallbackWorld();
|
|
558
|
+
const world = generateFallbackWorld({ itemIds: getFallbackDefaultItems() });
|
|
518
559
|
const fallbackConf = buildFallbackConfig();
|
|
519
560
|
|
|
520
561
|
// Collect all objectLayerItemIds from the generated maps so the
|
|
@@ -560,6 +601,23 @@ async function fetchFullInstance(models, requestedInstanceCode) {
|
|
|
560
601
|
|
|
561
602
|
const fallbackConfig = buildFallbackInstanceConfig(fallbackConf, world.instance.itemIds);
|
|
562
603
|
|
|
604
|
+
// Opaque version over everything mutable in this payload, mirroring the
|
|
605
|
+
// persisted path below. A constant here would make hot reload a silent
|
|
606
|
+
// no-op: WorldBuilder.ReloadWorld skips the rebuild — and therefore
|
|
607
|
+
// ApplyInstanceConfig — whenever the version is unchanged. The world
|
|
608
|
+
// geometry itself is deterministic (code defaults + seed), so the inputs
|
|
609
|
+
// that can actually differ are the staged default items and the
|
|
610
|
+
// ObjectLayer docs, which are the only things read from the DB here.
|
|
611
|
+
const fallbackVersionParts = ['fallback'];
|
|
612
|
+
for (const entry of world.instance.itemIds || []) {
|
|
613
|
+
fallbackVersionParts.push(`${entry.id}:${entry.defaultPlayerInventory ? 1 : 0}`);
|
|
614
|
+
}
|
|
615
|
+
for (const doc of fallbackOlDocs) fallbackVersionParts.push(String(doc.sha256 || doc._id));
|
|
616
|
+
const fallbackVersion = `fallback-${crypto
|
|
617
|
+
.createHash('sha256')
|
|
618
|
+
.update(fallbackVersionParts.join('|'))
|
|
619
|
+
.digest('hex')}`;
|
|
620
|
+
|
|
563
621
|
return {
|
|
564
622
|
instance: toInstanceMsg({ ...world.instance, _id: '', seed: instanceCode }),
|
|
565
623
|
maps: world.maps.map((m) => ({
|
|
@@ -574,7 +632,7 @@ async function fetchFullInstance(models, requestedInstanceCode) {
|
|
|
574
632
|
})),
|
|
575
633
|
objectLayers: fallbackOlDocs.map(toObjectLayerMsg),
|
|
576
634
|
config: fallbackConfig,
|
|
577
|
-
version:
|
|
635
|
+
version: fallbackVersion,
|
|
578
636
|
// Mission content for the procedural fallback comes straight from
|
|
579
637
|
// the canonical defaults — no DB, fully self-contained.
|
|
580
638
|
actions: DefaultCyberiaActions.map(toActionMsg),
|
|
@@ -693,6 +751,8 @@ async function fetchFullInstance(models, requestedInstanceCode) {
|
|
|
693
751
|
}
|
|
694
752
|
|
|
695
753
|
export {
|
|
754
|
+
buildCyberiaMmoInstanceEnv as buildInstanceEnv,
|
|
755
|
+
buildCyberiaMmoInstanceEnv,
|
|
696
756
|
getInstanceModels,
|
|
697
757
|
normalizeEntityDefault,
|
|
698
758
|
applyInstanceDefaultPlayerInventory,
|
|
@@ -10,9 +10,7 @@ import path from 'path';
|
|
|
10
10
|
import { PNG } from 'pngjs';
|
|
11
11
|
import sharp from 'sharp';
|
|
12
12
|
import { Jimp, intToRGBA, rgbaToInt } from 'jimp';
|
|
13
|
-
import
|
|
14
|
-
import stringify from 'fast-json-stable-stringify';
|
|
15
|
-
|
|
13
|
+
import { computeObjectLayerSha256 } from '../../api/object-layer/object-layer.model.js';
|
|
16
14
|
import { range } from '../../client/components/core/CommonJs.js';
|
|
17
15
|
import {
|
|
18
16
|
generateRandomStats,
|
|
@@ -450,7 +448,7 @@ export class ObjectLayerEngine {
|
|
|
450
448
|
* @memberof CyberiaObjectLayer
|
|
451
449
|
*/
|
|
452
450
|
static computeSha256(data) {
|
|
453
|
-
return
|
|
451
|
+
return computeObjectLayerSha256(data);
|
|
454
452
|
}
|
|
455
453
|
|
|
456
454
|
/**
|
|
@@ -642,23 +640,15 @@ export class ObjectLayerEngine {
|
|
|
642
640
|
}
|
|
643
641
|
|
|
644
642
|
// 4. Atomic create/upsert - ObjectLayer is fully populated with all CIDs
|
|
645
|
-
|
|
646
|
-
const
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
);
|
|
652
|
-
objectLayer = await ObjectLayer.findByIdAndUpdate(existingByItemId._id, objectLayerData, {
|
|
653
|
-
returnDocument: 'after',
|
|
654
|
-
}).populate('objectLayerRenderFramesId');
|
|
655
|
-
if (oldRenderFramesId && !oldRenderFramesId.equals(objectLayerRenderFramesDoc._id)) {
|
|
656
|
-
await ObjectLayerRenderFrames.findByIdAndDelete(oldRenderFramesId);
|
|
657
|
-
}
|
|
658
|
-
} else {
|
|
659
|
-
objectLayer = await (await ObjectLayer.create(objectLayerData)).populate('objectLayerRenderFramesId');
|
|
660
|
-
logger.info(`ObjectLayer created successfully with id: ${objectLayer._id}`);
|
|
643
|
+
const existingByItemId = await ObjectLayer.findByItemId(objectLayerData.data.item.id);
|
|
644
|
+
const oldRenderFramesId = existingByItemId?.objectLayerRenderFramesId;
|
|
645
|
+
|
|
646
|
+
const objectLayer = await (await ObjectLayer.upsertByItemId(objectLayerData)).populate('objectLayerRenderFramesId');
|
|
647
|
+
|
|
648
|
+
if (oldRenderFramesId && !oldRenderFramesId.equals(objectLayerRenderFramesDoc._id)) {
|
|
649
|
+
await ObjectLayerRenderFrames.findByIdAndDelete(oldRenderFramesId);
|
|
661
650
|
}
|
|
651
|
+
logger.info(`ObjectLayer for item "${objectLayerData.data.item.id}" persisted with id: ${objectLayer._id}`);
|
|
662
652
|
|
|
663
653
|
return { objectLayer, objectLayerRenderFramesDoc };
|
|
664
654
|
}
|
|
@@ -848,7 +838,7 @@ export class ObjectLayerEngine {
|
|
|
848
838
|
* @memberof CyberiaObjectLayer
|
|
849
839
|
*/
|
|
850
840
|
static async resolveCanonicalCid({ itemId, ObjectLayer, ipfsClient = null, options }) {
|
|
851
|
-
const objectLayer = await ObjectLayer.
|
|
841
|
+
const objectLayer = await ObjectLayer.findByItemId(itemId);
|
|
852
842
|
if (!objectLayer) {
|
|
853
843
|
throw new Error(`ObjectLayer "${itemId}" not found in database`);
|
|
854
844
|
}
|
|
@@ -18,7 +18,10 @@ const TEMPLATE_RESTORE_PATHS = [
|
|
|
18
18
|
`./.github/workflows/gitlab.ci.yml`,
|
|
19
19
|
`./.github/workflows/publish.ci.yml`,
|
|
20
20
|
`./.github/workflows/release.cd.yml`,
|
|
21
|
-
`./
|
|
21
|
+
`./deploy/lib`,
|
|
22
|
+
'./deploy/release',
|
|
23
|
+
'./deploy/pwa-microservices-template',
|
|
24
|
+
'./src/client/services/user/guest.service.js',
|
|
22
25
|
'./src/api/user/guest.service.js',
|
|
23
26
|
'./src/ws/IoInterface.js',
|
|
24
27
|
'./src/ws/IoServer.js',
|
|
@@ -43,7 +43,7 @@ RUN make -f Web.mk all BUILD_MODE=${BUILD_MODE} OUTPUT_DIR=bin/
|
|
|
43
43
|
# --- Runtime Image ---
|
|
44
44
|
FROM rockylinux/rockylinux:9 AS runtime
|
|
45
45
|
|
|
46
|
-
ARG UNDERPOST_VERSION=3.
|
|
46
|
+
ARG UNDERPOST_VERSION=3.3.0
|
|
47
47
|
ARG NODE_VERSION=24.15.0
|
|
48
48
|
RUN set -eux; \
|
|
49
49
|
dnf -y update; \
|
|
@@ -11,7 +11,7 @@ RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o server ./cmd/cyberia-se
|
|
|
11
11
|
|
|
12
12
|
# --- Runtime Image ---
|
|
13
13
|
FROM rockylinux/rockylinux:9 AS runtime
|
|
14
|
-
ARG UNDERPOST_VERSION=3.
|
|
14
|
+
ARG UNDERPOST_VERSION=3.3.0
|
|
15
15
|
ARG NODE_VERSION=24.15.0
|
|
16
16
|
|
|
17
17
|
RUN set -eux; \
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# Stage 1 — builder: clone the private deploy, build it, then scrub secrets.
|
|
7
7
|
# ---------------------------------------------------------------------------
|
|
8
8
|
FROM rockylinux/rockylinux:9 AS builder
|
|
9
|
-
ARG UNDERPOST_VERSION=3.
|
|
9
|
+
ARG UNDERPOST_VERSION=3.3.0
|
|
10
10
|
# Pin Node to an exact patch: dnf's nodejs:24 module lags (24.14.1) while
|
|
11
11
|
# underpost's dependencies require >=24.15.0, so install the official binary.
|
|
12
12
|
ARG NODE_VERSION=24.15.0
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# Stage 1 — builder: clone the private deploy, build it, then scrub secrets.
|
|
7
7
|
# ---------------------------------------------------------------------------
|
|
8
8
|
FROM rockylinux/rockylinux:9 AS builder
|
|
9
|
-
ARG UNDERPOST_VERSION=3.
|
|
9
|
+
ARG UNDERPOST_VERSION=3.3.0
|
|
10
10
|
# Pin Node to an exact patch: dnf's nodejs:24 module lags (24.14.1) while
|
|
11
11
|
# underpost's dependencies require >=24.15.0, so install the official binary.
|
|
12
12
|
ARG NODE_VERSION=24.15.0
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# Stage 1 — builder: clone the private deploy, build it, then scrub secrets.
|
|
7
7
|
# ---------------------------------------------------------------------------
|
|
8
8
|
FROM rockylinux/rockylinux:9 AS builder
|
|
9
|
-
ARG UNDERPOST_VERSION=3.
|
|
9
|
+
ARG UNDERPOST_VERSION=3.3.0
|
|
10
10
|
# Pin Node to an exact patch: dnf's nodejs:24 module lags (24.14.1) while
|
|
11
11
|
# underpost's dependencies require >=24.15.0, so install the official binary.
|
|
12
12
|
ARG NODE_VERSION=24.15.0
|
|
@@ -40,29 +40,27 @@ VALKEY_HOST=valkey-service
|
|
|
40
40
|
VALKEY_PORT=6379
|
|
41
41
|
|
|
42
42
|
# --- Cyberia instance wiring (compose service DNS) ---------------------------
|
|
43
|
-
# cyberia-server-* -> engine
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
ENGINE_GRPC_ADDRESS=engine-cyberia:50051
|
|
43
|
+
# cyberia-server-* -> stable engine gateway for HTTP and the raw engine runtime
|
|
44
|
+
# for gRPC. The public engine-cyberia name belongs to nginx, avoiding ambiguous
|
|
45
|
+
# Docker DNS while keeping one stable HTTP endpoint for every module.
|
|
46
|
+
ENGINE_API_BASE_URL=http://engine-cyberia
|
|
47
|
+
ENGINE_GRPC_ADDRESS=engine-cyberia-runtime:50051
|
|
49
48
|
|
|
50
49
|
# Client-visible Content Authority origin, forwarded to browser/Raylib clients
|
|
51
50
|
# for every engine-cyberia content/asset/metadata request. Host-reachable
|
|
52
|
-
# (
|
|
51
|
+
# (Docker publishes the raw engine runtime on host :4005). Unlike the internal
|
|
52
|
+
# ENGINE_API_BASE_URL, this value is consumed outside the Compose network:
|
|
53
53
|
# the two responsibilities must never overwrite each other.
|
|
54
54
|
ENGINE_PUBLIC_URL=http://localhost:4005
|
|
55
55
|
ENGINE_GRPC_RELOAD_INTERVAL_SEC=300
|
|
56
56
|
|
|
57
57
|
# --- Browser-facing client runtime config (injected by docker-driver.py) -----
|
|
58
58
|
# The single WASM bundle resolves its instance from the URL sub-path and builds
|
|
59
|
-
# its endpoints from these origins.
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
|
|
64
|
-
# http://localhost/FOREST -> FOREST instance, ws -> ws://localhost/FOREST/ws
|
|
65
|
-
CYBERIA_WS_ORIGIN=ws://localhost
|
|
59
|
+
# its endpoints from these origins. HTTP client/API traffic uses nginx on :80;
|
|
60
|
+
# WebSocket traffic uses the dedicated multi-path server gateway on :8081.
|
|
61
|
+
# http://localhost/ -> default, ws://localhost:8081/ws
|
|
62
|
+
# http://localhost/FOREST -> FOREST, ws://localhost:8081/FOREST/ws
|
|
63
|
+
CYBERIA_WS_ORIGIN=ws://localhost:8081
|
|
66
64
|
CYBERIA_ENGINE_API_ORIGIN=http://localhost
|
|
67
65
|
CYBERIA_DEFAULT_INSTANCE=amethyst-strata-expansion
|
|
68
66
|
|
|
@@ -72,6 +70,22 @@ CYBERIA_DEFAULT_INSTANCE=amethyst-strata-expansion
|
|
|
72
70
|
CYBERIA_SERVER_APP_ENV=development
|
|
73
71
|
CYBERIA_SERVER_LOG_LEVEL=
|
|
74
72
|
|
|
73
|
+
# --- cyberia-server WebSocket admission and rate limits ----------------------
|
|
74
|
+
# Unset keeps the built-in default. An explicit 0 turns that one limit off.
|
|
75
|
+
# The startup log prints the effective profile ("ws limits: ...").
|
|
76
|
+
#
|
|
77
|
+
# Set CYBERIA_DISABLE_CONNECTION_LIMITS=1 to turn every limit off. The load test
|
|
78
|
+
# (test/cyberia-load.test.js) drives every simulated client from one address, so
|
|
79
|
+
# it needs this. NEVER enable it on a public deploy.
|
|
80
|
+
CYBERIA_DISABLE_CONNECTION_LIMITS=
|
|
81
|
+
CYBERIA_MAX_CONNECTIONS=
|
|
82
|
+
CYBERIA_MAX_CONNECTIONS_PER_IP=
|
|
83
|
+
CYBERIA_CONNECT_RATE_PER_IP=
|
|
84
|
+
CYBERIA_CONNECT_BURST_PER_IP=
|
|
85
|
+
CYBERIA_MESSAGE_RATE=
|
|
86
|
+
CYBERIA_MESSAGE_BURST=
|
|
87
|
+
CYBERIA_MAX_STRIKES=
|
|
88
|
+
|
|
75
89
|
# --- engine-cyberia runtime env (loaded into the container via env_file) -----
|
|
76
90
|
# The dd-cyberia engine (engine-private/conf/dd-cyberia/conf.server.json) needs
|
|
77
91
|
# these to boot: DB auth + per-site DB names, the base PORT (the cyberia host is
|
|
@@ -82,6 +96,7 @@ NODE_OPTIONS=--max-old-space-size=8192
|
|
|
82
96
|
BASE_API=api
|
|
83
97
|
DEFAULT_DEPLOY_ID=dd-cyberia
|
|
84
98
|
DEPLOY_ID=dd-cyberia
|
|
99
|
+
# Configuration/DB selector from conf.server.json; this is not a Docker DNS alias.
|
|
85
100
|
DEFAULT_DEPLOY_HOST=www.cyberiaonline.com
|
|
86
101
|
DEFAULT_DEPLOY_PATH=/
|
|
87
102
|
DISABLE_API_RATE_LIMIT=true
|
|
@@ -131,7 +146,25 @@ IPFS_CLUSTER_API_URL=http://ipfs-cluster:9094
|
|
|
131
146
|
# in docker-compose.yml). Override for a real/shared cluster.
|
|
132
147
|
# CLUSTER_SECRET=
|
|
133
148
|
|
|
134
|
-
# ---
|
|
149
|
+
# --- Local access ------------------------------------------------------------
|
|
150
|
+
# Client gateway: http://localhost/{,FOREST,TEST}
|
|
151
|
+
# Client port alias: http://localhost:8082/{,FOREST,TEST}
|
|
152
|
+
# Server gateway: http://localhost:8081/{,FOREST,TEST}
|
|
153
|
+
# Engine authority: http://localhost:4005
|
|
154
|
+
# Docker-network gateways:
|
|
155
|
+
# http://cyberia-client/{,FOREST,TEST}
|
|
156
|
+
# http://cyberia-server/{,FOREST,TEST}
|
|
157
|
+
# http://engine-cyberia/
|
|
158
|
+
#
|
|
159
|
+
# The *.localhost aliases normally resolve to loopback without configuration:
|
|
160
|
+
# http://client.cyberia.localhost/{,FOREST,TEST}
|
|
161
|
+
# http://server.cyberia.localhost/{,FOREST,TEST}
|
|
162
|
+
# http://engine.cyberia.localhost/
|
|
163
|
+
# `node bin/cyberia run-workflow docker:up` maintains this host entry (the
|
|
164
|
+
# aliases already work between containers):
|
|
165
|
+
# 127.0.0.1 cyberia-client cyberia-server engine-cyberia
|
|
166
|
+
#
|
|
167
|
+
# Host-published ports:
|
|
135
168
|
PROXY_HTTP_PORT=80
|
|
136
169
|
IPFS_API_PORT=5001
|
|
137
170
|
IPFS_GATEWAY_PORT=8080
|
|
@@ -140,5 +173,7 @@ MONGO_HOST_PORT=27017
|
|
|
140
173
|
VALKEY_NODEPORT=32079
|
|
141
174
|
ENGINE_CYBERIA_REST_PORT=4005
|
|
142
175
|
ENGINE_CYBERIA_GRPC_PORT=50051
|
|
176
|
+
# Multi-path nginx server gateway, not a single server container publication.
|
|
143
177
|
CYBERIA_SERVER_PORT=8081
|
|
178
|
+
# Multi-path nginx client gateway; raw client containers remain internal.
|
|
144
179
|
CYBERIA_CLIENT_PORT=8082
|