V6 initial #507

Merged
Sirherobrine23 merged 6 commits from V6_big_changes into main 2023-02-05 02:50:34 +00:00
29 changed files with 1049 additions and 1972 deletions

21
.github/spigotBuilld/index.mjs vendored Normal file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env node
import { createReadStream, promises as fs } from "node:fs";
import { execFileSync } from "child_process";
import { tmpdir } from "os";
import coreUtils from "@sirherobrine23/coreutils";
import path from "path";
const oracleBucket = await coreUtils.oracleBucket("sa-saopaulo-1", "bdsFiles", "grwodtg32n4d", process.env.OCI_AUTHKEY?.trim());
const __dirname = path.dirname(new URL(import.meta.url).pathname);
let version = process.argv.find(arg => arg.startsWith("--version="))?.split("=")?.[1]?.trim() ?? "latest";
const buildFile = await coreUtils.httpRequestLarge.saveFile("https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar");
execFileSync("java", ["-jar", buildFile, "--rev", version, "-o", __dirname], {
cwd: tmpdir(),
stdio: "inherit"
});
const SpigotFile = (await fs.readdir(__dirname)).find(file => file.endsWith(".jar"));
if (!SpigotFile) throw new Error("No spigot file found");
if (version.trim().toLowerCase() === "latest") version = path.basename(SpigotFile, ".jar").split("-")[1];
await oracleBucket.uploadFile(path.posix.join("SpigotBuild", version+".jar"), createReadStream(path.join(__dirname, SpigotFile)));
await Promise.all((await fs.readdir(__dirname)).filter(file => file.endsWith(".jar")).map(file => fs.unlink(file)));

View File

@ -1,17 +1,16 @@
#!/usr/bin/env node
import coreutils from "@sirherobrine23/coreutils";
import fs from "node:fs/promises";
import { createReadStream } from "node:fs";
import coreutils from "@sirherobrine23/coreutils";
import path from "node:path";
import fs from "node:fs/promises";
if (!process.env.OCI_AUTHKEY) throw new Error("No key auth");
const ociKeyAuth = process.env.OCI_AUTHKEY.trim();
const ociKeyAuth = (process.env.OCI_AUTHKEY||"").trim();
console.log("using key to upload '%s'", ociKeyAuth);
const files = (await coreutils.extendFs.readdirrecursive(path.join(process.cwd(), "phpOutput"))).filter(file => file.endsWith(".tar.gz")||file.endsWith(".zip")||file.endsWith(".tgz"));
const files = (await coreutils.extendFs.readdir({folderPath: path.join(process.cwd(), "phpOutput")})).filter(file => file.endsWith(".tar.gz")||file.endsWith(".zip")||file.endsWith(".tgz"));
await Promise.all(files.map(async file => {
const fileName = path.basename(file);
console.log("Uploading %s", fileName);
// https://docs.oracle.com/en-us/iaas/api/#/en/objectstorage/20160918/Object/PutObject
await coreutils.httpRequest.bufferFetch({
url: `https://objectstorage.sa-saopaulo-1.oraclecloud.com/p/${ociKeyAuth}/n/grwodtg32n4d/b/bdsFiles/o/php_bin/${fileName.toLowerCase()}`,
method: "PUT",

88
.github/workflows/spigotBuild.yaml vendored Normal file
View File

@ -0,0 +1,88 @@
name: Spigot Build
on:
workflow_dispatch:
schedule:
- cron: "0 0 */2 * 0"
push:
# branches:
# - main
# paths:
# - ".github/workflows/spigotBuild.yaml"
# - ".github/spigotBuilld/**/*"
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
version:
- latest
- "1.19.2"
- "1.19.1"
- "1.19"
- "1.18.2"
- "1.18.1"
- "1.18-rc3"
- "1.18-pre8"
- "1.18-pre5"
- "1.18"
- "1.17.1"
- "1.17"
- "1.16.5"
- "1.16.4"
- "1.16.3"
- "1.16.2"
- "1.16.1"
- "1.15.2"
- "1.15.1"
- "1.15"
- "1.14.4"
- "1.14.3-pre4"
- "1.14.3"
- "1.14.2"
- "1.14.1"
- "1.14-pre5"
- "1.14"
- "1.13.2"
- "1.13.1"
- "1.13-pre7"
- "1.13"
- "1.12.2"
- "1.12.1"
- "1.12"
- "1.11.2"
- "1.11.1"
- "1.11"
- "1.10.2"
- "1.10"
- "1.9.4"
- "1.9.2"
- "1.9"
- "1.8.8"
- "1.8.7"
- "1.8.6"
- "1.8.5"
- "1.8.4"
- "1.8.3"
- "1.8"
steps:
- uses: actions/checkout@v3
name: Code checkout
- name: Install ${{ startsWith(matrix.version, 'latest') && '19' || (startsWith(matrix.version, '1.19')||startsWith(matrix.version, '1.18')) && '17' || startsWith(matrix.version, '1.17') && '16' || '8' }} java
uses: actions/setup-java@v3
continue-on-error: true
with:
distribution: liberica
java-version: ${{ (startsWith(matrix.version, 'latest')||startsWith(matrix.version, '1.19')||startsWith(matrix.version, '1.18')) && '17' || startsWith(matrix.version, '1.17') && '16' || '8' }}
- uses: actions/setup-node@v3
name: Setup node.js
with:
node-version: 18.x
- run: npm ci && node .github/spigotBuilld/index.mjs --version=${{ matrix.version || 'latest' }}
continue-on-error: true
env:
OCI_AUTHKEY: "${{ secrets.OCI_AUTHKEY }}"

3
.gitignore vendored
View File

@ -12,3 +12,6 @@ phpOutput/
*.tar.gz
*.tgz
*.zip
# Spigot
*.jar

View File

@ -10,7 +10,7 @@
"**/node_modules/": true,
// Ignore generate tsc files
"**/dist/": true,
"**/src/**/*.js": true,
"**/src/**/*.d.ts": true,
"**/src/**/*.js": false,
"**/src/**/*.d.ts": false,
}
}

557
package-lock.json generated
View File

@ -9,7 +9,7 @@
"version": "5.4.0",
"license": "GPL-3.0",
"dependencies": {
"@sirherobrine23/coreutils": "^2.2.4",
"@sirherobrine23/coreutils": "^2.4.5",
"adm-zip": "^0.5.10",
"compare-versions": "^5.0.3",
"debug": "^4.3.4",
@ -20,13 +20,13 @@
"@types/adm-zip": "^0.5.0",
"@types/debug": "^4.1.7",
"@types/mocha": "^10.0.1",
"@types/node": "^18.11.18",
"@types/node": "^18.11.19",
"@types/tar": "^6.1.3",
"mocha": "^10.2.0",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.1.2",
"typedoc": "^0.23.23",
"typescript": "^4.9.4"
"typedoc": "^0.23.24",
"typescript": "^4.9.5"
},
"engines": {
"node": ">=16.0.0"
@ -153,7 +153,94 @@
"node": ">= 14"
}
},
"node_modules/@octokit/app": {
"version": "13.1.2",
"resolved": "https://registry.npmjs.org/@octokit/app/-/app-13.1.2.tgz",
"integrity": "sha512-Kf+h5sa1SOI33hFsuHvTsWj1jUrjp1x4MuiJBq7U/NicfEGa6nArPUoDnyfP/YTmcQ5cQ5yvOgoIBkbwPg6kzQ==",
"dependencies": {
"@octokit/auth-app": "^4.0.8",
"@octokit/auth-unauthenticated": "^3.0.0",
"@octokit/core": "^4.0.0",
"@octokit/oauth-app": "^4.0.7",
"@octokit/plugin-paginate-rest": "^6.0.0",
"@octokit/types": "^9.0.0",
"@octokit/webhooks": "^10.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/auth-app": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-4.0.9.tgz",
"integrity": "sha512-VFpKIXhHO+kVJtane5cEvdYPtjDKCOI0uKsRrsZfJP+uEu7rcPbQCLCcRKgyT+mUIzGr1IIOmwP/lFqSip1dXA==",
"dependencies": {
"@octokit/auth-oauth-app": "^5.0.0",
"@octokit/auth-oauth-user": "^2.0.0",
"@octokit/request": "^6.0.0",
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^9.0.0",
"@types/lru-cache": "^5.1.0",
"deprecation": "^2.3.1",
"lru-cache": "^6.0.0",
"universal-github-app-jwt": "^1.1.1",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/auth-oauth-app": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-5.0.5.tgz",
"integrity": "sha512-UPX1su6XpseaeLVCi78s9droxpGtBWIgz9XhXAx9VXabksoF0MyI5vaa1zo1njyYt6VaAjFisC2A2Wchcu2WmQ==",
"dependencies": {
"@octokit/auth-oauth-device": "^4.0.0",
"@octokit/auth-oauth-user": "^2.0.0",
"@octokit/request": "^6.0.0",
"@octokit/types": "^9.0.0",
"@types/btoa-lite": "^1.0.0",
"btoa-lite": "^1.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/auth-oauth-device": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-4.0.4.tgz",
"integrity": "sha512-Xl85BZYfqCMv+Uvz33nVVUjE7I/PVySNaK6dRRqlkvYcArSr9vRcZC9KVjXYObGRTCN6mISeYdakAZvWEN4+Jw==",
"dependencies": {
"@octokit/oauth-methods": "^2.0.0",
"@octokit/request": "^6.0.0",
"@octokit/types": "^9.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/auth-oauth-user": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-2.1.1.tgz",
"integrity": "sha512-JgqnNNPf9CaWLxWm9uh2WgxcaVYhxBR09NVIPTiMU2dVZ3FObOHs3njBiLNw+zq84k+rEdm5Y7AsiASrZ84Apg==",
"dependencies": {
"@octokit/auth-oauth-device": "^4.0.0",
"@octokit/oauth-methods": "^2.0.0",
"@octokit/request": "^6.0.0",
"@octokit/types": "^9.0.0",
"btoa-lite": "^1.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/auth-token": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.3.tgz",
"integrity": "sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.3.tgz",
"integrity": "sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA==",
@ -164,6 +251,22 @@
"node": ">= 14"
}
},
"node_modules/@octokit/auth-unauthenticated": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@octokit/auth-unauthenticated/-/auth-unauthenticated-3.0.4.tgz",
"integrity": "sha512-AT74XGBylcLr4lmUp1s6mjSUgphGdlse21Qjtv5DzpX1YOl5FXKwvNcZWESdhyBbpDT8VkVyLFqa/7a7eqpPNw==",
"dependencies": {
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^9.0.0"
},
"engines": {
"node": ">= 14"
"@octokit/types": "^9.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/auth-unauthenticated": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@octokit/auth-unauthenticated/-/auth-unauthenticated-3.0.4.tgz",
@ -177,10 +280,18 @@
}
},
"node_modules/@octokit/core": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.0.tgz",
"integrity": "sha512-AgvDRUg3COpR82P7PBdGZF/NNqGmtMq2NiPqeSsDIeCfYFOZ9gddqWNQHnFdEUf+YwOj4aZYmJnlPp7OXmDIDg==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.0.tgz",
"integrity": "sha512-AgvDRUg3COpR82P7PBdGZF/NNqGmtMq2NiPqeSsDIeCfYFOZ9gddqWNQHnFdEUf+YwOj4aZYmJnlPp7OXmDIDg==",
"dependencies": {
"@octokit/auth-token": "^3.0.0",
"@octokit/graphql": "^5.0.0",
"@octokit/request": "^6.0.0",
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^9.0.0",
"@octokit/auth-token": "^3.0.0",
"@octokit/graphql": "^5.0.0",
"@octokit/request": "^6.0.0",
@ -189,28 +300,43 @@
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/endpoint": {
"version": "7.0.5",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.5.tgz",
"integrity": "sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==",
"version": "7.0.5",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.5.tgz",
"integrity": "sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==",
"dependencies": {
"@octokit/types": "^9.0.0",
"@octokit/types": "^9.0.0",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/graphql": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.5.tgz",
"integrity": "sha512-Qwfvh3xdqKtIznjX9lz2D458r7dJPP8l6r4GQkIdWQouZwHQK0mVT88uwiU2bdTU2OtT1uOlKpRciUWldpG0yQ==",
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.5.tgz",
"integrity": "sha512-Qwfvh3xdqKtIznjX9lz2D458r7dJPP8l6r4GQkIdWQouZwHQK0mVT88uwiU2bdTU2OtT1uOlKpRciUWldpG0yQ==",
"dependencies": {
"@octokit/request": "^6.0.0",
"@octokit/types": "^9.0.0",
"@octokit/request": "^6.0.0",
"@octokit/types": "^9.0.0",
"universal-user-agent": "^6.0.0"
@ -246,6 +372,51 @@
"node": ">= 14"
}
},
"node_modules/@octokit/oauth-methods": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-2.0.5.tgz",
"integrity": "sha512-yQP6B5gE3axNxuM3U9KqWs/ErAQ+WLPaPgC/7EjsZsQibkf8sjdAfF8/y/EJW+Dd05XQvadX4WhQZPMnO1SE1A==",
"dependencies": {
"@octokit/oauth-authorization-url": "^5.0.0",
"@octokit/request": "^6.2.3",
"@octokit/request-error": "^3.0.3",
"@octokit/types": "^9.0.0",
"btoa-lite": "^1.0.0"
},
"engines": {
"node": ">= 14"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/oauth-app": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@octokit/oauth-app/-/oauth-app-4.2.0.tgz",
"integrity": "sha512-gyGclT77RQMkVUEW3YBeAKY+LBSc5u3eC9Wn/Uwt3WhuKuu9mrV18EnNpDqmeNll+mdV02yyBROU29Tlili6gg==",
"dependencies": {
"@octokit/auth-oauth-app": "^5.0.0",
"@octokit/auth-oauth-user": "^2.0.0",
"@octokit/auth-unauthenticated": "^3.0.0",
"@octokit/core": "^4.0.0",
"@octokit/oauth-authorization-url": "^5.0.0",
"@octokit/oauth-methods": "^2.0.0",
"@types/aws-lambda": "^8.10.83",
"fromentries": "^1.3.1",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/oauth-authorization-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-5.0.0.tgz",
"integrity": "sha512-y1WhN+ERDZTh0qZ4SR+zotgsQUE1ysKnvBt1hvDRB2WRzYtVKQjn97HEPzoehh66Fj9LwNdlZh+p6TJatT0zzg==",
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/oauth-methods": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-2.0.5.tgz",
@ -265,32 +436,50 @@
"version": "16.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-16.0.0.tgz",
"integrity": "sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA=="
"version": "16.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-16.0.0.tgz",
"integrity": "sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA=="
},
"node_modules/@octokit/plugin-paginate-rest": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.0.0.tgz",
"integrity": "sha512-Sq5VU1PfT6/JyuXPyt04KZNVsFOSBaYOAq2QRZUwzVlI10KFvcbUo8lR258AAQL1Et60b0WuVik+zOWKLuDZxw==",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.0.0.tgz",
"integrity": "sha512-Sq5VU1PfT6/JyuXPyt04KZNVsFOSBaYOAq2QRZUwzVlI10KFvcbUo8lR258AAQL1Et60b0WuVik+zOWKLuDZxw==",
"dependencies": {
"@octokit/types": "^9.0.0"
},
"engines": {
"node": ">= 14"
"@octokit/types": "^9.0.0"
},
"engines": {
"node": ">= 14"
},
"peerDependencies": {
"@octokit/core": ">=4"
"@octokit/core": ">=4"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.0.1.tgz",
"integrity": "sha512-pnCaLwZBudK5xCdrR823xHGNgqOzRnJ/mpC/76YPpNP7DybdsJtP7mdOwh+wYZxK5jqeQuhu59ogMI4NRlBUvA==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.0.1.tgz",
"integrity": "sha512-pnCaLwZBudK5xCdrR823xHGNgqOzRnJ/mpC/76YPpNP7DybdsJtP7mdOwh+wYZxK5jqeQuhu59ogMI4NRlBUvA==",
"dependencies": {
"@octokit/types": "^9.0.0",
"@octokit/types": "^9.0.0",
"deprecation": "^2.3.1"
},
"engines": {
"node": ">= 14"
},
"engines": {
"node": ">= 14"
},
"peerDependencies": {
"@octokit/core": ">=3"
}
@ -325,11 +514,47 @@
"@octokit/core": "^4.0.0"
}
},
"node_modules/@octokit/plugin-retry": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-4.1.1.tgz",
"integrity": "sha512-iR7rg5KRSl6L6RELTQQ3CYeNgeBJyuAmP95odzcQ/zyefnRT/Peo8rWeky4z7V/+/oPWqOL4I5Z+V8KtjpHCJw==",
"dependencies": {
"@octokit/types": "^9.0.0",
"bottleneck": "^2.15.3"
},
"engines": {
"node": ">= 14"
},
"peerDependencies": {
"@octokit/core": ">=3"
}
},
"node_modules/@octokit/plugin-throttling": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-5.0.1.tgz",
"integrity": "sha512-I4qxs7wYvYlFuY3PAUGWAVPhFXG3RwnvTiSr5Fu/Auz7bYhDLnzS2MjwV8nGLq/FPrWwYiweeZrI5yjs1YG4tQ==",
"dependencies": {
"@octokit/types": "^9.0.0",
"bottleneck": "^2.15.3"
},
"engines": {
"node": ">= 14"
},
"peerDependencies": {
"@octokit/core": "^4.0.0"
}
},
"node_modules/@octokit/request": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.3.tgz",
"integrity": "sha512-TNAodj5yNzrrZ/VxP+H5HiYaZep0H3GU0O7PaF+fhDrt8FPrnkei9Aal/txsN/1P7V3CPiThG0tIvpPDYUsyAA==",
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.3.tgz",
"integrity": "sha512-TNAodj5yNzrrZ/VxP+H5HiYaZep0H3GU0O7PaF+fhDrt8FPrnkei9Aal/txsN/1P7V3CPiThG0tIvpPDYUsyAA==",
"dependencies": {
"@octokit/endpoint": "^7.0.0",
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^9.0.0",
"@octokit/endpoint": "^7.0.0",
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^9.0.0",
@ -337,29 +562,43 @@
"node-fetch": "^2.6.7",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/request-error": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz",
"integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz",
"integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==",
"dependencies": {
"@octokit/types": "^9.0.0",
"@octokit/types": "^9.0.0",
"deprecation": "^2.0.0",
"once": "^1.4.0"
},
"engines": {
"node": ">= 14"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/types": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.0.0.tgz",
"integrity": "sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==",
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.0.0.tgz",
"integrity": "sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==",
"dependencies": {
"@octokit/openapi-types": "^16.0.0"
"@octokit/openapi-types": "^16.0.0"
}
},
"node_modules/@octokit/webhooks": {
@ -389,6 +628,33 @@
"resolved": "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-6.10.0.tgz",
"integrity": "sha512-lDNv83BeEyxxukdQ0UttiUXawk9+6DkdjjFtm2GFED+24IQhTVaoSbwV9vWWKONyGLzRmCQqZmoEWkDhkEmPlw=="
},
"node_modules/@octokit/webhooks": {
"version": "10.7.0",
"resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-10.7.0.tgz",
"integrity": "sha512-zZBbQMpXXnK/ki/utrFG/TuWv9545XCSLibfDTxrYqR1PmU6zel02ebTOrA7t5XIGHzlEOc/NgISUIBUe7pMFA==",
"dependencies": {
"@octokit/request-error": "^3.0.0",
"@octokit/webhooks-methods": "^3.0.0",
"@octokit/webhooks-types": "6.10.0",
"aggregate-error": "^3.1.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/webhooks-methods": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-3.0.2.tgz",
"integrity": "sha512-Vlnv5WBscf07tyAvfDbp7pTkMZUwk7z7VwEF32x6HqI+55QRwBTcT+D7DDjZXtad/1dU9E32x0HmtDlF9VIRaQ==",
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/webhooks-types": {
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-6.10.0.tgz",
"integrity": "sha512-lDNv83BeEyxxukdQ0UttiUXawk9+6DkdjjFtm2GFED+24IQhTVaoSbwV9vWWKONyGLzRmCQqZmoEWkDhkEmPlw=="
},
"node_modules/@sindresorhus/is": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz",
@ -401,6 +667,9 @@
}
},
"node_modules/@sirherobrine23/coreutils": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/@sirherobrine23/coreutils/-/coreutils-2.4.5.tgz",
"integrity": "sha512-9Fe97Fm3IcK2nFPnDw6vtPoMAWFeC995IhNUr6Zxe3YyvD25DEeIwPAapQTewCUtQEkkk3xyGccZ3mT5ECnP1g==",
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/@sirherobrine23/coreutils/-/coreutils-2.4.5.tgz",
"integrity": "sha512-9Fe97Fm3IcK2nFPnDw6vtPoMAWFeC995IhNUr6Zxe3YyvD25DEeIwPAapQTewCUtQEkkk3xyGccZ3mT5ECnP1g==",
@ -414,6 +683,10 @@
"stream-json": "^1.7.5",
"tar": "^6.1.13",
"yaml": "^2.2.1"
"octokit": "^2.0.11",
"stream-json": "^1.7.5",
"tar": "^6.1.13",
"yaml": "^2.2.1"
}
},
"node_modules/@szmarczak/http-timer": {
@ -478,6 +751,16 @@
"resolved": "https://registry.npmjs.org/@types/btoa-lite/-/btoa-lite-1.0.0.tgz",
"integrity": "sha512-wJsiX1tosQ+J5+bY5LrSahHxr2wT+uME5UDwdN1kg4frt40euqA+wzECkmq4t5QbveHiJepfdThgQrPw6KiSlg=="
},
"node_modules/@types/aws-lambda": {
"version": "8.10.110",
"resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.110.tgz",
"integrity": "sha512-r6egf2Cwv/JaFTTrF9OXFVUB3j/SXTgM9BwrlbBRjWAa2Tu6GWoDoLflppAZ8uSfbUJdXvC7Br3DjuN9pQ2NUQ=="
},
"node_modules/@types/btoa-lite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/btoa-lite/-/btoa-lite-1.0.0.tgz",
"integrity": "sha512-wJsiX1tosQ+J5+bY5LrSahHxr2wT+uME5UDwdN1kg4frt40euqA+wzECkmq4t5QbveHiJepfdThgQrPw6KiSlg=="
},
"node_modules/@types/debug": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz",
@ -505,6 +788,19 @@
"resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw=="
},
"node_modules/@types/jsonwebtoken": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz",
"integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw=="
},
"node_modules/@types/mocha": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz",
@ -518,9 +814,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "18.11.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
"integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA=="
"version": "18.11.19",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.19.tgz",
"integrity": "sha512-YUgMWAQBWLObABqrvx8qKO1enAvBUdjZOAWQ5grBAkp5LQv45jBvYKZ3oFS9iKRCQyFjqw6iuEa1vmFqtxYLZw=="
},
"node_modules/@types/tar": {
"version": "6.1.3",
@ -538,9 +834,9 @@
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA=="
},
"node_modules/acorn": {
"version": "8.8.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
"bin": {
"acorn": "bin/acorn"
},
@ -596,6 +892,18 @@
"node": ">=8"
}
},
"node_modules/aggregate-error": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
"integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
"dependencies": {
"clean-stack": "^2.0.0",
"indent-string": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@ -734,6 +1042,11 @@
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
"integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="
},
"node_modules/bottleneck": {
"version": "2.19.5",
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
"integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="
},
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
@ -766,6 +1079,11 @@
"resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz",
"integrity": "sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA=="
},
"node_modules/btoa-lite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz",
"integrity": "sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA=="
},
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
@ -780,9 +1098,9 @@
}
},
"node_modules/cacheable-request": {
"version": "10.2.5",
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.5.tgz",
"integrity": "sha512-5RwYYCfzjNPsyJxb/QpaM0bfzx+kw5/YpDhZPm9oMIDntHFQ9YXeyV47ZvzlTE0XrrrbyO2UITJH4GF9eRLdXQ==",
"version": "10.2.6",
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.6.tgz",
"integrity": "sha512-fhVLoXIFHvTizxQkAVohKPToSzdwzjrhL5SsjHT0umeSCxWeqJOS0oPqHg+yO1FPFST3VE5rxaqUvseyH9JHtg==",
"dependencies": {
"@types/http-cache-semantics": "^4.0.1",
"get-stream": "^6.0.1",
@ -891,6 +1209,14 @@
"node": ">=6"
}
},
"node_modules/clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
"engines": {
"node": ">=6"
}
},
"node_modules/cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@ -1283,6 +1609,25 @@
}
]
},
"node_modules/fromentries": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
"integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/fs-minipass": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
@ -1355,9 +1700,9 @@
}
},
"node_modules/get-intrinsic": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
"integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
"integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
"dependencies": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
@ -1582,9 +1927,9 @@
}
},
"node_modules/http-cache-semantics": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ=="
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
},
"node_modules/http-proxy-agent": {
"version": "5.0.0",
@ -1642,6 +1987,14 @@
"node": ">=8"
}
},
"node_modules/indent-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
"engines": {
"node": ">=8"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@ -1879,6 +2232,40 @@
"safe-buffer": "^5.0.1"
}
},
"node_modules/jsonwebtoken": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
"integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
"dependencies": {
"jws": "^3.2.2",
"lodash": "^4.17.21",
"ms": "^2.1.1",
"semver": "^7.3.8"
},
"engines": {
"node": ">=12",
"npm": ">=6"
}
},
"node_modules/jsonwebtoken/node_modules/jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"dependencies": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jsonwebtoken/node_modules/jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"dependencies": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jwa": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
@ -1938,6 +2325,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
@ -2016,9 +2408,9 @@
"dev": true
},
"node_modules/marked": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz",
"integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==",
"version": "4.2.12",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
"integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==",
"dev": true,
"bin": {
"marked": "bin/marked.js"
@ -2181,9 +2573,9 @@
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
},
"node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
"integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
@ -2262,9 +2654,9 @@
"integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw=="
},
"node_modules/object-inspect": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
"integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
"version": "1.12.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@ -2287,6 +2679,24 @@
"node": ">= 14"
}
},
"node_modules/octokit": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/octokit/-/octokit-2.0.14.tgz",
"integrity": "sha512-z6cgZBFxirpFEQ1La8Lg83GCs5hOV2EPpkYYdjsGNbfQMv8qUGjq294MiRBCbZqLufviakGsPUxaNKe3JrPmsA==",
"dependencies": {
"@octokit/app": "^13.1.1",
"@octokit/core": "^4.0.4",
"@octokit/oauth-app": "^4.0.6",
"@octokit/plugin-paginate-rest": "^6.0.0",
"@octokit/plugin-rest-endpoint-methods": "^7.0.0",
"@octokit/plugin-retry": "^4.0.3",
"@octokit/plugin-throttling": "^5.0.0",
"@octokit/types": "^9.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@ -2437,9 +2847,9 @@
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
},
"node_modules/punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
"engines": {
"node": ">=6"
}
@ -2590,6 +3000,20 @@
"node": ">=10"
}
},
"node_modules/semver": {
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
@ -2600,6 +3024,9 @@
}
},
"node_modules/shiki": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.12.1.tgz",
"integrity": "sha512-aieaV1m349rZINEBkjxh2QbBvFFQOlgqYTNtCal82hHj4dDZ76oMlQIX+C7ryerBTDiga3e5NfH6smjdJ02BbQ==",
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.12.1.tgz",
"integrity": "sha512-aieaV1m349rZINEBkjxh2QbBvFFQOlgqYTNtCal82hHj4dDZ76oMlQIX+C7ryerBTDiga3e5NfH6smjdJ02BbQ==",
@ -2608,6 +3035,9 @@
"jsonc-parser": "^3.2.0",
"vscode-oniguruma": "^1.7.0",
"vscode-textmate": "^8.0.0"
"jsonc-parser": "^3.2.0",
"vscode-oniguruma": "^1.7.0",
"vscode-textmate": "^8.0.0"
}
},
"node_modules/side-channel": {
@ -2645,6 +3075,19 @@
"stream-chain": "^2.2.5"
}
},
"node_modules/stream-chain": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz",
"integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA=="
},
"node_modules/stream-json": {
"version": "1.7.5",
"resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.7.5.tgz",
"integrity": "sha512-NSkoVduGakxZ8a+pTPUlcGEeAGQpWL9rKJhOFCV+J/QtdQUEU5vtBgVg6eJXn8JB8RZvpbJWZGvXkhz70MLWoA==",
"dependencies": {
"stream-chain": "^2.2.5"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@ -2737,12 +3180,9 @@
}
},
"node_modules/tar/node_modules/minipass": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz",
"integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==",
"dependencies": {
"yallist": "^4.0.0"
},
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.1.tgz",
"integrity": "sha512-V9esFpNbK0arbN3fm2sxDKqMYgIp7XtVdE4Esj+PE4Qaaxdg1wIw48ITQIOn1sc8xXSmUviVL3cyjMqPlrVkiA==",
"engines": {
"node": ">=8"
}
@ -2862,6 +3302,9 @@
}
},
"node_modules/typedoc": {
"version": "0.23.24",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.24.tgz",
"integrity": "sha512-bfmy8lNQh+WrPYcJbtjQ6JEEsVl/ce1ZIXyXhyW+a1vFrjO39t6J8sL/d6FfAGrJTc7McCXgk9AanYBSNvLdIA==",
"version": "0.23.24",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.24.tgz",
"integrity": "sha512-bfmy8lNQh+WrPYcJbtjQ6JEEsVl/ce1ZIXyXhyW+a1vFrjO39t6J8sL/d6FfAGrJTc7McCXgk9AanYBSNvLdIA==",
@ -2871,6 +3314,9 @@
"marked": "^4.2.5",
"minimatch": "^5.1.2",
"shiki": "^0.12.1"
"marked": "^4.2.5",
"minimatch": "^5.1.2",
"shiki": "^0.12.1"
},
"bin": {
"typedoc": "bin/typedoc"
@ -2883,9 +3329,9 @@
}
},
"node_modules/typedoc/node_modules/minimatch": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz",
"integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==",
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
@ -2895,6 +3341,9 @@
}
},
"node_modules/typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
@ -2916,6 +3365,15 @@
"jsonwebtoken": "^9.0.0"
}
},
"node_modules/universal-github-app-jwt": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-1.1.1.tgz",
"integrity": "sha512-G33RTLrIBMFmlDV4u4CBF7dh71eWwykck4XgaxaIVeZKOYZRAAxvcGMRFTUclVY6xoUPQvO4Ne5wKGxYm/Yy9w==",
"dependencies": {
"@types/jsonwebtoken": "^9.0.0",
"jsonwebtoken": "^9.0.0"
}
},
"node_modules/universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
@ -2977,6 +3435,9 @@
"dev": true
},
"node_modules/vscode-textmate": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
"integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
"integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
@ -3069,15 +3530,15 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/ws": {
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz",
"integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
@ -3123,6 +3584,14 @@
"node": ">= 14"
}
},
"node_modules/yaml": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz",
"integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==",
"engines": {
"node": ">= 14"
}
},
"node_modules/yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",

