cyberia 3.0.3 → 3.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{.env.production → .env.example} +20 -4
- package/.github/workflows/engine-cyberia.cd.yml +43 -10
- package/.github/workflows/engine-cyberia.ci.yml +48 -26
- package/.github/workflows/ghpkg.ci.yml +5 -5
- package/.github/workflows/gitlab.ci.yml +1 -1
- package/.github/workflows/hardhat.ci.yml +82 -0
- package/.github/workflows/npmpkg.ci.yml +60 -14
- package/.github/workflows/publish.ci.yml +26 -7
- package/.github/workflows/publish.cyberia.ci.yml +5 -5
- package/.github/workflows/pwa-microservices-template-page.cd.yml +6 -7
- package/.github/workflows/pwa-microservices-template-test.ci.yml +4 -4
- package/.github/workflows/release.cd.yml +14 -8
- package/.vscode/extensions.json +9 -8
- package/.vscode/settings.json +3 -2
- package/CHANGELOG.md +643 -1
- package/CLI-HELP.md +132 -57
- package/Dockerfile +4 -2
- package/README.md +347 -22
- package/WHITE-PAPER.md +1540 -0
- package/bin/build.js +21 -12
- package/bin/cyberia.js +2640 -106
- package/bin/deploy.js +258 -372
- package/bin/file.js +5 -1
- package/bin/index.js +2640 -106
- package/bin/vs.js +3 -3
- package/conf.js +169 -105
- package/deployment.yaml +236 -20
- package/hardhat/.env.example +31 -0
- package/hardhat/README.md +531 -0
- package/hardhat/WHITE-PAPER.md +1540 -0
- package/hardhat/contracts/ObjectLayerToken.sol +391 -0
- package/hardhat/deployments/.gitkeep +0 -0
- package/hardhat/deployments/hardhat-ObjectLayerToken.json +11 -0
- package/hardhat/hardhat.config.js +136 -0
- package/hardhat/ignition/modules/ObjectLayerToken.js +21 -0
- package/hardhat/networks/besu-object-layer.network.json +138 -0
- package/hardhat/package-lock.json +4323 -0
- package/hardhat/package.json +36 -0
- package/hardhat/scripts/deployObjectLayerToken.js +98 -0
- package/hardhat/test/ObjectLayerToken.js +592 -0
- package/hardhat/types/ethers-contracts/ObjectLayerToken.ts +690 -0
- package/hardhat/types/ethers-contracts/common.ts +92 -0
- package/hardhat/types/ethers-contracts/factories/ObjectLayerToken__factory.ts +1055 -0
- package/hardhat/types/ethers-contracts/factories/index.ts +4 -0
- package/hardhat/types/ethers-contracts/hardhat.d.ts +47 -0
- package/hardhat/types/ethers-contracts/index.ts +6 -0
- package/jsdoc.dd-cyberia.json +68 -0
- package/jsdoc.json +65 -49
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +5 -4
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +5 -4
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +562 -0
- package/manifests/deployment/dd-cyberia-development/proxy.yaml +297 -0
- package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +132 -0
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +88 -74
- package/manifests/deployment/dd-test-development/proxy.yaml +13 -4
- package/manifests/deployment/playwright/deployment.yaml +1 -1
- package/manifests/pv-pvc-dd.yaml +1 -1
- package/nodemon.json +1 -1
- package/package.json +60 -48
- package/proxy.yaml +118 -10
- package/pv-pvc.yaml +132 -0
- package/scripts/k3s-node-setup.sh +1 -1
- package/scripts/ports-ls.sh +2 -0
- package/scripts/rhel-grpc-setup.sh +56 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +47 -1
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +17 -2
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +80 -7
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +93 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +36 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +29 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +51 -0
- package/src/api/cyberia-entity/cyberia-entity.controller.js +74 -0
- package/src/api/cyberia-entity/cyberia-entity.model.js +24 -0
- package/src/api/cyberia-entity/cyberia-entity.router.js +27 -0
- package/src/api/cyberia-entity/cyberia-entity.service.js +42 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +368 -0
- package/src/api/cyberia-instance/cyberia-instance.controller.js +92 -0
- package/src/api/cyberia-instance/cyberia-instance.model.js +84 -0
- package/src/api/cyberia-instance/cyberia-instance.router.js +63 -0
- package/src/api/cyberia-instance/cyberia-instance.service.js +191 -0
- package/src/api/cyberia-instance/cyberia-portal-connector.js +486 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +74 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +413 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +228 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +27 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +42 -0
- package/src/api/cyberia-map/cyberia-map.controller.js +79 -0
- package/src/api/cyberia-map/cyberia-map.model.js +30 -0
- package/src/api/cyberia-map/cyberia-map.router.js +40 -0
- package/src/api/cyberia-map/cyberia-map.service.js +74 -0
- package/src/api/document/document.service.js +1 -1
- package/src/api/file/file.controller.js +3 -1
- package/src/api/file/file.ref.json +18 -0
- package/src/api/file/file.service.js +28 -5
- package/src/api/ipfs/ipfs.controller.js +4 -25
- package/src/api/ipfs/ipfs.model.js +43 -34
- package/src/api/ipfs/ipfs.router.js +8 -13
- package/src/api/ipfs/ipfs.service.js +56 -104
- package/src/api/object-layer/README.md +347 -22
- package/src/api/object-layer/object-layer.controller.js +6 -2
- package/src/api/object-layer/object-layer.model.js +12 -8
- package/src/api/object-layer/object-layer.router.js +698 -42
- package/src/api/object-layer/object-layer.service.js +119 -37
- package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +1 -2
- package/src/api/user/user.router.js +10 -5
- package/src/api/user/user.service.js +15 -14
- package/src/cli/baremetal.js +6 -10
- package/src/cli/cloud-init.js +0 -3
- package/src/cli/cluster.js +7 -7
- package/src/cli/db.js +723 -857
- package/src/cli/deploy.js +215 -105
- package/src/cli/env.js +34 -5
- package/src/cli/fs.js +5 -4
- package/src/cli/image.js +0 -3
- package/src/cli/index.js +83 -15
- package/src/cli/kubectl.js +211 -0
- package/src/cli/monitor.js +5 -6
- package/src/cli/release.js +284 -0
- package/src/cli/repository.js +708 -62
- package/src/cli/run.js +371 -151
- package/src/cli/secrets.js +73 -2
- package/src/cli/ssh.js +1 -1
- package/src/cli/test.js +3 -3
- package/src/client/Cryptokoyn.index.js +3 -4
- package/src/client/CyberiaPortal.index.js +3 -4
- package/src/client/Default.index.js +3 -4
- package/src/client/Itemledger.index.js +4 -963
- package/src/client/Underpost.index.js +3 -4
- package/src/client/components/core/AgGrid.js +20 -5
- package/src/client/components/core/Alert.js +2 -2
- package/src/client/components/core/AppStore.js +69 -0
- package/src/client/components/core/CalendarCore.js +2 -2
- package/src/client/components/core/Content.js +22 -3
- package/src/client/components/core/Docs.js +30 -6
- package/src/client/components/core/DropDown.js +137 -17
- package/src/client/components/core/FileExplorer.js +71 -4
- package/src/client/components/core/Input.js +1 -1
- package/src/client/components/core/Keyboard.js +2 -2
- package/src/client/components/core/LogIn.js +2 -2
- package/src/client/components/core/LogOut.js +2 -2
- package/src/client/components/core/Modal.js +20 -7
- package/src/client/components/core/Panel.js +0 -1
- package/src/client/components/core/PanelForm.js +19 -19
- package/src/client/components/core/RichText.js +1 -2
- package/src/client/components/core/SocketIo.js +82 -29
- package/src/client/components/core/SocketIoHandler.js +75 -0
- package/src/client/components/core/Stream.js +143 -95
- package/src/client/components/core/Webhook.js +40 -7
- package/src/client/components/cryptokoyn/AppStoreCryptokoyn.js +5 -0
- package/src/client/components/cryptokoyn/LogInCryptokoyn.js +3 -3
- package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +2 -2
- package/src/client/components/cryptokoyn/MenuCryptokoyn.js +3 -3
- package/src/client/components/cryptokoyn/SocketIoCryptokoyn.js +3 -51
- package/src/client/components/cyberia/InstanceEngineCyberia.js +700 -0
- package/src/client/components/cyberia/MapEngineCyberia.js +1359 -2
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +17 -6
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +92 -54
- package/src/client/components/cyberia-portal/AppStoreCyberiaPortal.js +5 -0
- package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +217 -30
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +44 -2
- package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +3 -4
- package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +2 -2
- package/src/client/components/cyberia-portal/MenuCyberiaPortal.js +104 -9
- package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +5 -0
- package/src/client/components/cyberia-portal/SocketIoCyberiaPortal.js +3 -49
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -0
- package/src/client/components/default/AppStoreDefault.js +5 -0
- package/src/client/components/default/LogInDefault.js +3 -3
- package/src/client/components/default/LogOutDefault.js +2 -2
- package/src/client/components/default/MenuDefault.js +5 -5
- package/src/client/components/default/SocketIoDefault.js +3 -51
- package/src/client/components/itemledger/AppStoreItemledger.js +5 -0
- package/src/client/components/itemledger/LogInItemledger.js +3 -3
- package/src/client/components/itemledger/LogOutItemledger.js +2 -2
- package/src/client/components/itemledger/MenuItemledger.js +3 -3
- package/src/client/components/itemledger/SocketIoItemledger.js +3 -51
- package/src/client/components/underpost/AppStoreUnderpost.js +5 -0
- package/src/client/components/underpost/CssUnderpost.js +59 -0
- package/src/client/components/underpost/LogInUnderpost.js +6 -3
- package/src/client/components/underpost/LogOutUnderpost.js +4 -2
- package/src/client/components/underpost/MenuUnderpost.js +104 -18
- package/src/client/components/underpost/RoutesUnderpost.js +2 -0
- package/src/client/components/underpost/SocketIoUnderpost.js +3 -51
- package/src/client/public/cryptokoyn/assets/logo/base-icon.png +0 -0
- package/src/client/public/cryptokoyn/browserconfig.xml +12 -0
- package/src/client/public/cryptokoyn/microdata.json +85 -0
- package/src/client/public/cryptokoyn/site.webmanifest +57 -0
- package/src/client/public/cryptokoyn/sitemap +3 -3
- package/src/client/public/default/sitemap +3 -3
- package/src/client/public/itemledger/browserconfig.xml +2 -2
- package/src/client/public/itemledger/manifest.webmanifest +4 -4
- package/src/client/public/itemledger/microdata.json +71 -0
- package/src/client/public/itemledger/sitemap +3 -3
- package/src/client/public/itemledger/yandex-browser-manifest.json +2 -2
- package/src/client/public/test/sitemap +3 -3
- package/src/client/services/core/core.service.js +20 -8
- package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +105 -0
- package/src/client/services/cyberia-entity/cyberia-entity.management.js +57 -0
- package/src/client/services/cyberia-entity/cyberia-entity.service.js +105 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +194 -0
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +122 -0
- package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +105 -0
- package/src/client/services/cyberia-map/cyberia-map.management.js +193 -0
- package/src/client/services/cyberia-map/cyberia-map.service.js +126 -0
- package/src/client/services/instance/instance.management.js +2 -2
- package/src/client/services/ipfs/ipfs.service.js +3 -23
- package/src/client/services/object-layer/object-layer.management.js +3 -3
- package/src/client/services/object-layer/object-layer.service.js +21 -0
- package/src/client/services/user/user.management.js +2 -2
- package/src/client/ssr/body/404.js +15 -11
- package/src/client/ssr/body/500.js +15 -11
- package/src/client/ssr/body/SwaggerDarkMode.js +285 -0
- package/src/client/ssr/head/PwaItemledger.js +60 -0
- package/src/client/ssr/offline/NoNetworkConnection.js +11 -10
- package/src/client/ssr/pages/CyberiaServerMetrics.js +1 -1
- package/src/client/ssr/pages/Test.js +11 -10
- package/src/client.build.js +0 -3
- package/src/client.dev.js +0 -3
- package/src/db/DataBaseProvider.js +17 -2
- package/src/db/mariadb/MariaDB.js +14 -9
- package/src/db/mongo/MongooseDB.js +17 -1
- package/src/grpc/cyberia/OFF_CHAIN_ECONOMY.md +305 -0
- package/src/grpc/cyberia/README.md +326 -0
- package/src/grpc/cyberia/grpc-server.js +530 -0
- package/src/index.js +24 -1
- package/src/proxy.js +0 -3
- package/src/runtime/express/Dockerfile +4 -0
- package/src/runtime/express/Express.js +33 -10
- package/src/runtime/lampp/Dockerfile +13 -2
- package/src/runtime/lampp/Lampp.js +33 -17
- package/src/runtime/wp/Dockerfile +68 -0
- package/src/runtime/wp/Wp.js +639 -0
- package/src/server/auth.js +36 -15
- package/src/server/backup.js +39 -12
- package/src/server/besu-genesis-generator.js +1630 -0
- package/src/server/client-build-docs.js +133 -17
- package/src/server/client-build-live.js +9 -18
- package/src/server/client-build.js +229 -101
- package/src/server/client-dev-server.js +14 -13
- package/src/server/client-formatted.js +109 -57
- package/src/server/conf.js +391 -164
- package/src/server/cron.js +27 -24
- package/src/server/dns.js +29 -12
- package/src/server/downloader.js +0 -2
- package/src/server/ipfs-client.js +24 -1
- package/src/server/logger.js +27 -9
- package/src/server/object-layer.js +217 -103
- package/src/server/peer.js +8 -2
- package/src/server/process.js +1 -50
- package/src/server/proxy.js +4 -8
- package/src/server/runtime.js +30 -9
- package/src/server/semantic-layer-generator-floor.js +359 -0
- package/src/server/semantic-layer-generator-skin.js +1294 -0
- package/src/server/semantic-layer-generator.js +116 -555
- package/src/server/ssr.js +0 -3
- package/src/server/start.js +19 -12
- package/src/server/tls.js +0 -2
- package/src/server.js +0 -4
- package/src/ws/IoInterface.js +1 -10
- package/src/ws/IoServer.js +14 -33
- package/src/ws/core/channels/core.ws.chat.js +65 -20
- package/src/ws/core/channels/core.ws.mailer.js +113 -32
- package/src/ws/core/channels/core.ws.stream.js +90 -31
- package/src/ws/core/core.ws.connection.js +12 -33
- package/src/ws/core/core.ws.emit.js +10 -26
- package/src/ws/core/core.ws.server.js +25 -58
- package/src/ws/default/channels/default.ws.main.js +53 -12
- package/src/ws/default/default.ws.connection.js +26 -13
- package/src/ws/default/default.ws.server.js +30 -12
- package/.env.development +0 -43
- package/.env.test +0 -43
- package/hardhat/contracts/CryptoKoyn.sol +0 -59
- package/hardhat/contracts/ItemLedger.sol +0 -73
- package/hardhat/contracts/Lock.sol +0 -34
- package/hardhat/hardhat.config.cjs +0 -45
- package/hardhat/ignition/modules/Lock.js +0 -18
- package/hardhat/networks/cryptokoyn-itemledger.network.json +0 -29
- package/hardhat/scripts/deployCryptokoyn.cjs +0 -25
- package/hardhat/scripts/deployItemledger.cjs +0 -25
- package/hardhat/test/Lock.js +0 -126
- package/hardhat/white-paper.md +0 -581
- package/src/client/components/cryptokoyn/CommonCryptokoyn.js +0 -29
- package/src/client/components/cryptokoyn/ElementsCryptokoyn.js +0 -38
- package/src/client/components/cyberia-portal/ElementsCyberiaPortal.js +0 -38
- package/src/client/components/default/ElementsDefault.js +0 -38
- package/src/client/components/itemledger/CommonItemledger.js +0 -29
- package/src/client/components/itemledger/ElementsItemledger.js +0 -38
- package/src/client/components/underpost/CommonUnderpost.js +0 -29
- package/src/client/components/underpost/ElementsUnderpost.js +0 -38
- package/src/ws/core/management/core.ws.chat.js +0 -8
- package/src/ws/core/management/core.ws.mailer.js +0 -16
- package/src/ws/core/management/core.ws.stream.js +0 -8
- package/src/ws/default/management/default.ws.main.js +0 -8
- package/white-paper.md +0 -581
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Mongoose model for IPFS
|
|
3
|
-
*
|
|
2
|
+
* Mongoose model for the IPFS CID Registry.
|
|
3
|
+
*
|
|
4
|
+
* Purpose: tracks every CID that the Engine has pinned to IPFS so that:
|
|
5
|
+
* 1. Deletions can cleanly unpin the right CID from the IPFS node/cluster.
|
|
6
|
+
* 2. Admins can run a health-check that verifies every DB-registered CID is
|
|
7
|
+
* still actually pinned (GET /ipfs/verify).
|
|
8
|
+
* 3. Garbage-collection jobs can discover orphaned CIDs (pinned on the node
|
|
9
|
+
* but not referenced by any DB document).
|
|
10
|
+
*
|
|
11
|
+
* Fields:
|
|
12
|
+
* cid - IPFS Content Identifier (CIDv0 or CIDv1).
|
|
13
|
+
* resourceType - What kind of asset this CID belongs to:
|
|
14
|
+
* 'object-layer-data' - JSON payload of an ObjectLayer document.
|
|
15
|
+
* 'atlas-sprite-sheet' - PNG sprite-sheet of an ObjectLayer.
|
|
16
|
+
* 'atlas-metadata' - JSON metadata of an AtlasSpriteSheet.
|
|
17
|
+
* mfsPath - MFS (Mutable File System) path used when the CID was added,
|
|
18
|
+
* e.g. /object-layer/sword/sword_data.json.
|
|
19
|
+
* Enables targeted removal via files/rm without knowing the CID.
|
|
4
20
|
*
|
|
5
21
|
* @module src/api/ipfs/ipfs.model.js
|
|
6
22
|
* @namespace IpfsModel
|
|
@@ -8,14 +24,6 @@
|
|
|
8
24
|
|
|
9
25
|
import { Schema, model } from 'mongoose';
|
|
10
26
|
|
|
11
|
-
/**
|
|
12
|
-
* @typedef {Object} Ipfs
|
|
13
|
-
* @property {string} cid – IPFS Content Identifier (CIDv0 or CIDv1).
|
|
14
|
-
* @property {Types.ObjectId} userId – Reference to the User who owns / requested the pin.
|
|
15
|
-
* @property {Date} createdAt – Auto-managed by Mongoose.
|
|
16
|
-
* @property {Date} updatedAt – Auto-managed by Mongoose.
|
|
17
|
-
* @memberof IpfsModel
|
|
18
|
-
*/
|
|
19
27
|
const IpfsSchema = new Schema(
|
|
20
28
|
{
|
|
21
29
|
cid: {
|
|
@@ -23,10 +31,19 @@ const IpfsSchema = new Schema(
|
|
|
23
31
|
required: true,
|
|
24
32
|
trim: true,
|
|
25
33
|
},
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
// Asset category - determines which service owns this CID.
|
|
35
|
+
resourceType: {
|
|
36
|
+
type: String,
|
|
29
37
|
required: true,
|
|
38
|
+
trim: true,
|
|
39
|
+
enum: ['object-layer-data', 'atlas-sprite-sheet', 'atlas-metadata'],
|
|
40
|
+
},
|
|
41
|
+
// MFS path used when the content was added to IPFS.
|
|
42
|
+
// Empty string when the content was added without an MFS copy.
|
|
43
|
+
mfsPath: {
|
|
44
|
+
type: String,
|
|
45
|
+
default: '',
|
|
46
|
+
trim: true,
|
|
30
47
|
},
|
|
31
48
|
},
|
|
32
49
|
{
|
|
@@ -34,14 +51,14 @@ const IpfsSchema = new Schema(
|
|
|
34
51
|
},
|
|
35
52
|
);
|
|
36
53
|
|
|
37
|
-
//
|
|
38
|
-
IpfsSchema.index({ cid: 1,
|
|
54
|
+
// One DB record per (CID, resourceType) pair.
|
|
55
|
+
IpfsSchema.index({ cid: 1, resourceType: 1 }, { unique: true });
|
|
39
56
|
|
|
40
|
-
// Fast look-ups by
|
|
41
|
-
IpfsSchema.index({
|
|
57
|
+
// Fast look-ups for health-check and garbage-collection by type.
|
|
58
|
+
IpfsSchema.index({ resourceType: 1 });
|
|
42
59
|
|
|
43
|
-
// Fast look-ups
|
|
44
|
-
IpfsSchema.index({
|
|
60
|
+
// Fast look-ups for targeted MFS cleanup.
|
|
61
|
+
IpfsSchema.index({ mfsPath: 1 });
|
|
45
62
|
|
|
46
63
|
const IpfsModel = model('Ipfs', IpfsSchema);
|
|
47
64
|
|
|
@@ -49,21 +66,13 @@ const ProviderSchema = IpfsSchema;
|
|
|
49
66
|
|
|
50
67
|
const IpfsDto = {
|
|
51
68
|
select: {
|
|
52
|
-
get: () => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
};
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
populate: {
|
|
63
|
-
user: () => ({
|
|
64
|
-
path: 'userId',
|
|
65
|
-
model: 'User',
|
|
66
|
-
select: '_id username email role',
|
|
69
|
+
get: () => ({
|
|
70
|
+
_id: 1,
|
|
71
|
+
cid: 1,
|
|
72
|
+
resourceType: 1,
|
|
73
|
+
mfsPath: 1,
|
|
74
|
+
createdAt: 1,
|
|
75
|
+
updatedAt: 1,
|
|
67
76
|
}),
|
|
68
77
|
},
|
|
69
78
|
};
|
|
@@ -8,19 +8,14 @@ const logger = loggerFactory(import.meta);
|
|
|
8
8
|
const IpfsRouter = (options) => {
|
|
9
9
|
const router = express.Router();
|
|
10
10
|
const authMiddleware = options.authMiddleware;
|
|
11
|
-
|
|
12
|
-
router.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
);
|
|
18
|
-
router.
|
|
19
|
-
router.post(`/`, authMiddleware, async (req, res) => await IpfsController.post(req, res, options));
|
|
20
|
-
router.get(`/:id`, authMiddleware, async (req, res) => await IpfsController.get(req, res, options));
|
|
21
|
-
router.get(`/`, authMiddleware, async (req, res) => await IpfsController.get(req, res, options));
|
|
22
|
-
router.put(`/:id`, authMiddleware, async (req, res) => await IpfsController.put(req, res, options));
|
|
23
|
-
router.put(`/`, authMiddleware, async (req, res) => await IpfsController.put(req, res, options));
|
|
11
|
+
// Health / audit — must come before /:id to avoid matching conflicts.
|
|
12
|
+
router.get(`/verify`, authMiddleware, adminGuard, async (req, res) => await IpfsController.verify(req, res, options));
|
|
13
|
+
router.post(`/:id`, authMiddleware, adminGuard, async (req, res) => await IpfsController.post(req, res, options));
|
|
14
|
+
router.post(`/`, authMiddleware, adminGuard, async (req, res) => await IpfsController.post(req, res, options));
|
|
15
|
+
router.get(`/:id`, authMiddleware, adminGuard, async (req, res) => await IpfsController.get(req, res, options));
|
|
16
|
+
router.get(`/`, authMiddleware, adminGuard, async (req, res) => await IpfsController.get(req, res, options));
|
|
17
|
+
router.put(`/:id`, authMiddleware, adminGuard, async (req, res) => await IpfsController.put(req, res, options));
|
|
18
|
+
router.put(`/`, authMiddleware, adminGuard, async (req, res) => await IpfsController.put(req, res, options));
|
|
24
19
|
router.delete(`/:id`, authMiddleware, adminGuard, async (req, res) => await IpfsController.delete(req, res, options));
|
|
25
20
|
router.delete(`/`, authMiddleware, adminGuard, async (req, res) => await IpfsController.delete(req, res, options));
|
|
26
21
|
return router;
|
|
@@ -7,47 +7,40 @@ import { IpfsDto } from './ipfs.model.js';
|
|
|
7
7
|
const logger = loggerFactory(import.meta);
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Upsert a CID registry entry.
|
|
11
|
+
* Called by asset services (ObjectLayer, AtlasSpriteSheet) after a successful
|
|
12
|
+
* IPFS pin so the registry always reflects what is actually pinned.
|
|
13
13
|
*
|
|
14
|
-
* @param {object}
|
|
15
|
-
* @param {string}
|
|
16
|
-
* @param {string}
|
|
17
|
-
* @param {
|
|
14
|
+
* @param {object} opts
|
|
15
|
+
* @param {string} opts.cid - IPFS Content Identifier.
|
|
16
|
+
* @param {string} opts.resourceType - Asset category ('object-layer-data' | 'atlas-sprite-sheet' | 'atlas-metadata').
|
|
17
|
+
* @param {string} [opts.mfsPath] - MFS path used when adding the content.
|
|
18
|
+
* @param {object} opts.options - Router options ({ host, path }) for DB lookup.
|
|
18
19
|
* @returns {Promise<import('mongoose').Document>}
|
|
19
20
|
*/
|
|
20
|
-
const createPinRecord = async ({ cid,
|
|
21
|
+
const createPinRecord = async ({ cid, resourceType, mfsPath = '', options }) => {
|
|
21
22
|
const Ipfs = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Ipfs;
|
|
22
|
-
|
|
23
|
-
// Upsert: if a record for this user + CID already exists, just touch it.
|
|
24
23
|
const record = await Ipfs.findOneAndUpdate(
|
|
25
|
-
{ cid,
|
|
26
|
-
{ cid,
|
|
27
|
-
{ upsert: true,
|
|
24
|
+
{ cid, resourceType },
|
|
25
|
+
{ cid, resourceType, mfsPath },
|
|
26
|
+
{ upsert: true, returnDocument: 'after', setDefaultsOnInsert: true },
|
|
28
27
|
);
|
|
29
|
-
|
|
30
|
-
logger.info(`IPFS pin record upserted – CID: ${cid}, userId: ${userId}`);
|
|
28
|
+
logger.info(`IPFS registry upserted – CID: ${cid}, type: ${resourceType}, mfsPath: ${mfsPath}`);
|
|
31
29
|
return record;
|
|
32
30
|
};
|
|
33
31
|
|
|
34
32
|
/**
|
|
35
|
-
* Remove all DB
|
|
36
|
-
* Always deletes
|
|
37
|
-
* the database stays clean.
|
|
33
|
+
* Remove all DB registry entries for a CID, then best-effort unpin from the IPFS node.
|
|
34
|
+
* Always deletes DB records first so the registry stays clean even if the node is down.
|
|
38
35
|
*
|
|
39
|
-
* @param {string} cid
|
|
40
|
-
* @param {object} options
|
|
36
|
+
* @param {string} cid - IPFS Content Identifier to remove.
|
|
37
|
+
* @param {object} options - Router options ({ host, path }) for DB lookup.
|
|
41
38
|
* @returns {Promise<void>}
|
|
42
39
|
*/
|
|
43
40
|
const removePinRecordsAndUnpin = async (cid, options) => {
|
|
44
41
|
const Ipfs = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Ipfs;
|
|
45
|
-
|
|
46
|
-
// 1. Remove all DB pin records for this CID first
|
|
47
42
|
await Ipfs.deleteMany({ cid });
|
|
48
|
-
logger.info(`Removed
|
|
49
|
-
|
|
50
|
-
// 2. Best-effort unpin from IPFS node/cluster (ignore "not pinned" errors)
|
|
43
|
+
logger.info(`Removed IPFS registry entries for CID: ${cid}`);
|
|
51
44
|
try {
|
|
52
45
|
await IpfsClient.unpinCid(cid);
|
|
53
46
|
} catch (err) {
|
|
@@ -65,128 +58,87 @@ const IpfsService = {
|
|
|
65
58
|
// ──────────────────────────────────────────────
|
|
66
59
|
|
|
67
60
|
post: async (req, res, options) => {
|
|
68
|
-
/** @type {import('./ipfs.model.js').IpfsModel} */
|
|
69
61
|
const Ipfs = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Ipfs;
|
|
70
|
-
|
|
71
|
-
// Accept { cid, userId? } in body.
|
|
72
|
-
// If userId is omitted, fall back to the authenticated user.
|
|
73
|
-
const body = { ...req.body };
|
|
74
|
-
if (!body.userId && req.auth && req.auth.user) {
|
|
75
|
-
body.userId = req.auth.user._id;
|
|
76
|
-
}
|
|
77
|
-
// Strip pinType if sent by legacy clients
|
|
78
|
-
delete body.pinType;
|
|
79
|
-
|
|
80
|
-
return await new Ipfs(body).save();
|
|
62
|
+
return await new Ipfs(req.body).save();
|
|
81
63
|
},
|
|
82
64
|
|
|
83
65
|
get: async (req, res, options) => {
|
|
84
|
-
/** @type {import('./ipfs.model.js').IpfsModel} */
|
|
85
66
|
const Ipfs = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Ipfs;
|
|
86
|
-
|
|
87
67
|
if (req.params.id) {
|
|
88
|
-
return await Ipfs.findById(req.params.id).select(IpfsDto.select.get())
|
|
68
|
+
return await Ipfs.findById(req.params.id).select(IpfsDto.select.get());
|
|
89
69
|
}
|
|
90
|
-
|
|
91
70
|
const { query, sort, skip, limit, page } = DataQuery.parse(req.query);
|
|
92
|
-
|
|
93
71
|
const [data, total] = await Promise.all([
|
|
94
|
-
Ipfs.find(query)
|
|
95
|
-
.select(IpfsDto.select.get())
|
|
96
|
-
.sort(sort)
|
|
97
|
-
.limit(limit)
|
|
98
|
-
.skip(skip)
|
|
99
|
-
.populate(IpfsDto.populate.user()),
|
|
72
|
+
Ipfs.find(query).select(IpfsDto.select.get()).sort(sort).limit(limit).skip(skip),
|
|
100
73
|
Ipfs.countDocuments(query),
|
|
101
74
|
]);
|
|
102
|
-
|
|
103
75
|
const totalPages = Math.ceil(total / limit);
|
|
104
76
|
return { data, total, page, totalPages };
|
|
105
77
|
},
|
|
106
78
|
|
|
107
79
|
put: async (req, res, options) => {
|
|
108
|
-
/** @type {import('./ipfs.model.js').IpfsModel} */
|
|
109
80
|
const Ipfs = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Ipfs;
|
|
110
|
-
return await Ipfs.findByIdAndUpdate(req.params.id, req.body, {
|
|
81
|
+
return await Ipfs.findByIdAndUpdate(req.params.id, req.body, { returnDocument: 'after' });
|
|
111
82
|
},
|
|
112
83
|
|
|
113
84
|
delete: async (req, res, options) => {
|
|
114
|
-
/** @type {import('./ipfs.model.js').IpfsModel} */
|
|
115
85
|
const Ipfs = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Ipfs;
|
|
116
|
-
|
|
117
86
|
if (req.params.id) {
|
|
118
87
|
const record = await Ipfs.findById(req.params.id);
|
|
119
88
|
if (record) {
|
|
120
|
-
// Remove DB record first, then best-effort unpin
|
|
121
89
|
await Ipfs.findByIdAndDelete(req.params.id);
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
90
|
+
// Only unpin from the node when no other registry entries reference this CID.
|
|
91
|
+
const remaining = await Ipfs.countDocuments({ cid: record.cid });
|
|
92
|
+
if (remaining === 0) {
|
|
93
|
+
try {
|
|
126
94
|
await IpfsClient.unpinCid(record.cid);
|
|
95
|
+
} catch (err) {
|
|
96
|
+
logger.warn(`Failed to unpin CID ${record.cid}: ${err.message}`);
|
|
127
97
|
}
|
|
128
|
-
} catch (err) {
|
|
129
|
-
logger.warn(`Failed to unpin CID ${record.cid} from IPFS node: ${err.message}`);
|
|
130
98
|
}
|
|
131
99
|
return record;
|
|
132
100
|
}
|
|
133
101
|
return null;
|
|
134
102
|
}
|
|
135
|
-
|
|
136
103
|
return await Ipfs.deleteMany();
|
|
137
104
|
},
|
|
138
105
|
|
|
139
106
|
// ──────────────────────────────────────────────
|
|
140
|
-
//
|
|
107
|
+
// Health / audit
|
|
141
108
|
// ──────────────────────────────────────────────
|
|
142
109
|
|
|
143
110
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
111
|
+
* GET /ipfs/verify
|
|
112
|
+
*
|
|
113
|
+
* Iterates every CID in the registry and checks whether it is actually pinned
|
|
114
|
+
* on the connected IPFS node. Returns a summary suitable for admin dashboards
|
|
115
|
+
* and automated alerting.
|
|
116
|
+
*
|
|
117
|
+
* Response shape:
|
|
118
|
+
* { total, pinned, unpinned, errors, entries: [{ cid, resourceType, mfsPath, pinned, error? }] }
|
|
146
119
|
*/
|
|
147
|
-
|
|
148
|
-
const userId = req.body.userId || (req.auth && req.auth.user ? req.auth.user._id : undefined);
|
|
149
|
-
if (!userId) throw new Error('userId is required to create a pin record');
|
|
150
|
-
|
|
151
|
-
const content = typeof req.body.data === 'string' ? req.body.data : JSON.stringify(req.body.data);
|
|
152
|
-
const result = await IpfsClient.addToIpfs(Buffer.from(content, 'utf-8'), req.body.filename || 'data');
|
|
153
|
-
|
|
154
|
-
if (!result) throw new Error('IPFS node is unreachable – content was not pinned');
|
|
155
|
-
|
|
156
|
-
const record = await createPinRecord({
|
|
157
|
-
cid: result.cid,
|
|
158
|
-
userId,
|
|
159
|
-
options,
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
return { cid: result.cid, size: result.size, record };
|
|
163
|
-
},
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* DELETE /ipfs/pin/:cid – unpin a CID and remove the DB record for the current user.
|
|
167
|
-
*/
|
|
168
|
-
unpin: async (req, res, options) => {
|
|
120
|
+
verify: async (req, res, options) => {
|
|
169
121
|
const Ipfs = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Ipfs;
|
|
170
|
-
const
|
|
171
|
-
const cid = req.params.cid || req.params.id;
|
|
122
|
+
const records = await Ipfs.find({}).select(IpfsDto.select.get()).lean();
|
|
172
123
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
124
|
+
let pinned = 0;
|
|
125
|
+
let unpinned = 0;
|
|
126
|
+
let errors = 0;
|
|
127
|
+
const entries = await Promise.all(
|
|
128
|
+
records.map(async (r) => {
|
|
129
|
+
try {
|
|
130
|
+
const isPinned = await IpfsClient.isCidPinned(r.cid);
|
|
131
|
+
if (isPinned) pinned++;
|
|
132
|
+
else unpinned++;
|
|
133
|
+
return { cid: r.cid, resourceType: r.resourceType, mfsPath: r.mfsPath, pinned: isPinned };
|
|
134
|
+
} catch (err) {
|
|
135
|
+
errors++;
|
|
136
|
+
return { cid: r.cid, resourceType: r.resourceType, mfsPath: r.mfsPath, pinned: false, error: err.message };
|
|
137
|
+
}
|
|
138
|
+
}),
|
|
139
|
+
);
|
|
188
140
|
|
|
189
|
-
return {
|
|
141
|
+
return { total: records.length, pinned, unpinned, errors, entries };
|
|
190
142
|
},
|
|
191
143
|
};
|
|
192
144
|
|