View File

@ -30,7 +30,7 @@
"node": ">=16.0.0"
},
"dependencies": {
"@sirherobrine23/coreutils": "^2.2.4",
"@sirherobrine23/coreutils": "^2.4.5",
"adm-zip": "^0.5.10",
"compare-versions": "^5.0.3",
"debug": "^4.3.4",
@ -41,12 +41,12 @@
"@types/adm-zip": "^0.5.0",
"@types/debug": "^4.1.7",
"@types/mocha": "^10.0.1",
"@types/node": "^18.11.18",
"@types/node": "^18.11.19",
"@types/tar": "^6.1.3",
"mocha": "^10.2.0",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.1.2",
"typedoc": "^0.23.23",
"typescript": "^4.9.4"
"typedoc": "^0.23.24",
"typescript": "^4.9.5"
}
}

View File

@ -1,15 +0,0 @@
import * as Bedrock from "./bedrock.js";
if (!(process.platform === "win32"||process.platform === "linux")) console.log("Bedrock disabled to %s, avaible only to Windows and Linux");
else {
describe("Bedrock", async function() {
this.timeout(Infinity);
let id: string;
it("Install and Start", async () => {
id = (await Bedrock.installServer({version: "latest", platformOptions: {newId: true}})).id as string
const serverManeger = await Bedrock.startServer({id});
serverManeger.events.once("serverStarted", () => serverManeger.stopServer());
return serverManeger.waitExit();
});
});
}

View File

@ -1,14 +0,0 @@
import * as java from "./java.js";
describe("Java", function() {
this.timeout(Infinity);
let id: string;
it("Install and Start", async () => {
id = (await java.installServer("latest", {newId: true})).id as string
const serverManeger = await java.startServer({
platformOptions: {id}
});
serverManeger.events.once("serverStarted", () => serverManeger.stopServer());
return serverManeger.waitExit();
});
});

View File

@ -1,12 +0,0 @@
import {installServer, startServer} from "./paper.js";
describe("PaperMC", function() {
this.timeout(Infinity);
let id: string;
it("Install and Start", async () => {
id = (await installServer("latest", {newId: true})).id as string
const serverManeger = await startServer({platformOptions: {id}});
serverManeger.events.once("serverStarted", () => serverManeger.stopServer());
return serverManeger.waitExit();
});
});

View File

@ -1,12 +0,0 @@
import { installServer, startServer } from "./pocketmine.js";
describe("Pocketmine", function() {
this.timeout(Infinity);
let id: string;
it("Install and Start", async () => {
id = (await installServer("latest", {newId: true})).id as string
const serverManeger = await startServer({id});
serverManeger.events.once("serverStarted", () => serverManeger.stopServer());
return serverManeger.waitExit();
});
});

View File

@ -1,12 +0,0 @@
import { installServer, startServer } from "./pwnuukit.js";
describe("Powernukkit", function() {
this.timeout(Infinity);
let id: string;
it("Install and Start", async () => {
id = (await installServer("latest", {newId: true})).id as string
const serverManeger = await startServer({platformOptions: {id}});
serverManeger.events.once("serverStarted", () => serverManeger.stopServer());
return serverManeger.waitExit();
});
});

View File

@ -1,12 +0,0 @@
import * as spigot from "./spigot.js";
describe("Spigot", function (){
this.timeout(Infinity);
let id: string;
it("Install and Start", async () => {
id = (await spigot.installServer("latest", {newId: true})).id as string
const serverManeger = await spigot.startServer({platformOptions: {id}});
serverManeger.events.once("serverStarted", () => serverManeger.stopServer());
return serverManeger.waitExit();
});
});

View File

@ -1,348 +0,0 @@
import { manegerConfigProprieties } from "../configManipulate.js";
import { randomPort } from "../lib/randomPort.js";
import { pathControl, bdsPlatformOptions } from "../platformPathManeger.js";
import * as globalPlatfroms from "../globalPlatfroms.js";
import coreUtils from "@sirherobrine23/coreutils";
import path from "node:path";
import fsOld from "node:fs";
import fs from "node:fs/promises";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// RegExp
const portListen = /\[.*\]\s+(IPv[46])\s+supported,\s+port:\s+([0-9]+)/;
const started = /\[.*\]\s+Server\s+started\./;
const playerActionsV1 = /\[.*\]\s+Player\s+((dis|)connected):\s+(.*),\s+xuid:\s+([0-9]+)/;
const newPlayerActions = /\[.*INFO\]\s+Player\s+(Spawned|connected|disconnected):\s+([\s\S\w]+)\s+(xuid:\s+([0-9]+))?/;
const fileSave = /^(worlds|server\.properties|((permissions|allowlist)\.json))$/;
type bedrockVersionJSON = {
version: string,
date: Date,
release?: "stable"|"preview",
url: {
[platform in NodeJS.Platform]?: {
[arch in NodeJS.Architecture]?: string
}
}
};
export type installOptions = {
version: string|boolean,
release?: bedrockVersionJSON["release"],
platformOptions?: bdsPlatformOptions,
generateRandomPorts?: boolean
};
const emulaterSoftwares = [
"qemu-x86_64-static",
"qemu-x86_64",
"box64"
];
export async function installServer(installOptions: installOptions) {
if ((["android", "linux"]).includes(process.platform) && process.arch !== "x64") {
let emitThrow = true;
for (const emu of emulaterSoftwares) if (await coreUtils.childPromisses.commandExists(emu)) {emitThrow = false; break;}
if (emitThrow) throw new Error("Cannot emulate x64 architecture. Check the documentents in \"https://github.com/core/wiki/Server-Platforms#minecraft-bedrock-server-alpha\"");
}
const folderControl = await pathControl("bedrock", installOptions?.platformOptions||{id: "default"});
const allVersions = await coreUtils.httpRequest.getJSON<bedrockVersionJSON[]>("https://the-bds-maneger.github.io/BedrockFetch/all.json");
const bedrockData = ((typeof installOptions?.version === "boolean")||(installOptions?.version?.trim()?.toLowerCase() === "latest")) ? allVersions.at(-1) : allVersions.find(rel => ((rel.release||"stable") !== (installOptions?.release||"stable")) && (rel.version === installOptions.version));
let platform = process.platform;
if (platform === "android") platform = "linux";
let url = bedrockData?.url[platform]?.[process.arch];
if (!url) throw new Error("No url to current os platform");
// Remover files
const files = await fs.readdir(folderControl.serverPath);
await Promise.all(files.filter(file => !fileSave.test(file)).map(file => fs.rm(path.join(folderControl.serverPath, file), {recursive: true, force: true})));
const backups = await Promise.all(files.filter(file => fileSave.test(file)).map(async file => fs.lstat(path.join(folderControl.serverPath, file)).then(res => res.isFile()?fs.readFile(path.join(folderControl.serverPath, file)).then(data => ({data, file: path.join(folderControl.serverPath, file)})).catch(() => null):null)))
// Extract file
await coreUtils.httpRequestLarge.extractZip({url, folderTarget: folderControl.serverPath});
await fs.writeFile(path.join(folderControl.serverRoot, "version_installed.json"), JSON.stringify({version: bedrockData.version, date: bedrockData.date, installDate: new Date()}));
// Restore files
if (backups.length > 0) await Promise.all(backups.filter(file => file !== null).map(({data, file}) => fs.writeFile(file, data).catch(() => null)));
if (installOptions?.generateRandomPorts||folderControl.platformIDs.length > 2) {
let v4: number, v6: number;
const platformPorts = (await Promise.all(folderControl.platformIDs.map(async id =>(await serverConfig({id})).getConfig()))).map(config => ({v4: config["server-port"], v6: config["server-portv6"]}));
while (!v4||!v6) {
const tmpNumber = await randomPort();
if (platformPorts.some(ports => ports.v4 === tmpNumber||ports.v6 == tmpNumber)) continue;
if (!v4) v4 = tmpNumber;
else v6 = tmpNumber;
};
await (await serverConfig({id: folderControl.id})).editConfig({name: "serverPort", data: v4}).editConfig({name: "serverPortv6", data: v6}).save()
}
return {
id: folderControl.id,
url: url,
version: bedrockData.version,
date: bedrockData.date
};
}
export async function startServer(platformOptions: bdsPlatformOptions = {id: "default"}) {
const { serverPath, logsPath, id } = await pathControl("bedrock", platformOptions);
if (!fsOld.existsSync(path.join(serverPath, "bedrock_server"+(process.platform==="win32"?".exe":"")))) throw new Error("Install server fist");
const args: string[] = [];
let command = path.join(serverPath, "bedrock_server");
if ((["android", "linux"]).includes(process.platform) && process.arch !== "x64") {
args.push(command);
let emitThrow = true;
for (const emu of emulaterSoftwares) if (await coreUtils.childPromisses.commandExists(emu)) {
emitThrow = false;
command = emu;
break;
}
if (emitThrow) throw new Error("Cannot emulate x64 architecture. Check the documentents in \"https://github.com/core/wiki/Server-Platforms#minecraft-bedrock-server-alpha\"");
}
const backendStart = new Date(), logFileOut = path.join(logsPath, `${backendStart.getTime()}_${process.platform}_${process.arch}.log`);
const serverConfig: globalPlatfroms.actionsV2 = {
serverStarted(data, done) {
if (started.test(data)) done({
onAvaible: new Date(),
timePassed: Date.now() - backendStart.getTime()
});
},
portListening(data, done) {
if (!portListen.test(data)) return;
const [, protocol, port] = data.match(portListen);
done({
type: "UDP",
port: parseInt(port),
host: protocol?.trim() === "IPv4" ? "127.0.0.1" : protocol?.trim() === "IPv6" ? "[::]" : "Unknown",
protocol: protocol?.trim() === "IPv4" ? "IPv4" : protocol?.trim() === "IPv6" ? "IPv6" : "Unknown"
});
},
playerAction(data, Callbacks) {
const connectTime = new Date();
if (!(newPlayerActions.test(data)||playerActionsV1.test(data))) return;
let playerName: string, action: string, xuid: string;
if (newPlayerActions.test(data)) {
const [, actionV2,, playerNameV2,, xuidV2] = data.match(newPlayerActions);
playerName = playerNameV2;
action = actionV2;
xuid = xuidV2;
} else {
const [, actionV1,, playerNameV1, xuidV1] = data.match(newPlayerActions);
playerName = playerNameV1;
action = actionV1;
xuid = xuidV1;
}
const playerData: globalPlatfroms.playerBase = {connectTime, playerName, xuid};
if (action === "connect") Callbacks.connect(playerData);
else if (action === "disconnect") Callbacks.disconnect(playerData);
else if (action === "Spawned") Callbacks.spawn(playerData);
else Callbacks.unknown({...playerData, lineString: data});
},
stopServer(components) {
components.actions.runCommand("stop");
return components.actions.waitExit();
},
playerTp(actions, playerName, x, y, z) {
if (!/".*"/.test(playerName) && playerName.includes(" ")) playerName = `"${playerName}"`;
actions.runCommand("tp", playerName, x, y, z);
},
};
return globalPlatfroms.actionV2({
id,
platform: "bedrock",
processConfig: {command, args, options: {cwd: serverPath, maxBuffer: Infinity, env: {LD_LIBRARY_PATH: process.platform === "win32"?undefined:serverPath}, logPath: {stdout: logFileOut}}},
hooks: serverConfig
});
}
export type editConfig =
{name: "serverName", data: string}|
{name: "gamemode", data: "survival"|"creative"|"adventure"}|
{name: "forceGamemode", data: boolean}|
{name: "difficulty", data: "peaceful"|"easy"|"normal"|"hard"}|
{name: "allowCheats", data: boolean}|
{name: "maxPlayers", data: number}|
{name: "onlineMode", data: boolean}|
{name: "allowList", data: boolean}|
{name: "serverPort", data: number}|
{name: "serverPortv6", data: number}|
{name: "viewDistance", data: number}|
{name: "tickDistance", data: "4"|"6"|"8"|"10"|"12"}|
{name: "playerIdleTimeout", data: number}|
{name: "maxThreads", data: number}|
{name: "levelName", data: string}|
{name: "levelSeed", data?: string}|
{name: "levelType", data?: "FLAT"|"LEGACY"|"DEFAULT"}|
{name: "defaultPlayerPermissionLevel", data: "visitor"|"member"|"operator"}|
{name: "texturepackRequired", data: boolean}|
{name: "chatRestriction", data: "None"|"Dropped"|"Disabled"}|
{name: "mojangTelemetry", data: boolean};
export type bedrockConfig = {
"server-name": string,
"gamemode": "survival"|"creative"|"adventure",
"force-gamemode": boolean,
"difficulty": "peaceful"|"easy"|"normal"|"hard",
"allow-cheats": boolean,
"max-players": number,
"online-mode": true,
"allow-list": boolean,
"server-port": number,
"server-portv6": number,
"view-distance": number,
"tick-distance": "4"|"6"|"8"|"10"|"12",
"player-idle-timeout": number,
"max-threads": number,
"level-name": string,
"level-seed": any,
"default-player-permission-level": "visitor"|"member"|"operator",
"texturepack-required": boolean,
"content-log-file-enabled": boolean,
"compression-threshold": number,
"server-authoritative-movement": string,
"player-movement-score-threshold": number,
"player-movement-action-direction-threshold": number,
"player-movement-distance-threshold": number,
"player-movement-duration-threshold-in-ms": number,
"correct-player-movement": boolean,
"server-authoritative-block-breaking": boolean,
"chat-restriction": "None"|"Dropped"|"Disabled",
"disable-player-interaction": boolean,
"emit-server-telemetry"?: boolean
}
export async function serverConfig(platformOptions: bdsPlatformOptions = {id: "default"}) {
const { serverPath } = await pathControl("bedrock", platformOptions);
const fileProperties = path.join(serverPath, "server.properties");
if (!await coreUtils.extendFs.exists(fileProperties)) await fs.cp(path.join(__dirname, "../configs/java/server.properties"), fileProperties);
return manegerConfigProprieties<editConfig, bedrockConfig>({
configPath: fileProperties,
configManipulate: {
serverName: {
regexReplace: /server-name=.*/,
valueFormat: "server-name=%s"
},
gamemode: {
regexReplace: /gamemode=(survival|creative|adventure)/,
valueFormat: "gamemode=%s"
},
forceGamemode: {
regexReplace: /force-gamemode=(true|false)/,
valueFormat: "force-gamemode=%s"
},
difficulty: {
regexReplace: /difficulty=(peaceful|easy|normal|hard)/,
valueFormat: "difficulty=%s"
},
allowCheats: {
regexReplace: /allow-cheats=(false|true)/,
valueFormat: "allow-cheats=%s"
},
maxPlayers: {
regexReplace: /max-players=[0-9]+/,
valueFormat: "max-players=%s"
},
onlineMode: {
regexReplace: /online-mode=(true|false)/,
valueFormat: "online-mode=%s"
},
allowList: {
regexReplace: /allow-list=(false|true)/,
valueFormat: "allow-list=%s"
},
tickDistance: {
regexReplace: /tick-distance=(4|6|8|10|12)/,
valueFormat: "tick-distance=%f",
validate(value: number) {return ([4,6,8,10,12]).includes(value);}
},
playerIdleTimeout: {
regexReplace: /player-idle-timeout=[0-9]+/,
valueFormat: "player-idle-timeout=%f"
},
maxThreads: {
regexReplace: /max-threads=[0-9]+/,
valueFormat: "max-threads=%f"
},
levelName: {
regexReplace: /^level-name=[\s\w\S]+/,
valueFormat: "level-name=%s"
},
levelSeed: {
regexReplace: /level-seed=[0-9]+/,
valueFormat: "level-seed=%f"
},
levelType: {
regexReplace: /level-type=(FLAT|LEGACY|DEFAULT)/,
valueFormat: "level-type=%s"
},
defaultPlayerPermissionLevel: {
regexReplace: /default-player-permission-level=(visitor|member|operator)/,
valueFormat: "default-player-permission-level=%s"
},
texturepackRequired: {
regexReplace: /texturepack-required=(false|true)/,
valueFormat: "texturepack-required=%s"
},
chatRestriction: {
regexReplace: /chat-restriction=(None|Dropped|Disabled)/,
valueFormat: "chat-restriction=%s"
},
viewDistance: {
validate(value: number) {return value > 4},
regexReplace: /view-distance=[0-9]+/,
valueFormat: "view-distance=%f"
},
mojangTelemetry: {
addIfNotExist: "chat-restriction=false",
regexReplace: /chat-restriction=(true|false)/,
valueFormat: "chat-restriction=%s"
},
serverPort: {
regexReplace: /server-port=[0-9]+/,
valueFormat: "server-port=%f"
},
serverPortv6: {
regexReplace: /server-portv6=[0-9]+/,
valueFormat: "server-portv6=%f"
},
}
})
}
export type resourcePacks = {
pack_id: string,
version?: number[]
};
export type resourceManifest = {
format_version?: 2,
header: {
uuid: string,
name?: string,
description?: string,
version?: number[],
min_engine_version?: number[]
},
modules?: {
uuid: string,
type: "resources",
description?: string,
version: number[]
}[]
};
export async function addResourcePacksToWorld(resourceId: string, platformOptions: bdsPlatformOptions = {id: "default"}) {
const { serverPath } = await pathControl("bedrock", platformOptions);
const serverConfigObject = (await serverConfig(platformOptions)).getConfig();
if (!await coreUtils.extendFs.exists(path.join(serverPath, "worlds", serverConfigObject["level-name"], "world_resource_packs.json"))) await fs.writeFile(path.join(serverPath, "worlds", serverConfigObject["level-name"], "world_resource_packs.json"), "[]");
const resourcesData: resourcePacks[] = JSON.parse(await fs.readFile(path.join(serverPath, "worlds", serverConfigObject["level-name"], "world_resource_packs.json"), "utf8"));
const manifests: resourceManifest[] = await Promise.all((await coreUtils.extendFs.readdir({folderPath: [path.join(serverPath, "resource_packs"), path.join(serverPath, "worlds", serverConfigObject["level-name"], "resource_packs")]})).filter((file: string) => file.endsWith("manifest.json")).map(async (file: string) => JSON.parse(await fs.readFile(file, "utf8"))));
const packInfo = manifests.find(pf => pf.header.uuid === resourceId);
if (!packInfo) throw new Error("UUID to texture not installed in the server");
if (resourcesData.includes({pack_id: resourceId})) throw new Error("Textura alredy installed in the World");
resourcesData.push({pack_id: packInfo.header.uuid, version: packInfo.header.version});
await fs.writeFile(path.join(serverPath, "worlds", serverConfigObject["level-name"], "world_resource_packs.json"), JSON.stringify(resourcesData, null, 2));
return resourcesData;
}

View File

@ -1,194 +0,0 @@
import coreUtils from "@sirherobrine23/coreutils";
import { actionV2, actionsV2 } from "../globalPlatfroms.js";
import { pathControl, bdsPlatformOptions } from "../platformPathManeger.js";
import { manegerConfigProprieties } from "../configManipulate.js";
import { randomPort } from "../lib/randomPort.js";
import fsOld from "node:fs";
import path from "node:path";
import fs from "node:fs/promises";
import os from "node:os";
import { compareVersions } from "compare-versions";
import {fileURLToPath} from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
type javaRemoteVersion = {
version: string,
date: string,
latest: boolean,
url: string
};
export async function installServer(version: string|boolean, platformOptions: bdsPlatformOptions = {id: "default"}) {
const { serverPath, serverRoot, platformIDs, id } = await pathControl("java", platformOptions);
const allVersions = (await coreUtils.httpRequest.getJSON<javaRemoteVersion[]>("https://mcpeversion-static.sirherobrine23.org/java/all.json")).sort(({version: a}, {version: b}) => compareVersions(a, b));
const javaDownload = ((typeof version === "boolean")||(version?.trim()?.toLowerCase() === "latest")) ? allVersions.at(-1) : allVersions.find(rel => (version === rel.version));
if (!javaDownload) throw new Error("Cannot find version!");
await coreUtils.httpRequestLarge.saveFile({url: javaDownload.url, filePath: path.join(serverPath, "server.jar")});
await fs.writeFile(path.join(serverRoot, "version_installed.json"), JSON.stringify({version: javaDownload.version, date: javaDownload.date, installDate: new Date()}));
if (platformIDs.length > 1) {
const platformPorts = (await Promise.all(platformIDs.map(id => serverConfig({id})))).map(config => config.getConfig()["server-port"]);
let port: number;
while (!port) {
const tmpNumber = await randomPort();
if (platformPorts.some(ports => ports === tmpNumber)) continue;
port = tmpNumber;
};
await (await serverConfig({id})).editConfig({name: "serverPort", data: port}).save();
}
return {
id,
version: javaDownload.version,
date: javaDownload.date,
url: javaDownload.url
};
}
export const started = /\[.*\].*\s+Done\s+\([0-9\.]+s\)\!.*/;
export const portListen = /\[.*\]:\s+Starting\s+Minecraft\s+server\s+on\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[A-Za-z0-9]+|\*):([0-9]+))/;
export const playerAction = /\[.*\]:\s+([\S\w]+)\s+(joined|left|lost)/;
const javaHooks: actionsV2 = {
serverStarted(data, done) {
// [22:35:26] [Server thread/INFO]: Done (6.249s)! For help, type "help"
if (started.test(data)) done(new Date());
},
portListening(data, done) {
const portParse = data.match(portListen);
if (!portParse) return;
let [,, host, port] = portParse;
if (host === "*"||!host) host = "127.0.0.1";
done({
port: parseInt(port),
type: "TCP",
host: host,
protocol: "IPV4/IPv6"
});
},
playerAction(data, Callbacks) {
if (playerAction.test(data)) {
const [, playerName, action] = data.match(data)||[];
if (action === "joined") Callbacks.connect({playerName, connectTime: new Date()});
else if (action === "left") Callbacks.disconnect({playerName, connectTime: new Date()});
else if (action === "lost") Callbacks.unknown({playerName, connectTime: new Date(), action: "lost"});
else Callbacks.unknown({playerName, connectTime: new Date()});
}
},
stopServer(components) {
components.actions.runCommand("stop");
return components.actions.waitExit();
},
};
export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean, platformOptions?: bdsPlatformOptions}) {
const { serverPath, logsPath, id } = await pathControl("java", Config?.platformOptions||{id: "default"});
const jarPath = path.join(serverPath, "server.jar");
if (!fsOld.existsSync(jarPath)) throw new Error("Install server fist.");
const command = "java";
const args = [
"-XX:+UseG1GC",
"-XX:+ParallelRefProcEnabled",
"-XX:MaxGCPauseMillis=200",
"-XX:+UnlockExperimentalVMOptions",
"-XX:+DisableExplicitGC",
"-XX:+AlwaysPreTouch",
"-XX:G1NewSizePercent=30",
"-XX:G1MaxNewSizePercent=40",
"-XX:G1HeapRegionSize=8M",
"-XX:G1ReservePercent=20",
"-XX:G1HeapWastePercent=5",
"-XX:G1MixedGCCountTarget=4",
"-XX:InitiatingHeapOccupancyPercent=15",
"-XX:G1MixedGCLiveThresholdPercent=90",
"-XX:G1RSetUpdatingPauseTimePercent=5",
"-XX:SurvivorRatio=32",
"-XX:+PerfDisableSharedMem",
"-XX:MaxTenuringThreshold=1",
"-Dusing.aikars.flags=https://mcflags.emc.gs",
"-Daikars.new.flags=true",
"-XX:+UnlockDiagnosticVMOptions",
"-XX:-UseAESCTRIntrinsics"
];
if (Config) {
if (Config.maxFreeMemory) {
const safeFree = Math.floor(os.freemem()/1e6);
if (safeFree > 1000) Config.maxMemory = safeFree;
else console.warn("There is little ram available!")
}
if (Config.maxMemory) args.push(`-Xmx${Config.maxMemory}m`);
if (Config.minMemory) args.push(`-Xms${Config.minMemory}m`);
}
args.push("-jar", jarPath, "nogui");
const eula = path.join(serverPath, "eula.txt");
await fs.writeFile(eula, (await fs.readFile(eula, "utf8").catch(() => "eula=false")).replace("eula=false", "eula=true"));
const logFileOut = path.join(logsPath, `${Date.now()}_${process.platform}_${process.arch}.log`);
return actionV2({
id, platform: "java",
processConfig: {command, args, options: {cwd: serverPath, maxBuffer: Infinity, logPath: {stdout: logFileOut}}},
hooks: javaHooks
});
}
export type Gamemode = {name: "Gamemode", data: "survival"|"creative"|"hardcore"};
export type Difficulty = {name: "Difficulty", data: "peaceful"|"easy"|"normal"|"hard"};
export type serverPort = {name: "serverPort", data: number};
export type maxPlayers = {name: "maxPlayers", data: number};
export type allowList = {name: "allowList", data: boolean};
export type serverDescription = {name: "serverDescription", data: string};
export type worldName = {name: "worldName", data: string};
export type editConfig = Gamemode|Difficulty|serverPort|maxPlayers|allowList|serverDescription|worldName;
/**
* Update java server config
* @param platformOptions
* @returns
*/
export async function serverConfig(platformOptions: bdsPlatformOptions = {id: "default"}) {
const { serverPath } = await pathControl("java", platformOptions);
const fileProperties = path.join(serverPath, "server.properties");
if (!await coreUtils.extendFs.exists(fileProperties)) await fs.cp(path.join(__dirname, "../configs/java/server.properties"), fileProperties);
return manegerConfigProprieties<editConfig>({
configPath: fileProperties,
configManipulate: {
Gamemode: (fileConfig, value: string) => {
if (!(["survival", "creative", "hardcore"]).includes(value)) throw new Error("Invalid gameode");
if (value === "hardcore") fileConfig = fileConfig.replace(/gamemode=(survival|creative)/, `gamemode=survial`).replace(/hardcore=(false|true)/, `hardcore=true`);
else {
if (!(value === "survival"||value === "creative")) throw new Error("Invalid gamemode");
fileConfig = fileConfig.replace(/gamemode=(survival|creative)/, `gamemode=${value}`).replace(/hardcore=(false|true)/, `hardcore=false`);
}
return fileConfig;
},
Difficulty: {
validate: (value: string) => (["peaceful", "easy", "normal", "hard"]).includes(value),
regexReplace: /difficulty=(peaceful|easy|normal|hard)/,
valueFormat: "difficulty=%s"
},
serverPort: {
validate: (value: number) => value > 1000,
regexReplace: /server-port=([0-9]+)/,
valueFormat: "server-port=%f"
},
maxPlayers: {
validate: (value: number) => value > 1,
regexReplace: /max-players=([0-9]+)/,
valueFormat: "max-players=%f"
},
serverDescription: {
validate: (value: string) => value.length < 50,
regexReplace: /motd=(.*)/,
valueFormat: "motd=%s"
},
worldName: {
validate: (value: string) => value.length < 50,
regexReplace: /level-name=(.*)/,
valueFormat: "level-name=%s"
},
allowList: {
validate: (value: boolean) => value === true||value === false,
regexReplace: /white-list=(true|false)/,
valueFormat: "white-list=%o"
}
}
})
}

View File

@ -1,119 +0,0 @@
import { pathControl, bdsPlatformOptions } from "../platformPathManeger.js";
import { spigotProprieties } from "./spigot.js";
import * as globalPlatfroms from "../globalPlatfroms.js";
import * as coreUtils from "@sirherobrine23/coreutils";
import Proprieties from "../lib/Proprieties.js";
import fsOld from "node:fs";
import path from "node:path";
import fs from "node:fs/promises";
import os from "node:os";
import { compareVersions } from "compare-versions";
export async function installServer(version: string|boolean, platformOptions: bdsPlatformOptions = {id: "default"}) {
const { serverPath, id } = await pathControl("paper", platformOptions);
const allVersions = (await coreUtils.httpRequest.getJSON("https://mcpeversion-static.sirherobrine23.org/paper/all.json")).sort(({version: a}, {version: b}) => compareVersions(a, b));
const release = ((typeof version === "boolean")||(version?.trim()?.toLowerCase() === "latest")) ? allVersions.at(-1) : allVersions.find(rel => (version === rel.version));
if (!release) throw new Error("Cannot find version!");
await coreUtils.httpRequestLarge.saveFile({url: release.url, filePath: path.join(serverPath, "paper.jar")});
return {
id,
version: release.version,
url: release.url,
date: release.date
};
}
export const started = /\[.*\].*\s+Done\s+\(.*\)\!.*/;
export const portListen = /\[.*\]:\s+Starting\s+Minecraft\s+server\s+on\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[A-Za-z0-9]+|\*):([0-9]+))/;
export const playerAction = /\[.*\]:\s+([\S\w]+)\s+(joined|left|lost)/;
export const paperHook: globalPlatfroms.actionsV2 = {
serverStarted(data, done) {
// [22:35:26] [Server thread/INFO]: Done (6.249s)! For help, type "help"
if (started.test(data)) done(new Date());
},
playerAction(data, Callbacks) {
if (!playerAction.test(data)) return;
const [, playerName, action] = data.match(data)||[];
if (action === "joined") Callbacks.connect({playerName, connectTime: new Date()});
else if (action === "left") Callbacks.disconnect({playerName, connectTime: new Date()});
else if (action === "lost") Callbacks.unknown({playerName, connectTime: new Date(), action: "lost"});
else Callbacks.unknown({playerName, connectTime: new Date()});
},
portListening(data, done) {
const portParse = data.match(portListen);
if (!portParse) return;
let [,, host, port] = portParse;
if (host === "*"||!host) host = "127.0.0.1";
done({
port: parseInt(port),
type: "TCP",
host: host,
protocol: /::/.test(host?.trim())?"IPv6":/[0-9]+\.[0-9]+/.test(host?.trim())?"IPv4":"IPV4/IPv6"
});
},
stopServer(components) {
components.actions.runCommand("stop");
return components.actions.waitExit();
},
};
export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean, platformOptions?: bdsPlatformOptions}) {
const { serverPath, logsPath, id } = await pathControl("paper", Config?.platformOptions||{id: "default"});
if (!fsOld.existsSync(path.join(serverPath, "paper.jar"))) throw new Error("Install server fist.");
const args = [
"-XX:+UseG1GC",
"-XX:+ParallelRefProcEnabled",
"-XX:MaxGCPauseMillis=200",
"-XX:+UnlockExperimentalVMOptions",
"-XX:+DisableExplicitGC",
"-XX:+AlwaysPreTouch",
"-XX:G1NewSizePercent=30",
"-XX:G1MaxNewSizePercent=40",
"-XX:G1HeapRegionSize=8M",
"-XX:G1ReservePercent=20",
"-XX:G1HeapWastePercent=5",
"-XX:G1MixedGCCountTarget=4",
"-XX:InitiatingHeapOccupancyPercent=15",
"-XX:G1MixedGCLiveThresholdPercent=90",
"-XX:G1RSetUpdatingPauseTimePercent=5",
"-XX:SurvivorRatio=32",
"-XX:+PerfDisableSharedMem",
"-XX:MaxTenuringThreshold=1",
"-Dusing.aikars.flags=https://mcflags.emc.gs",
"-Daikars.new.flags=true",
"-XX:+UnlockDiagnosticVMOptions",
"-XX:-UseAESCTRIntrinsics"
];
if (Config) {
if (Config.maxFreeMemory) {
const safeFree = Math.floor(os.freemem()/1e6);
if (safeFree > 1000) Config.maxMemory = safeFree;
else console.warn("There is little ram available!")
}
if (Config.maxMemory) args.push(`-Xmx${Config.maxMemory}m`);
if (Config.minMemory) args.push(`-Xms${Config.minMemory}m`);
}
args.push("-jar", path.join(serverPath, "paper.jar"), "nogui");
const eula = path.join(serverPath, "eula.txt");
await fs.writeFile(eula, (await fs.readFile(eula, "utf8").catch(() => "eula=false")).replace("eula=false", "eula=true"));
const logFileOut = path.join(logsPath, `${Date.now()}_${process.platform}_${process.arch}.log`);
return globalPlatfroms.actionV2({
id, platform: "paper",
processConfig: {command: "java", args, options: {cwd: serverPath, maxBuffer: Infinity, logPath: {stdout: logFileOut}}},
hooks: paperHook
});
}
export async function getConfig(platformOptions: bdsPlatformOptions = {id: "default"}) {
const { serverPath } = await pathControl("paper", platformOptions);
return Proprieties.parse<spigotProprieties>(await fs.readFile(path.join(serverPath, "server.properties"), "utf8"));
}
// This is a fast and dirty way to implement a new feature, but i'm too exhausted to implement the same type as bedrock
export async function updateConfig(config: {key: string, value: any}, platformOptions: bdsPlatformOptions = {id: "default"}) {
const currentConfig = await getConfig(platformOptions);
const { serverPath } = await pathControl("paper", platformOptions);
currentConfig[config.key] = config.value;
return fs.writeFile(path.join(serverPath, "server.properties"), Proprieties.stringify(currentConfig));
}

View File

@ -1,115 +0,0 @@
import { childPromisses, extendFs, httpRequest, httpRequestGithub, httpRequestLarge } from "@sirherobrine23/coreutils";
import { pathControl, bdsPlatformOptions } from "../platformPathManeger.js";
import { existsSync as fsExistsSync, Stats } from "node:fs";
import * as globalPlatfroms from "../globalPlatfroms.js";
import path from "node:path";
import fs from "node:fs/promises";
import debug from "debug";
const pocketmineDebug = debug("bdscore:platform:pocketmine");
const phpStaticBucket = "https://objectstorage.sa-saopaulo-1.oraclecloud.com/p/0IKM-5KFpAF8PuWoVe86QFsF4sipU2rXfojpaOMEdf4QgFQLcLlDWgMSPHWmjf5W/n/grwodtg32n4d/b/bdsFiles/o/";
export async function listVersions() {
return (await httpRequestGithub.getRelease({owner: "pmmp", repository: "PocketMine-MP", all: true})).map(data => {
const pharFile = data.assets.find(data => data.name.endsWith((".phar")));
return {
version: data.tag_name,
publish: new Date(data.published_at),
pharFile: pharFile?.browser_download_url,
size: pharFile?.size
};
}).filter(rel => !!rel.pharFile);
}
async function findPhp(serverPath: string, extraPath?: string): Promise<string> {
if (!extraPath) extraPath = path.join(serverPath, "bin");
const files = await Promise.all((await fs.readdir(extraPath)).map(file => fs.lstat(path.join(extraPath, file)).then(stat => ({stat, file, fullPath: path.join(extraPath, file)})).catch(() => {})));
let folderFF = "";
for (const file of (files.filter(a=>!!a) as {file: string, fullPath: string, stat: Stats}[]).sort(a => a.stat.isDirectory() ? 1:-1)) {
if (file.stat.isDirectory()) {
folderFF = await findPhp(serverPath, file.fullPath).catch(() => "");
if (folderFF) return folderFF;
} else if (file.file === "php"||file.file === "php.exe") return file.fullPath;
}
if (folderFF) return folderFF;
throw new Error("Cannot find php");
}
async function installPhp(serverPath: string): Promise<void> {
let filePath = (await httpRequest.getJSON<{objects: {name: string}[]}>(phpStaticBucket)).objects.find(({name}) => name.includes(process.platform) && name.includes(process.arch))?.name;
if (!filePath) {
pocketmineDebug("Current OS: %s", process.platform);
pocketmineDebug("Current Arch: %s", process.arch);
throw new Error("Cannot find php release!");
}
const binFolder = path.resolve(serverPath, "bin");
if (await extendFs.exists(binFolder)) await fs.rm(path.resolve(serverPath, "bin"), {recursive: true});
filePath = phpStaticBucket+filePath;
if (filePath.endsWith(".zip")) await httpRequestLarge.extractZip({url: filePath, folderTarget: binFolder});
else if (filePath.endsWith(".tar.gz")||filePath.endsWith(".tgz")||filePath.endsWith(".tar")) await httpRequestLarge.tarExtract({url: filePath, folderPath: binFolder});
else throw new Error("Invalid file: "+filePath);
// test it's works php
const phpExec = await findPhp(serverPath);
if (!phpExec) throw new Error("Cannot find php exec file!");
await childPromisses.execFile(phpExec, ["--version"]).catch(err => {
pocketmineDebug("PHP bin error: %O", err);
pocketmineDebug("Current OS: %s", process.platform);
pocketmineDebug("Current Arch: %s", process.arch);
throw new Error("Corrupt PHP in host!");
});
}
export async function installServer(version: string|boolean, platformOptions: bdsPlatformOptions = {id: "default"}) {
platformOptions.withBuildFolder = true;
const serverFolders = await pathControl("pocketmine", platformOptions);
await installPhp(serverFolders.serverPath);
if (typeof version === "boolean") version = "latest";
if (version?.trim()?.toLowerCase() === "latest") version = (await listVersions()).at(0)?.version
const info = (await listVersions()).find(rel => rel.version === version);
await httpRequestLarge.saveFile({url: info?.pharFile, filePath: path.join(serverFolders.serverPath, "pocketmine.phar")});
return {
id: serverFolders.id,
version: info.version,
url: info.pharFile,
date: info.publish
};
}
const portListen = /([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}|\[[a-zA-Z0-9:]+\]):([0-9]+)/;
// const player = /[.*]:\s+(.*)\s+(.*)\s+the\s+game/gi;
export async function startServer(platformOptions: bdsPlatformOptions = {id: "default"}) {
const { serverPath, logsPath, id } = await pathControl("pocketmine", platformOptions);
const serverPhar = path.join(serverPath, "pocketmine.phar");
if (!fsExistsSync(serverPhar)) throw new Error("Install server fist!");
const runStart = new Date();
const logFileOut = path.join(logsPath, `${runStart.getTime()}_${process.platform}_${process.arch}.stdout.log`);
const pocketmineHooks: globalPlatfroms.actionsV2 = {
serverStarted(data, done) {
if (!(data.includes("INFO") && data.includes("Done") && data.includes("help"))) return;
const doneStart = new Date();
done({
onAvaible: doneStart,
timePassed: runStart.getTime() - doneStart.getTime()
});
},
portListening(data, done) {
if (!portListen.test(data)) return;
const [,, host, port] = data.match(portListen);
done({
type: "UDP",
protocol: /\[[a-zA-Z0-9:]+\]/.test(host?.trim())?"IPv6":/[0-9]+\.[0-9]+/.test(host?.trim())?"IPv4":"IPV4/IPv6",
port: parseInt(port),
host: host?.trim()
});
},
stopServer(components) {
components.actions.runCommand("stop");
return components.actions.waitExit();
},
};
return globalPlatfroms.actionV2({
id, platform: "pocketmine",
processConfig: {command: await findPhp(serverPath), args: [serverPhar, "--no-wizard"], options: {cwd: serverPath, maxBuffer: Infinity, logPath: {stdout: logFileOut}}},
hooks: pocketmineHooks
});
}

View File

@ -1,103 +0,0 @@
import coreUtils, { httpRequestLarge } from "@sirherobrine23/coreutils";
import { pathControl, bdsPlatformOptions } from "../platformPathManeger.js";
import * as globalPlatfroms from "../globalPlatfroms.js";
import path from "node:path";
import fsOld from "node:fs";
import fs from "node:fs/promises";
import os from "node:os";
import { compareVersions } from "compare-versions";
export async function installServer(version: string|boolean, platformOptions: bdsPlatformOptions = {id: "default"}) {
const { serverPath, id } = await pathControl("powernukkit", platformOptions);
const jarPath = path.join(serverPath, "pwnukkit.jar");
if (!fsOld.existsSync(serverPath)) await fs.mkdir(serverPath, {recursive: true});
const allVersions = (await coreUtils.httpRequest.getJSON("https://mcpeversion-static.sirherobrine23.org/paper/all.json")).sort(({version: a}, {version: b}) => compareVersions(a, b));
const pwNukktiData = ((typeof version === "boolean")||(version?.trim()?.toLowerCase() === "latest")) ? allVersions.at(-1) : allVersions.find(rel => (version === rel.version));
if (!pwNukktiData) throw new Error("Cannot find version!");
// const pwNukktiData = await platformManeger.powernukkit.find(version);
await httpRequestLarge.saveFile({url: pwNukktiData.url, filePath: jarPath})
return {
id,
version: pwNukktiData.version,
url: pwNukktiData.url,
date: pwNukktiData.date
};
}
export const playerAction = /^.*\[.*\]\s([\S\w]+|"[\S\w]+")\s+(left|joined)\s+the\s+game$/;
export const portListen = /Opening\s+server\s+on\s+(([A-Za-z0-9:\.]+):([0-9]+))/;
export const powernukkitHooks: globalPlatfroms.actionsV2 = {
serverStarted(data, done) {
// 16:57:15 [INFO ] Done (2.122s)! For help, type "help" or "?"
if (/^.*\[.*\]\s+Done\s+\([0-9\.]+s\)!/.test(data)) done(new Date());
},
portListening(data, done) {
if (portListen.test(data)) {
const [,, host, port] = data.match(portListen);
done({
port: parseInt(port),
type: "UDP",
protocol: /::/.test(host?.trim())?"IPv6":/[0-9]+\.[0-9]+/.test(host?.trim())?"IPv4":"IPV4/IPv6",
host: host
})
}
},
playerAction(data, Callbacks) {
if (playerAction.test(data)) {
const [, playerName, action] = data.match(playerAction)||[];
if (action === "joined") Callbacks.connect({connectTime: new Date(), playerName});
else if (action === "left") Callbacks.disconnect({connectTime: new Date(), playerName});
else Callbacks.unknown({connectTime: new Date(), playerName});
}
},
stopServer(components) {
components.actions.runCommand("stop");
return components.actions.waitExit();
},
};
export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean, platformOptions?: bdsPlatformOptions}) {
const { serverPath, logsPath, id } = await pathControl("powernukkit", Config?.platformOptions||{id: "default"});
const jarPath = path.join(serverPath, "pwnukkit.jar");
if (!fsOld.existsSync(jarPath)) throw new Error("Install server fist.");
const args = [
"-XX:+UseG1GC",
"-XX:+ParallelRefProcEnabled",
"-XX:MaxGCPauseMillis=200",
"-XX:+UnlockExperimentalVMOptions",
"-XX:+DisableExplicitGC",
"-XX:+AlwaysPreTouch",
"-XX:G1NewSizePercent=30",
"-XX:G1MaxNewSizePercent=40",
"-XX:G1HeapRegionSize=8M",
"-XX:G1ReservePercent=20",
"-XX:G1HeapWastePercent=5",
"-XX:G1MixedGCCountTarget=4",
"-XX:InitiatingHeapOccupancyPercent=15",
"-XX:G1MixedGCLiveThresholdPercent=90",
"-XX:G1RSetUpdatingPauseTimePercent=5",
"-XX:SurvivorRatio=32",
"-XX:+PerfDisableSharedMem",
"-XX:MaxTenuringThreshold=1",
"-Dusing.aikars.flags=https://mcflags.emc.gs",
"-Daikars.new.flags=true",
"-XX:+UnlockDiagnosticVMOptions",
"-XX:-UseAESCTRIntrinsics"
];
if (Config) {
if (Config.maxFreeMemory) {
const safeFree = Math.floor(os.freemem()/1e6);
if (safeFree > 1000) Config.maxMemory = safeFree;
else console.warn("There is little ram available!")
}
if (Config.maxMemory) args.push(`-Xmx${Config.maxMemory}m`);
if (Config.minMemory) args.push(`-Xms${Config.minMemory}m`);
}
args.push("-jar", jarPath, "--language", "eng");
const logFileOut = path.join(logsPath, `${Date.now()}_${process.platform}_${process.arch}.log`);
return globalPlatfroms.actionV2({
id, platform: "powernukkit",
processConfig: {command: "java", args, options: {cwd: serverPath, maxBuffer: Infinity, logPath: {stdout: logFileOut}}},
hooks: powernukkitHooks
});
}

View File

@ -1,198 +0,0 @@
import { httpRequestLarge, httpRequestGithub } from "@sirherobrine23/coreutils";
import { pathControl, bdsPlatformOptions } from "../platformPathManeger.js";
import * as globalPlatfroms from "../globalPlatfroms.js";
import Proprieties from "../lib/Proprieties.js"
import fsOld from "node:fs";
import path from "node:path";
import fs from "node:fs/promises";
import os from "node:os";
import { compareVersions } from "compare-versions";
async function listVersions(): Promise<{version: string, date: Date, url: string}[]> {
const releases = (await httpRequestGithub.getRelease({owner: "The-Bds-Maneger", repository: "SpigotBuilds", all: true})).filter(rel => rel.tag_name !== "latest" && rel.assets.some(file => file.name.endsWith(".jar")));
return releases.map(rel => ({
version: rel.tag_name,
date: new Date(rel.published_at),
url: rel.assets.find(file => file.name.endsWith(".jar"))?.browser_download_url
})).sort((a, b) => compareVersions(a.version.replace(/\-[a-zA-Z\-]+/, ".0"), b.version.replace(/\-[a-zA-Z\-]+/, ".0")));
}
export async function installServer(version: string|boolean, platformOptions: bdsPlatformOptions = {id: "default"}) {
if (!(typeof version === "boolean"||typeof version === "string" && !!version?.trim())) throw TypeError("Version only if boolean and string");
const serverPath = await pathControl("spigot", platformOptions);
const relData = (await listVersions()).find(rel => ((typeof version === "boolean"||version.trim().toLowerCase() === "latest")||version === rel.version));
if (!relData) throw new Error("no version found!");
await httpRequestLarge.saveFile({
url: relData.url,
filePath: path.join(serverPath.serverPath, "server.jar")
});
return {
id: serverPath.id,
url: relData.url,
version: version,
date: relData.date
};
}
export const started = /\[.*\].*\s+Done\s+\(.*\)\!.*/;
export const portListen = /\[.*\]:\s+Starting\s+Minecraft\s+server\s+on\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[A-Za-z0-9]+|\*):([0-9]+))/;
export const playerAction = /\[.*\]:\s+([\S\w]+)\s+(joined|left|lost)/;
export const serverConfig: globalPlatfroms.actionsV2 = {
serverStarted(data, done) {
// [22:35:26] [Server thread/INFO]: Done (6.249s)! For help, type "help"
if (started.test(data)) done(new Date());
},
portListening(data, done) {
const serverPort = data.match(portListen);
if (serverPort) {
let [,, host, port] = serverPort;
if (host === "*"||!host) host = "127.0.0.1";
return done({
port: parseInt(port),
type: "TCP",
host: host,
protocol: /::/.test(host?.trim())?"IPv6":/[0-9]+\.[0-9]+/.test(host?.trim())?"IPv4":"IPV4/IPv6"
});
}
},
playerAction(data, Callbacks) {
if (playerAction.test(data)) {
const [, playerName, action] = data.match(data)||[];
if (action === "joined") Callbacks.connect({playerName, connectTime: new Date()});
else if (action === "left") Callbacks.disconnect({playerName, connectTime: new Date()});
else if (action === "lost") Callbacks.unknown({playerName, connectTime: new Date(), action: "lost"});
else Callbacks.unknown({playerName, connectTime: new Date()});
}
},
stopServer(components) {
components.actions.runCommand("stop");
return components.actions.waitExit();
},
};
export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean, platformOptions?: bdsPlatformOptions}) {
const { serverPath, logsPath, id } = await pathControl("spigot", Config?.platformOptions||{id: "default"});
const jarPath = path.join(serverPath, "server.jar");
if (!fsOld.existsSync(jarPath)) throw new Error("Install server fist.");
const args = [
"-XX:+UseG1GC",
"-XX:+ParallelRefProcEnabled",
"-XX:MaxGCPauseMillis=200",
"-XX:+UnlockExperimentalVMOptions",
"-XX:+DisableExplicitGC",
"-XX:+AlwaysPreTouch",
"-XX:G1NewSizePercent=30",
"-XX:G1MaxNewSizePercent=40",
"-XX:G1HeapRegionSize=8M",
"-XX:G1ReservePercent=20",
"-XX:G1HeapWastePercent=5",
"-XX:G1MixedGCCountTarget=4",
"-XX:InitiatingHeapOccupancyPercent=15",
"-XX:G1MixedGCLiveThresholdPercent=90",
"-XX:G1RSetUpdatingPauseTimePercent=5",
"-XX:SurvivorRatio=32",
"-XX:+PerfDisableSharedMem",
"-XX:MaxTenuringThreshold=1",
"-Dusing.aikars.flags=https://mcflags.emc.gs",
"-Daikars.new.flags=true",
"-XX:+UnlockDiagnosticVMOptions",
"-XX:-UseAESCTRIntrinsics"
];
if (Config) {
if (Config.maxFreeMemory) {
const safeFree = Math.floor(os.freemem()/1e6);
if (safeFree > 1000) Config.maxMemory = safeFree;
else console.warn("There is little ram available!")
}
if (Config.maxMemory) args.push(`-Xmx${Config.maxMemory}m`);
if (Config.minMemory) args.push(`-Xms${Config.minMemory}m`);
}
args.push("-jar", jarPath, "nogui");
const eula = path.join(serverPath, "eula.txt");
await fs.readFile(eula, "utf8").catch(() => "eula=false").then(eulaFile => fs.writeFile(eula, eulaFile.replace("eula=false", "eula=true")));
const logFileOut = path.join(logsPath, `${Date.now()}_${process.platform}_${process.arch}.log`);
return globalPlatfroms.actionV2({
id, platform: "spigot",
processConfig: {command: "java", args, options: {cwd: serverPath, maxBuffer: Infinity, logPath: {stdout: logFileOut}}},
hooks: serverConfig
});
}
export type baseConfig = {
"gamemode": string,
"level-name": string,
"level-seed": number,
"pvp": boolean,
"difficulty": "easy"|"normal"|"hard",
"hardcore": boolean,
"motd": string,
"server-port": number,
"enforce-secure-profile": boolean,
"require-resource-pack": boolean,
"max-players": number,
"online-mode": boolean,
"enable-status": boolean,
"allow-flight": boolean,
"view-distance": number,
"simulation-distance": number,
"player-idle-timeout": number,
"force-gamemode": boolean,
"white-list": boolean,
"spawn-animals": boolean,
"enforce-whitelist": boolean,
"enable-command-block": boolean,
};
export type ignoreBaseConfig = {
"query.port": number,
"enable-jmx-monitoring": boolean,
"rcon.port": number,
"enable-query": boolean,
"generator-settings": "{}"|string,
"generate-structures": boolean,
"max-chained-neighbor-updates": number,
"network-compression-threshold": number,
"max-tick-time": number,
"use-native-transport": boolean,
"broadcast-rcon-to-ops": boolean,
"server-ip": string,
"resource-pack-prompt": any,
"allow-nether": boolean,
"enable-rcon": boolean,
"sync-chunk-writes": boolean,
"op-permission-level": number,
"prevent-proxy-connections": boolean,
"hide-online-players": boolean,
"resource-pack": any,
"entity-broadcast-range-percentage": number,
"rcon.password": string,
"debug": boolean,
"rate-limit": number,
"broadcast-console-to-ops": boolean,
"spawn-npcs": boolean,
"previews-chat": boolean,
"function-permission-level": number,
"level-type": "minecraft\\:normal"|string,
"text-filtering-config": any,
"spawn-monsters": boolean,
"spawn-protection": number,
"resource-pack-sha1": any|string,
"max-world-size": number
}
export type spigotProprieties = baseConfig & ignoreBaseConfig;
export async function getConfig(platformOptions: bdsPlatformOptions = {id: "default"}) {
const { serverPath } = await pathControl("spigot", platformOptions);
return Proprieties.parse<spigotProprieties>(await fs.readFile(path.join(serverPath, "server.properties"), "utf8"));
}
// This is a fast and dirty way to implement a new feature, but i'm too exhausted to implement the same type as bedrock
export async function updateConfig(config: {key: string, value: any}, platformOptions: bdsPlatformOptions = {id: "default"}) {
const currentConfig = await getConfig(platformOptions);
const { serverPath } = await pathControl("spigot", platformOptions);
currentConfig[config.key] = config.value;
return fs.writeFile(path.join(serverPath, "server.properties"), Proprieties.stringify(currentConfig));
}

View File

@ -1,30 +0,0 @@
import fs from "node:fs/promises";
import utils from "node:util";
import Proprieties, { properitiesBase } from "./lib/Proprieties.js";
export type configEdit = {name: string, data?: any};
export async function manegerConfigProprieties<updateConfig extends configEdit, configJson extends properitiesBase = any>(config: {configPath: string, configManipulate: {[Properties in updateConfig["name"]]: ((config: string, value: updateConfig["data"]) => string)|{validate?: (value: updateConfig["data"]) => boolean, regexReplace: RegExp, valueFormat: string, addIfNotExist?: string}}}) {
let configFile = await fs.readFile(config.configPath, "utf8");
const mani = {save, editConfig, getConfig: () => Proprieties.parse<configJson>(configFile)};
async function save() {
await fs.writeFile(config.configPath, configFile);
return configFile;
}
function editConfig(serverConfig: updateConfig) {
if (!config.configManipulate[serverConfig.name]) throw new Error("Key name not exist");
const manipulation = config.configManipulate[serverConfig.name as updateConfig["name"]];
if (typeof manipulation === "function") configFile = manipulation(configFile, serverConfig.data);
else {
if (typeof manipulation.validate === "function") if (!manipulation.validate(serverConfig.data)) throw new Error("Invaid value");
if (!manipulation.regexReplace.test(configFile)) {
if (manipulation.addIfNotExist) configFile += ("\n"+manipulation.addIfNotExist);
else throw new Error("Not config exist!");
}
configFile = configFile.replace(manipulation.regexReplace, utils.format(manipulation.valueFormat, serverConfig.data));
}
return mani;
}
return mani;
}

View File

@ -1,155 +0,0 @@
import * as coreUtils from "@sirherobrine23/coreutils";
import net from "node:net";
import crypto from "node:crypto";
import fs from "node:fs/promises";
import tar from "tar";
import { bdsRoot } from "./platformPathManeger.js";
export type payload = {
httpVersion?: string,
request?: {method: string, path: string},
response?: {code: number, text: string},
header?: {[key: string]: string|boolean|number},
second?: payload,
raw?: string,
socket?: net.Socket
body?: any,
};
export class payloadError extends Error {
public payload: payload;
constructor(errMessage: string, payload: payload) {
super(errMessage);
this.payload = payload;
}
}
const payloadRequest = /^(GET|POST|CONNECT|HEAD|PUT|DELETE)\s+(.*)\s+HTTP\/([0-9\.]+)/;
const payloadResponse = /HTTP\/([0-9\.]+)\s+([0-9]+)\s+([\w\S\s]+)/;
const parseHeard = /^([0-9A-Za-z\._-\s@]+):([\w\S\s]+)/;
async function parsePayload(input: string|Buffer|net.Socket): Promise<payload> {
const payloadBody: payload = {header: {}};
let data = "";
if (typeof input === "string") data = input; else {
if (Buffer.isBuffer(input)) data = input.toString("utf8");
else {
payloadBody.socket = input;
data = await new Promise<string>(done => input.once("data", dataInput => done(dataInput.toString("utf8"))));
}
}
payloadBody.raw = data;
if (/^{.*}$/.test(data.replace(/\r?\n/, ""))) {
payloadBody.body = JSON.parse(data);
return payloadBody;
}
for (const line of data.trim().split(/\r?\n/g)) {
data = data.replace(line, "").trim();
if (payloadResponse.test(line) && !payloadBody.request) {
const [, httpVersion, CodeNumber, responseText] = line.match(payloadResponse);
payloadBody.httpVersion = httpVersion;
payloadBody.response = {
code: parseInt(CodeNumber),
text: responseText
};
} else if (payloadRequest.test(line) && !payloadBody.response) {
const [, method, reqPath, httpVersion] = line.match(payloadRequest);
if (!payloadBody.request) {
payloadBody.httpVersion = httpVersion;
payloadBody.request = {
method: method,
path: reqPath
};
continue;
} else payloadBody.second = await parsePayload(`${line}\r\n${data}`);
break;
} else if (parseHeard.test(line.trim())) {
const [, key, value] = line.trim().match(parseHeard);
if (value.trim() === "false"||value.trim() === "true") payloadBody.header[key.trim()] = Boolean(value.trim());
else if (/^[0-9]+$/.test(value.trim())) payloadBody.header[key.trim()] = parseFloat(value.trim());
else payloadBody.header[key.trim()] = value.trim();
continue;
}
payloadBody.body = data.trim();
if (line.trim() === "") break;
};
if (payloadBody.body) {
const backupBody = payloadBody.body;
try {
payloadBody.body = JSON.parse(backupBody);
} catch (_) {
payloadBody.body = backupBody;
}
}
if (payloadBody.response) {
if (!/[12][0-9][0-9]/.test(payloadBody.response.code.toFixed())) throw new payloadError(`Response code ${payloadBody.response.code}, text: ${payloadBody.response.text}`, payloadBody);
}
return payloadBody;
}
function stringifyPayload(socket: net.Socket, response: payload) {
let message = "";
if (response.request) message += `${response.request.method.toUpperCase()} ${response.request.path} HTTP/${response.httpVersion||"1.0"}\r\n`;
else message += `HTTP/${response.httpVersion||"1.0"} ${response.response.code} ${response.response.text}\r\n`;
if (response.header) message += (Object.keys(response.header).map(key => `${key}: ${response.header[key]}`).join("\r\n"))+"\r\n";
message += "\r\n";
if (response.body !== undefined) {
if (Array.isArray(response.body)||typeof response.body === "object") message += JSON.stringify(response.body);
else if (typeof response.body === "string") message += response.body;
else if (typeof response.body === "bigint") message += response.body.toString();
else message += String(response.body);
}
socket.write(message);
return socket;
}
export class exportBds {
public acceptConnection = true;
public authToken = crypto.randomBytes(16).toString("base64");
#server = net.createServer(async (socket): Promise<any> => {
if (!this.acceptConnection) return stringifyPayload(socket, {response: {code: 400, text: "Server locked"}, body: {erro: "Server locked"}}).end();
const payload = await parsePayload(await new Promise<string>(done => socket.once("data", res => done(res.toString("utf8")))));
if (payload.header.Authorization !== this.authToken) return stringifyPayload(socket, {response: {code: 401, text: "Not allowed"}, body: {error: "Invalid token"}}).end();
else stringifyPayload(socket, {response: {code: 200, text: "Success"}, header: {Date: (new Date()).toISOString(), "Content-Type": "bdsStream/tar"}});
this.acceptConnection = false;
console.log("Sending to %s", socket.localAddress+":"+socket.localPort);
// Compact bds root
const tarCompress = tar.create({gzip: true, cwd: bdsRoot}, await fs.readdir(bdsRoot));
tarCompress.pipe(socket);
tarCompress.on("end", () => this.#server.close());
socket.on("close", tarCompress.destroy);
});
public async listen(port = 0) {
return new Promise<number>(done => {
this.#server.listen(port, async () => {
const externalIP = await coreUtils.httpRequestClient.getExternalIP();
let address = this.#server.address()["address"], port = this.#server.address()["port"];
if (/::/.test(address)) address = `[${address}]`;
console.log("auth token '%s'", this.authToken);
console.log("Port listen on http://%s:%s/", address, port);
console.log("Port listen on http://%s:%s/", externalIP.ipv4, port);
if (externalIP.ipv6) console.log("Port listen on http://[%s]:%s/", externalIP.ipv6, port);
return done(port);
});
});
}
public async waitClose() {
return new Promise<void>((done, reject) => {
this.#server.on("error", reject);
this.#server.once("close", done);
});
}
}
export async function importBds(option: {host: string, port: number, authToken: string}) {
if (await coreUtils.extendFs.exists(bdsRoot)) await fs.rename(bdsRoot, bdsRoot+"_backup_"+Date.now());
const {socket} = await parsePayload(stringifyPayload(net.createConnection({host: option.host, port: option.port}), {request: {method: "GET", path: "/"}, header: {Authorization: option.authToken}}));
console.info("Connection sucess!");
const tar_extract = tar.extract({cwd: bdsRoot, noChmod: false, noMtime: false, preserveOwner: true});
socket.pipe(tar_extract);
return new Promise<void>((done, reject) => {
socket.on("error", reject);
tar_extract.on("error", reject);
socket.once("close", () => tar_extract.on("finish", done));
});
}

View File

@ -1,259 +0,0 @@
import fs from "node:fs";
import readline from "node:readline";
import child_process from "node:child_process";
import { EventEmitter } from "node:events";
import { bdsPlatform } from "./platformPathManeger.js";
import debug from "debug";
export const internalSessions: {[sessionID: string]: serverActionV2} = {};
process.once("exit", () => Object.keys(internalSessions).forEach(id => internalSessions[id].stopServer()));
const actionsDebug = debug("bdscore:global_platform");
export type actionCommandOption = {command: string, args?: string[], options?: fs.ObjectEncodingOptions & child_process.ExecFileOptions & {logPath?: {stdout: string, stderr?: string}}};
export type playerHistoric = {[player: string]: {action: "connect"|"disconnect"|"unknown"|"spawn"; date: Date; history: Array<{action: "connect"|"disconnect"|"unknown"|"spawn"; date: Date}>}};
export type playerBase = {
playerName: string,
connectTime: Date,
xuid?: string,
action?: string,
lineString?: string
};
export type portListen = {port: number, host?: string, type: "TCP"|"UDP"|"TCP/UDP", protocol: "IPv4"|"IPv6"|"IPV4/IPv6"|"Unknown", proxyOrigin?: number, plugin?: string};
export type serverStarted = Date|{
onAvaible: Date,
timePassed: number
};
export declare interface serverActionsEvent {
on(act: "error", fn: (data: any) => void): this;
once(act: "error", fn: (data: any) => void): this;
emit(act: "error", data: any): boolean;
on(act: "playerConnect"|"playerDisconnect"|"playerUnknown"|"playerSpawn", fn: (data: playerBase) => void): this;
once(act: "playerConnect"|"playerDisconnect"|"playerUnknown"|"playerSpawn", fn: (data: playerBase) => void): this;
emit(act: "playerConnect"|"playerDisconnect"|"playerUnknown"|"playerSpawn", data: playerBase): boolean;
on(act: "portListening", fn: (data: portListen) => void): this;
once(act: "portListening", fn: (data: portListen) => void): this;
emit(act: "portListening", data: portListen): boolean;
on(act: "serverStarted", fn: (data: serverStarted) => void): this;
once(act: "serverStarted", fn: (data: serverStarted) => void): this;
emit(act: "serverStarted", data: serverStarted): boolean;
on(act: "log_stderr", fn: (data: string) => void): this;
once(act: "log_stderr", fn: (data: string) => void): this;
emit(act: "log_stderr", data: string): boolean;
on(act: "log_stdout", fn: (data: string) => void): this;
once(act: "log_stdout", fn: (data: string) => void): this;
emit(act: "log_stdout", data: string): boolean;
on(act: "log", fn: (data: string) => void): this;
once(act: "log", fn: (data: string) => void): this;
emit(act: "log", data: string): boolean;
on(act: "exit", fn: (data: {code: number, signal: NodeJS.Signals}) => void): this;
once(act: "exit", fn: (data: {code: number, signal: NodeJS.Signals}) => void): this;
emit(act: "exit", data: {code: number, signal: NodeJS.Signals}): boolean;
}
export class serverActionsEvent extends EventEmitter {};
export type playerCallback = {
[T in playerHistoric[number]["action"]]: (player: playerBase) => void
};
export type actionsV2 = {
serverStarted?: (data: string, done: (startedDate: serverStarted) => void) => void,
portListening?: (data: string, done: (portInfo: portListen) => void) => void,
playerAction?: (data: string, Callbacks: playerCallback) => void,
stopServer?: (components: {child: child_process.ChildProcess, actions: serverActionV2}) => void|ReturnType<serverActionV2["stopServer"]>,
playerTp?: (actions: serverActionV2, playerName: string, x: number|string, y: number|string, z: number|string) => void,
};
export type serverActionV2 = {
version: 2,
id: string,
platform: bdsPlatform,
events: serverActionsEvent,
serverCommand?: actionCommandOption,
serverStarted?: serverStarted,
killProcess: (signal?: number|NodeJS.Signals) => boolean,
waitExit: () => Promise<number|NodeJS.Signals>
stopServer: () => ReturnType<serverActionV2["waitExit"]>,
runCommand?: (...command: Array<string|number|boolean>) => serverActionV2,
tp?: (playerName: string, x: number|string, y: number|string, z: number|string) => serverActionV2,
portListening: {[port: number]: portListen},
playerActions: playerHistoric,
};
/**
* A second version for actions, this version fixes several issues that occur with the old class-based version.
*/
export async function actionV2(options: {id: string, platform: bdsPlatform, processConfig: actionCommandOption, hooks: actionsV2}) {
if (internalSessions[options.id]) throw new Error("The platform with that id is already running!");
// Add exec options if not exists
const {processConfig} = options;
if (!processConfig.args) processConfig.args = [];
if (!processConfig.options) processConfig.options = {};
// Disable log buffer limit
processConfig.options.maxBuffer = Infinity;
processConfig.options.env = {...process.env, ...(processConfig.options.env||{})}
// Run commands
actionsDebug("Stating %s", options.id);
const childProcess = child_process.execFile(processConfig.command, processConfig.args, processConfig.options);
const serverObject: serverActionV2 = {
version: 2,
id: options.id,
platform: options.platform,
events: new serverActionsEvent({captureRejections: false}),
playerActions: {},
portListening: {},
serverCommand: processConfig,
runCommand(...command: Array<string|number|boolean>) {
const commandMaped = command.map(a => String(a)).join(" ")
actionsDebug("%s run '%s'", options.id, commandMaped);
childProcess.stdin.write(commandMaped+"\n");
return serverObject;
},
killProcess(signal?: number|NodeJS.Signals) {
actionsDebug("%s call kill with %s", options.id, signal);
if(childProcess?.killed) return childProcess?.killed;
return childProcess.kill(signal);
},
stopServer() {
actionsDebug("%s call stop server", options.id);
if (options.hooks.stopServer === undefined) childProcess.kill("SIGKILL");
const data = options.hooks.stopServer({child: childProcess, actions: serverObject});
if (!data) return serverObject.waitExit();
return data;
},
async waitExit(): Promise<number|NodeJS.Signals> {
if (childProcess.exitCode||childProcess.signalCode) return childProcess.exitCode||childProcess.signalCode;
return new Promise<number>((done, reject) => {
childProcess.once("error", err => reject(err));
childProcess.once("close", code => done(code));
});
},
tp(playerName: string, x: number|string = 0, y: number|string = 0, z: number|string = 0) {
const tpfunction = options.hooks.playerTp;
if (tpfunction === undefined) throw new Error("tp is disabled, tpfunction not defined to platform!");
if (!(playerName?.startsWith("@")||!!this.playerActions[playerName])) throw new Error("Player or target not exist");
tpfunction(serverObject, playerName, x, y, z);
return serverObject;
}
};
// Add to internal sessions
internalSessions[options.id] = serverObject;
serverObject.events.on("exit", () => delete internalSessions[options.id]);
// Break lines with readline
const readlineStdout = readline.createInterface(childProcess.stdout);
readlineStdout.on("line", data => {
serverObject.events.emit("log", data);
serverObject.events.emit("log_stdout", data)
});
const readlineStderr = readline.createInterface(childProcess.stderr);
readlineStderr.on("line", data => {
serverObject.events.emit("log", data);
serverObject.events.emit("log_stderr", data);
});
// Register hooks
// Server avaible to player
if (options.hooks.serverStarted) {
actionsDebug("Register server started function to %s", options.id);
function started(data: string) {
return options.hooks.serverStarted(data, onAvaible => {
actionsDebug("Call server started function to %s", options.id);
if (serverObject.serverStarted) return;
serverObject.serverStarted = onAvaible;
serverObject.events.emit("serverStarted", onAvaible);
});
}
readlineStderr.on("line", started);
readlineStdout.on("line", started);
}
// Server Player actions
if (options.hooks.playerAction) {
function updateHistoric(action: playerHistoric[0]["action"], data: playerBase) {
if (!serverObject.playerActions[data.playerName]) {
serverObject.playerActions[data.playerName] = {
action,
date: data.connectTime,
history: [
{
action,
date: data.connectTime
}
]
};
return;
}
serverObject.playerActions[data.playerName].action = action;
serverObject.playerActions[data.playerName].date = data.connectTime;
serverObject.playerActions[data.playerName].history.push({
action,
date: data.connectTime
});
}
actionsDebug("Register player actions to %s", options.id);
const playerConnect = (data: playerBase) => {
actionsDebug("Player actions to %s, call connect", options.id);
serverObject.events.emit("playerConnect", data);
updateHistoric("connect", data);
}
const playerSpawn = (data: playerBase) => {
actionsDebug("Player actions to %s, call spawn", options.id);
serverObject.events.emit("playerSpawn", data);
updateHistoric("spawn", data);
}
const playerDisonnect = (data: playerBase) => {
actionsDebug("Player actions to %s, call disconnect", options.id);
serverObject.events.emit("playerDisconnect", data);
updateHistoric("disconnect", data);
}
const playerUnknown = (data: playerBase) => {
actionsDebug("Player actions to %s, call unknown", options.id);
serverObject.events.emit("playerUnknown", data);
updateHistoric("unknown", data);
}
const mainFunc = (data: string) => options.hooks.playerAction(data, {
connect: playerConnect,
disconnect: playerDisonnect,
unknown: playerUnknown,
spawn: playerSpawn
});
readlineStdout.on("line", mainFunc);
readlineStderr.on("line", mainFunc);
}
// Port listen
if (options.hooks.portListening) {
actionsDebug("Register port listening to %s", options.id);
const mainFunc = (data: string) => options.hooks.portListening(data, (portData) => {
actionsDebug("Port listen to %s", options.id);
serverObject.events.emit("portListening", portData);
serverObject.portListening[portData.port] = portData;
})
readlineStdout.on("line", mainFunc);
readlineStderr.on("line", mainFunc);
}
// Pipe logs
if (processConfig.options.logPath) {
actionsDebug("Pipe log to file in %s", options.id);
childProcess.stdout.pipe(fs.createWriteStream(processConfig.options.logPath.stdout));
if (processConfig.options.logPath.stderr) childProcess.stderr.pipe(fs.createWriteStream(processConfig.options.logPath.stderr));
}
// Add listeners to actions events
childProcess.on("error", data => serverObject.events.emit("error", data));
childProcess.on("exit", (code, signal) => serverObject.events.emit("exit", {code, signal}));
childProcess.on("exit", () => serverObject.events.removeAllListeners());
// Return session maneger
return serverObject;
}

View File

@ -1,33 +1,3 @@
// Utils
import * as platformPathManeger from "./platformPathManeger.js"
import * as globalPlatfroms from "./globalPlatfroms.js";
import * as pluginManeger from "./plugin/plugin.js";
import * as export_import from "./export_import.js";
import * as pluginHooks from "./plugin/hook.js";
import * as proxy from "./lib/proxy.js";
// Platforms
import * as Bedrock from "./Platforms/bedrock.js";
import * as Java from "./Platforms/java.js";
import * as PocketmineMP from "./Platforms/pocketmine.js";
import * as Spigot from "./Platforms/spigot.js";
import * as Powernukkit from "./Platforms/pwnuukit.js";
import * as PaperMC from "./Platforms/paper.js";
export {platformPathManeger, globalPlatfroms, pluginManeger, export_import, PocketmineMP, pluginHooks, Powernukkit, PaperMC, Bedrock, Spigot, proxy, Java};
export default {
Bedrock,
Java,
PocketmineMP,
Powernukkit,
PaperMC,
Spigot,
utils: {
platformPathManeger,
globalPlatfroms,
pluginManeger,
pluginHooks,
export_import,
proxy
}
};
export * as serverManeger from "./serverManeger.js";
export * as Bedrock from "./platform/Bedrock.js";
export * as Java from "./platform/Java.js";

204
src/platform/Bedrock.ts Normal file
View File

@ -0,0 +1,204 @@
import { createServerManeger, platformPathID, pathOptions, serverConfig } from "../serverManeger.js";
import { promises as fs, createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";
import coreUtils, { childPromisses } from "@sirherobrine23/coreutils";
import { promisify } from "node:util";
import path from "node:path";
import tar from "tar";
import AdmZip from "adm-zip";
export type bedrockRootOption = pathOptions & {
variant?: "oficial"|"Pocketmine-PMMP"|"Powernukkit"|"Cloudbust"
};
const oracleBucket = await coreUtils.oracleBucket("sa-saopaulo-1", "bdsFiles", "grwodtg32n4d", "0IKM-5KFpAF8PuWoVe86QFsF4sipU2rXfojpaOMEdf4QgFQLcLlDWgMSPHWmjf5W");
const hostArchEmulate = [
"qemu-x86_64-static",
"qemu-x86_64",
"box64"
];
type bedrockVersionJSON = {
version: string,
date: Date,
release?: "stable"|"preview",
url: {
[platform in NodeJS.Platform]?: {
[arch in NodeJS.Architecture]?: string
}
}
};
async function getPHPBin(options?: bedrockRootOption) {
options = {variant: "oficial", ...options};
const serverPath = await platformPathID("bedrock", options);
const binFolder = path.join(serverPath.serverPath, "bin");
const files = await coreUtils.extendFs.readdir({folderPath: binFolder});
const file = files.filter((v) => v.endsWith("php.exe")||v.endsWith("php")).at(0);
if (!file) throw new Error("PHP Bin not found");
return file;
}
export async function installServer(version: string, options?: bedrockRootOption) {
options = {variant: "oficial", ...options};
const serverPath = await platformPathID("bedrock", options);
if (options?.variant === "Pocketmine-PMMP") {
const phpBin = (await oracleBucket.fileList()).filter(({name}) => name.startsWith("/php_bin/")).filter(({name}) => name.includes(process.platform) && name.includes(process.arch)).at(0);
if (!phpBin) throw new Error("PHP Bin not found");
const binFolder = path.join(serverPath.serverPath, "bin");
if (await coreUtils.extendFs.exists(binFolder)) await fs.rm(binFolder, {recursive: true});
await fs.mkdir(binFolder);
await pipeline(await oracleBucket.getFileStream(phpBin.name), createWriteStream(path.join(binFolder, "phpTmp")));
if (phpBin.name.endsWith(".tar.gz")) {
await tar.extract({
file: path.join(binFolder, "phpTmp"),
cwd: binFolder
});
} else if (phpBin.name.endsWith(".zip")) {
await promisify((new AdmZip(path.join(binFolder, "phpTmp"))).extractAllToAsync)(binFolder, true, true);
}
await fs.rm(path.join(binFolder, "phpTmp"));
const phpBinPath = await getPHPBin(options);
await coreUtils.childPromisses.execFile(phpBinPath, ["--version"]);
const rel = await (await coreUtils.httpRequestGithub("pmmp", "PocketMine-MP")).getRelease();
const relData = version.trim().toLowerCase() === "latest" ? rel.at(0) : rel.find((v) => v.tag_name === version.trim());
if (!relData) throw new Error("Version not found");
const phpAsset = relData.assets.find((a) => a.name.endsWith(".phar"))?.browser_download_url;
if (!phpAsset) throw new Error("PHP asset not found");
await coreUtils.httpRequestLarge.saveFile({url: phpAsset, filePath: path.join(serverPath.serverPath, "PocketMine-MP.phar")});
return {
version: relData.tag_name,
releaseDate: new Date(relData.published_at),
release: (relData.prerelease ? "preview" : "stable") as "preview"|"stable",
url: phpAsset,
phpBin: phpBin.name,
};
} else if (options?.variant === "Powernukkit") {
const versions = await coreUtils.httpRequest.fetchJSON<{version: string, mcpeVersion: string, date: string, url: string, variantType: "snapshot"|"stable"}[]>("https://mcpeversion-static.sirherobrine23.org/powernukkit/all.json");
const versionData = version.trim().toLowerCase() === "latest" ? versions.at(-1) : versions.find((v) => v.version === version.trim() || v.mcpeVersion === version.trim());
if (!versionData) throw new Error("Version not found");
const url = versionData.url;
if (!url) throw new Error("Platform not supported");
await coreUtils.httpRequestLarge.saveFile({url, filePath: path.join(serverPath.serverPath, "server.jar")});
return {
version: versionData.version,
mcpeVersion: versionData.mcpeVersion,
variantType: versionData.variantType,
releaseDate: new Date(versionData.date),
url,
};
} else if (options?.variant === "Cloudbust") {
throw new Error("Not implemented");
} else {
const versions = await coreUtils.httpRequest.fetchJSON<bedrockVersionJSON[]>("https://the-bds-maneger.github.io/BedrockFetch/all.json");
const versionData = version.trim().toLowerCase() === "latest" ? versions.at(-1) : versions.find((v) => v.version === version.trim());
if (!versionData) throw new Error("Version not found");
let currentPlatform = process.platform;
if (currentPlatform === "android") currentPlatform = "linux";
const url = versionData.url[currentPlatform]?.[process.arch];
if (!url) throw new Error("Platform not supported");
await coreUtils.httpRequestLarge.extractZip({url, folderTarget: serverPath.serverPath});
return {
version: versionData.version,
releaseDate: new Date(versionData.date),
release: versionData.release ?? "stable",
url: url
}
}
}
export async function startServer(options?: bedrockRootOption) {
// Bad fix options
options = {variant: "oficial", ...options};
const serverPath = await platformPathID("bedrock", options);
// Server Object
const serverExec: serverConfig = {
exec: {
cwd: serverPath.serverPath,
},
actions: {}
};
if (options?.variant === "Pocketmine-PMMP") {
serverExec.exec.exec = await getPHPBin();
serverExec.exec.args = ["PocketMine-MP.phar", "--no-wizard"];
serverExec.actions = {
stopServer(child_process) {
child_process.stdin.write("stop\n");
},
onStart(lineData, fnRegister) {
if (!(lineData.includes("INFO") && lineData.includes("Done") && lineData.includes("help"))) return;
const doneStart = new Date();
fnRegister({
serverAvaible: doneStart,
bootUp: runStart.getTime() - doneStart.getTime()
});
},
};
} else if (options?.variant === "Powernukkit") {
} else if (options?.variant === "Cloudbust") {
} else {
if (process.platform === "win32") serverExec.exec.exec = "bedrock_server.exe";
else if (process.platform === "darwin") throw new Error("MacOS is not supported, run in Docker or Virtual Machine");
else {
serverExec.exec.exec = path.join(serverPath.serverPath, "bedrock_server");
serverExec.exec.env = {
LD_LIBRARY_PATH: serverPath.serverPath
};
}
if ((["android", "linux"]).includes(process.platform) && process.arch !== "x64") {
const exec = serverExec.exec.exec;
serverExec.exec.exec = undefined;
for (const command of hostArchEmulate) {
if (await childPromisses.commandExists(command, true)) {
serverExec.exec.args = [exec];
serverExec.exec.exec = command;
break;
}
if (!serverExec.exec.exec) throw new Error("No emulator found for this platform");
}
}
const startTest = /\[.*\]\s+Server\s+started\./;
// Server actions
serverExec.actions = {
stopServer(child_process) {
child_process.stdin.write("stop\n");
},
onStart(lineData, fnRegister) {if (startTest.test(lineData)) fnRegister({serverAvaible: new Date()});},
playerActions(lineData, fnRegister) {
const playerActionsV1 = /\[.*\]\s+Player\s+((dis|)connected):\s+(.*),\s+xuid:\s+([0-9]+)/;
const newPlayerActions = /\[.*INFO\]\s+Player\s+(Spawned|connected|disconnected):\s+([\s\S\w]+)\s+(xuid:\s+([0-9]+))?/;
const connectTime = new Date();
if (!(newPlayerActions.test(lineData)||playerActionsV1.test(lineData))) return;
let playerName: string, action: string, xuid: string;
if (newPlayerActions.test(lineData)) {
const [, actionV2,, playerNameV2,, xuidV2] = lineData.match(newPlayerActions);
playerName = playerNameV2;
action = actionV2;
xuid = xuidV2;
} else {
const [, actionV1,, playerNameV1, xuidV1] = lineData.match(newPlayerActions);
playerName = playerNameV1;
action = actionV1;
xuid = xuidV1;
}
fnRegister({
player: playerName,
action: action === "Spawned" ? "spawned" : action === "connected" ? "join" : "leave",
actionDate: connectTime,
sessionID: serverPath.id,
more: {
xuid
}
});
},
};
}
const runStart = new Date();
return createServerManeger(serverExec);
}

14
src/platform/Java.ts Normal file
View File

@ -0,0 +1,14 @@
import { pathOptions } from "../serverManeger.js";
export type javaRootOption = pathOptions & {
variant?: "oficial"|"Spigot"|"Paper"|"Purpur",
};
export async function installServer(options?: javaRootOption) {
options = {variant: "oficial", ...options};
if (options?.variant === "Paper") {}
}
export default startServer;
export async function startServer(options?: javaRootOption) {}

View File

@ -1,142 +0,0 @@
import { extendFs } from "@sirherobrine23/coreutils";
import crypto from "node:crypto";
import path from "node:path";
import fs from "node:fs/promises";
import os from "node:os";
export let bdsRoot = process.env.BDS_HOME?(process.env.BDS_HOME.startsWith("~")?process.env.BDS_HOME.replace("~", os.homedir()):process.env.BDS_HOME):path.join(os.homedir(), ".bdsManeger");
export type bdsPlatform = "bedrock"|"java"|"pocketmine"|"spigot"|"powernukkit"|"paper";
export type bdsPlatformOptions = {
newId?: boolean,
id?: "default"|string,
withBuildFolder?: boolean
};
// This array to valida platform imput!
const platformArray: bdsPlatform[] = [
"bedrock",
"java",
"pocketmine",
"spigot",
"powernukkit",
"paper"
];
// Test ID
const idRegex = /^[A-Za-z0-9]*$/;
/**
* Register or get folder to Servers, this is to create and maneger folders
* @param platform - Select platform to maneger folders
* @param options - ?
*/
export async function pathControl(platform: bdsPlatform, options?: bdsPlatformOptions) {
if (!platformArray.includes(platform)) throw new Error("Invalid platform");
const platformRoot = path.join(bdsRoot, platform);
if (!await extendFs.exists(platformRoot)) await fs.mkdir(platformRoot, {recursive: true});
if (!options) options = {};
// Create if not exists
const foldersAndLink = await fs.readdir(platformRoot);
if (foldersAndLink.length === 0) options.newId = true;
if (options.newId) {
options.id = crypto.randomBytes(16).toString("hex");
fs.mkdir(path.join(platformRoot, options.id), {recursive: true});
if (await extendFs.exists(path.join(platformRoot, "default"))) await fs.unlink(path.join(platformRoot, "default"));
await fs.symlink(path.join(platformRoot, options.id), path.join(platformRoot, "default"));
} else if (!await extendFs.exists(path.join(platformRoot, options.id))) throw new Error("Folder ID not created!");
// Get real id
if (!idRegex.test(options.id)) throw new Error("Invalid Platform ID");
if (options?.id === "default") options.id = path.basename(await fs.realpath(path.join(platformRoot, options.id)).catch(async () => (await fs.readdir(platformRoot)).sort().at(0)));
// Mount Paths
const serverRoot = path.join(platformRoot, options.id);
const serverPath = path.join(serverRoot, "server");
const hooksPath = path.join(serverRoot, "hooks");
const backupPath = path.join(serverRoot, "backup");
const logsPath = path.join(serverRoot, "logs");
let buildFolder: string;
if (options?.withBuildFolder) buildFolder = path.join(serverRoot, "build");
// Create folder if not exists
if (!(await extendFs.exists(serverRoot))) await fs.mkdir(serverRoot, {recursive: true});
if (!(await extendFs.exists(serverPath))) await fs.mkdir(serverPath, {recursive: true});
if (!(await extendFs.exists(hooksPath))) await fs.mkdir(hooksPath, {recursive: true});
if (!(await extendFs.exists(backupPath))) await fs.mkdir(backupPath, {recursive: true});
if (!(await extendFs.exists(logsPath))) await fs.mkdir(logsPath, {recursive: true});
if (buildFolder && !(await extendFs.exists(buildFolder))) await fs.mkdir(buildFolder, {recursive: true});
return {
id: options?.id,
serverRoot,
serverPath,
hooksPath,
backupPath,
logsPath,
buildFolder,
platformIDs: foldersAndLink
};
}
/**
* Change default folder to Platform
* @param platform
* @param id
* @returns
*/
export async function changeDefault(platform: bdsPlatform, id: bdsPlatformOptions["id"]) {
if (!platformArray.includes(platform)) throw new Error("Invalid platform");
const serverPlatform = path.join(bdsRoot, platform);
if (!await extendFs.exists(serverPlatform)) throw new Error("Install server fist!");
const ids = (await fs.readdir(serverPlatform)).filter(folder => folder.toLowerCase() !== "default");
if (!ids.includes(id)) throw new Error("Id not exists to Platform");
const oldPath = fs.realpath(path.join(bdsRoot, platform, "default"));
if (await extendFs.exists(path.join(bdsRoot, platform, "default"))) await fs.unlink(path.join(bdsRoot, platform, "default"));
await fs.symlink(path.join(bdsRoot, platform, id), path.join(bdsRoot, platform, "default"));
return {
oldPath,
newPath: path.join(bdsRoot, platform, id)
};
}
export type platformIds = {
[platform in bdsPlatform]?: {
realID?: string,
id: string,
}[]
};
/**
* Get all ids to all platforms installed
* @returns
*/
export async function getIds(): Promise<platformIds>;
/**
* Get all ids to platform
* @param platform - Set platform to get ids
* @returns
*/
export async function getIds(platform: bdsPlatform): Promise<string[]>;
export async function getIds(platform?: bdsPlatform): Promise<platformIds|string[]> {
if (!platform) {
const platformIds: platformIds = {};
if (!await extendFs.exists(bdsRoot)) return platformIds;
const Platforms = (await fs.readdir(bdsRoot)).filter(folder => platformArray.includes(folder as bdsPlatform));
await Promise.all(Platforms.map(async Platform => {
for (const id of await fs.readdir(path.join(bdsRoot, Platform))) {
if (!platformIds[Platform]) platformIds[Platform] = []
const idPlatform = path.join(bdsRoot, Platform, id);
const realPath = await fs.realpath(idPlatform);
if (idPlatform !== realPath) platformIds[Platform].push({id, realID: path.basename(realPath)});
else platformIds[Platform].push({id});
}
}));
return platformIds;
}
if (!platformArray.includes(platform)) throw new Error("Invalid platform");
const serverPlatform = path.join(bdsRoot, platform);
if (!await extendFs.exists(serverPlatform)) throw new Error("Install server fist!");
return (await fs.readdir(serverPlatform)).filter(folder => folder.toLowerCase() !== "default");
}

View File

@ -1,82 +0,0 @@
import { httpRequestLarge, childPromisses } from "@sirherobrine23/coreutils";
import { actionsV2 } from "../globalPlatfroms.js";
import path from "node:path";
import fs from "node:fs/promises";
export type hooksPlatform = "bedrock"|"java"|"pocketmine"|"spigot"|"powernukkit"|"paper";
export type hooksPlatformGeneric = hooksPlatform|"generic";
export type hooksRegister = {
scriptName: string,
platforms: hooksPlatformGeneric[],
register: (actions: actionsV2) => void,
};
async function exists(path: string) {
return fs.access(path).then(() => true).catch(() => false);
}
const gitUrlDetect = /(^http:\/\/.*\.git$|^http:\/\/.*.git$|^git:\/\/)/;
export class script_hook {
#serverActions: actionsV2;
#currentPlatform: hooksPlatformGeneric;
#localFolder: string;
async #registerScript(filePath: string) {
const lo_script = (await(eval(`import("${filePath}")`))) as hooksRegister|{default: hooksRegister};
let script: hooksRegister;
if (lo_script["default"]) script = lo_script["default"];
else script = lo_script as hooksRegister;
console.log(script);
if (!script.scriptName) throw new Error("Scriptname in null");
if (!script.register) throw new Error("Register not is function");
if (!(script.platforms.includes("generic")||script.platforms.includes(this.#currentPlatform))) throw new Error(`Cannot get valid platform (${this.#currentPlatform}) (${script.platforms?.join(", ")})`);
const { scriptName, register } = script;
console.log("Loading hook %s (External)", scriptName);
return (Promise.resolve().then(() => register(this.#serverActions))).then(() => console.log("hook %s loaded (External)", scriptName));
};
async #loadLocalScript() {
if (!this.#serverActions) throw new Error("Server actions (globalPlatform) is undefined");
if (!await exists(this.#localFolder)) await fs.mkdir(this.#localFolder, {recursive: true});
const localFiles = (await fs.readdir(this.#localFolder)).map(file => path.join(this.#localFolder, file));
for (const localFile of localFiles) {
await fs.lstat(localFile).then(async stat => {
if (stat.isFile()) return this.#registerScript(localFile);
if (await exists(path.join(localFile, "package.json"))) {
const externalHookPackage = JSON.parse(await fs.readFile(path.join(localFile, "package.json"), "utf8"));
let indexFile: string;
if (externalHookPackage.main) indexFile = path.join(localFile, externalHookPackage.main);
else {
const files = (await fs.readdir(localFile)).filter(file => /index\.(js|cjs|mjs)$/.test(file));
if (files.length === 0) throw new Error("no index files");
indexFile = path.join(localFile, files[0]);
}
if (!indexFile) throw new Error("No file to init");
return this.#registerScript(indexFile);
}
throw new Error("Know know, boom!");
}).catch(err => console.error(String(err)));
}
}
public async installHook(urlHost: string, fileName?: string) {
if (!await exists(this.#localFolder)) await fs.mkdir(this.#localFolder, {recursive: true});
if (!fileName) fileName = path.basename(urlHost);
const onSave = path.join(this.#localFolder, fileName);
// Git
if (gitUrlDetect.test(urlHost)) {
await childPromisses.execFile("git", ["clone", urlHost, "--depth", "1", onSave], {cwd: this.#localFolder});
if (await exists(path.join(onSave, "package.json"))) await childPromisses.execFile("npm", ["install", "--no-save"], {cwd: onSave});
} else await httpRequestLarge.saveFile({url: urlHost, filePath: onSave});
if (!!this.#serverActions) await this.#registerScript(onSave);
return;
}
constructor(hookFolder: string, targetPlatform: hooksPlatform, platformActions?: actionsV2) {
this.#serverActions = platformActions;
this.#currentPlatform = targetPlatform;
this.#localFolder = hookFolder;
if (platformActions) this.#loadLocalScript();
}
}

View File

@ -1,61 +0,0 @@
import path from "node:path";
import type { bdsPlatform } from "../platformPathManeger.js";
import { httpRequest, httpRequestLarge } from "@sirherobrine23/coreutils";
export type pluginConfig = {
version?: 1,
name: string,
url: string,
fileName?: string,
platforms: bdsPlatform[],
dependecies?: string[],
/** @deprecated */
scripts?: string[],
};
export type pluginV2 = {
version: 2,
name: string,
pluginVersion?: string,
platform: {
[platform: string]: {
url: string,
fileName?: string,
dependencies?: string[]
}
}
};
export class pluginManeger {
#pluginFolder: string;
#platform: bdsPlatform;
constructor(pluginFolder: string, options?: {
bdsPlatfrom: bdsPlatform
}) {
this.#pluginFolder = pluginFolder;
this.#platform = options?.bdsPlatfrom;
}
async installPlugin(plugin: string) {
const urlandbds = /http[s]:\/\/|bdsplugin:\/\//;
if (/bdsplugin:\/\//.test(plugin)) plugin = `https://raw.githubusercontent.com/The-Bds-Maneger/plugin_list/main/plugins/${plugin.replace(urlandbds, "").replace(".json", "")}.json`;
else if (!/http[s]:\/\/\//.test(plugin)) plugin = "bdsplugin://"+plugin;
const info = await httpRequest.getJSON<pluginConfig|pluginV2>(plugin);
if (info.version === 2) {
const platformData = info.platform[this.#platform];
if (!platformData) throw new Error("Platform not supported to Plugin!");
await httpRequestLarge.saveFile({
url: platformData.url,
filePath: path.join(this.#pluginFolder, platformData.fileName||path.basename(platformData.url))
});
if (platformData.dependencies) await Promise.all(platformData.dependencies.map(dep => this.installPlugin(dep)));
return;
}
if (!info.platforms.includes(this.#platform)) throw new Error("Platform not supported to Plugin!");
await httpRequestLarge.saveFile({
url: info.url,
filePath: path.join(this.#pluginFolder, info.fileName||path.basename(info.url))
});
if (info.dependecies) await Promise.all(info.dependecies.map(dep => this.installPlugin(dep)));
}
};

192
src/serverManeger.ts Normal file
View File

@ -0,0 +1,192 @@
import { createInterface as readline } from "node:readline";
import { promises as fs } from "node:fs";
import child_process, { ChildProcess } from "node:child_process";
import { extendFs } from "@sirherobrine23/coreutils";
import crypto from "node:crypto";
import path from "node:path";
import os from "node:os";
import EventEmitter from "node:events";
export type pathOptions = {
id?: "default"|string,
newId?: boolean,
withBuildFolder?: boolean,
};
export let bdsRoot = process.env.BDS_HOME?(process.env.BDS_HOME.startsWith("~")?process.env.BDS_HOME.replace("~", os.homedir()):process.env.BDS_HOME):path.join(os.homedir(), ".bdsManeger");
export async function platformPathID(platform: "bedrock"|"java", options?: pathOptions) {
if (!(["bedrock", "java"].includes(platform))) throw new Error("Invalid platform target");
options = {id: "default", ...options};
const platformRoot = path.join(bdsRoot, platform);
if (!await extendFs.exists(platformRoot)) await fs.mkdir(platformRoot, {recursive: true});
if (!options) options = {};
// Create if not exists
const foldersAndLink = await fs.readdir(platformRoot);
if (foldersAndLink.length === 0) options.newId = true;
if (options.newId) {
options.id = crypto.randomBytes(16).toString("hex");
fs.mkdir(path.join(platformRoot, options.id), {recursive: true});
if (await extendFs.exists(path.join(platformRoot, "default"))) await fs.unlink(path.join(platformRoot, "default"));
await fs.symlink(path.join(platformRoot, options.id), path.join(platformRoot, "default"));
} else if (!await extendFs.exists(path.join(platformRoot, options.id))) throw new Error("Folder ID not created!");
// Get real id
if (!(/^[A-Za-z0-9]*$/).test(options.id)) throw new Error("Invalid Platform ID");
if (options?.id === "default") options.id = path.basename(await fs.realpath(path.join(platformRoot, options.id)).catch(async () => (await fs.readdir(platformRoot)).sort().at(0)));
// Mount Paths
const serverRoot = path.join(platformRoot, options.id);
const serverPath = path.join(serverRoot, "server");
const hooksPath = path.join(serverRoot, "hooks");
const backupPath = path.join(serverRoot, "backup");
const logsPath = path.join(serverRoot, "logs");
let buildFolder: string;
if (options?.withBuildFolder) buildFolder = path.join(serverRoot, "build");
// Create folder if not exists
if (!(await extendFs.exists(serverRoot))) await fs.mkdir(serverRoot, {recursive: true});
if (!(await extendFs.exists(serverPath))) await fs.mkdir(serverPath, {recursive: true});
if (!(await extendFs.exists(hooksPath))) await fs.mkdir(hooksPath, {recursive: true});
if (!(await extendFs.exists(backupPath))) await fs.mkdir(backupPath, {recursive: true});
if (!(await extendFs.exists(logsPath))) await fs.mkdir(logsPath, {recursive: true});
if (buildFolder && !(await extendFs.exists(buildFolder))) await fs.mkdir(buildFolder, {recursive: true});
return {
id: options?.id,
serverRoot,
serverPath,
hooksPath,
backupPath,
logsPath,
buildFolder,
platformIDs: foldersAndLink
};
}
export type playerAction = ({action: "join"|"spawned"|"leave"}|{
action: "kick"|"ban",
reason?: string,
by?: string
}) & {
player: string,
actionDate: Date,
sessionID: string
more?: any,
latestAction?: playerAction
}
export type serverConfig = {
exec: {
exec?: string,
args?: string[],
cwd?: string,
env?: NodeJS.ProcessEnv & {[key: string]: string},
},
actions?: {
stopServer?: (child_process: ChildProcess) => void,
onStart?: (lineData: string, fnRegister: (data?: {serverAvaible?: Date, bootUp?: number}) => void) => void,
playerActions?: (lineData: string, fnRegister: (data: playerAction) => void) => void,
}
};
declare class serverManeger extends EventEmitter {
on(event: "error", fn: (lineLog: any) => void): this;
once(event: "error", fn: (lineLog: any) => void): this;
emit(event: "error", data: any): boolean;
on(event: "log", fn: (lineLog: string) => void): this;
once(event: "log", fn: (lineLog: string) => void): this;
emit(event: "log", data: string): boolean;
on(event: "rawLog", fn: (raw: any) => void): this;
once(event: "rawLog", fn: (raw: any) => void): this;
emit(event: "rawLog", data: any): boolean;
// Player actions
on(event: "playerAction", fn: (playerAction: playerAction) => void): this;
once(event: "playerAction", fn: (playerAction: playerAction) => void): this;
emit(event: "playerAction", data: playerAction): boolean;
// Server started
on(event: "serverStarted", fn: (data: {serverAvaible: Date, bootUp: number}) => void): this;
once(event: "serverStarted", fn: (data: {serverAvaible: Date, bootUp: number}) => void): this;
emit(event: "serverStarted", data: {serverAvaible: Date, bootUp: number}): boolean;
}
export async function createServerManeger(serverOptions: serverConfig): Promise<serverManeger> {
const serverExec = child_process.execFile(serverOptions.exec.exec, serverOptions.exec.args ?? [], {
cwd: serverOptions.exec.cwd,
windowsHide: true,
maxBuffer: Infinity,
env: {
...process.env,
...serverOptions.exec.env
},
});
const playerActions: playerAction[] = [];
const internalEvent = new class serverManeger extends EventEmitter {
stopServer() {
const stopServer = serverOptions.actions?.stopServer ?? ((child_process) => child_process.kill("SIGKILL"));
stopServer(serverExec);
}
getPlayers() {
return playerActions ?? [];
}
};
serverExec.on("error", internalEvent.emit.bind(internalEvent, "error"));
const stdoutReadline = readline({input: serverExec.stdout});
stdoutReadline.on("line", (line) => internalEvent.emit("log", line));
stdoutReadline.on("error", internalEvent.emit.bind(internalEvent, "error"));
serverExec.stdout.on("data", (data) => internalEvent.emit("rawLog", data));
const stderrReadline = readline({input: serverExec.stderr});
stderrReadline.on("line", (line) => internalEvent.emit("log", line));
stderrReadline.on("error", internalEvent.emit.bind(internalEvent, "error"));
serverExec.stderr.on("data", (data) => internalEvent.emit("rawLog", data));
// Server start
if (serverOptions.actions?.onStart) {
const serverStartFN = serverOptions.actions.onStart;
let lock = false;
const started = new Date();
function register(data?: {serverAvaible?: Date, bootUp?: number}) {
if (lock) return;
const eventData = {
serverAvaible: data?.serverAvaible ?? new Date(),
bootUp: data?.bootUp ?? new Date().getTime() - started.getTime()
};
internalEvent.emit("serverStarted", eventData);
lock = true;
stderrReadline.removeListener("line", register);
stdoutReadline.removeListener("line", register);
// emit and remove new listener for serverStarted
internalEvent.removeAllListeners("serverStarted");
internalEvent.prependListener("serverStarted", () => {
internalEvent.emit("serverStarted", eventData);
internalEvent.removeAllListeners("serverStarted");
});
}
stdoutReadline.on("line", (line) => serverStartFN(line, register));
stderrReadline.on("line", (line) => serverStartFN(line, register));
}
// Player actions
if (serverOptions.actions?.playerActions) {
const playerFn = serverOptions.actions.playerActions;
const registerData = (data: playerAction) => {
const player = playerActions.find((player) => player.player === data.player);
if (!player) playerActions.push(data);
else {
data.latestAction = player;
playerActions[playerActions.indexOf(player)] = data;
}
internalEvent.emit("playerAction", data);
}
stdoutReadline.on("line", (line) => playerFn(line, registerData));
stderrReadline.on("line", (line) => playerFn(line, registerData));
}
return internalEvent;
}