diff --git a/docs/jsdoc.json b/docs/jsdoc.json
deleted file mode 100644
index 777c03a5..00000000
--- a/docs/jsdoc.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "plugins": [
- "plugins/markdown"
- ],
- "tags": {
- "allowUnknownTags": false
- },
- "opts": {
- "destination": "docs/api",
- "recurse": true
- },
- "source": {
- "include": [
- "packages/controller/src/",
- "packages/controller/controller.js",
- "packages/host/src/",
- "packages/host/host.js",
- "packages/ctl/src/",
- "packages/ctl/ctl.js",
- "packages/lib/",
- "plugins/"
- ],
- "excludePattern": "node_modules"
- }
-}
diff --git a/package.json b/package.json
index 67323b9e..7ff3a61b 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
"ci-cover": "nyc --reporter=lcovonly pnpm run-script test",
"lint": "eslint \"*.js\" packages plugins test",
"lint-fix": "eslint --fix \"*.js\" packages plugins test",
- "docs": "jsdoc --configure docs/jsdoc.json",
+ "docs": "typedoc",
"bundle-dependencies": "bundle-dependencies"
},
"nyc": {
@@ -31,11 +31,11 @@
"express": "^4.18.2",
"form-data": "^4.0.0",
"fs-extra": "^11.1.1",
- "jsdoc": "^4.0.2",
"jsonwebtoken": "^9.0.1",
"jszip": "^3.10.0",
"mocha": "^10.2.0",
"nyc": "^15.1.0",
- "phin": "^3.7.0"
+ "phin": "^3.7.0",
+ "typedoc": "^0.24.8"
}
}
diff --git a/packages/controller/src/ControlConnection.js b/packages/controller/src/ControlConnection.js
index d14bb5e7..ee446c8f 100644
--- a/packages/controller/src/ControlConnection.js
+++ b/packages/controller/src/ControlConnection.js
@@ -248,7 +248,7 @@ class ControlConnection extends BaseConnection {
async handleHostGenerateTokenRequest(message) {
let hostId = message.host_id;
- if (hostId === null) {
+ if (hostId === undefined) {
hostId = Math.random() * 2**31 | 0;
}
return this._controller.generateHostToken(hostId);
@@ -279,7 +279,7 @@ class ControlConnection extends BaseConnection {
instance.config.get("instance.name"),
instance.id,
instance.config.get("instance.assigned_host"),
- instance.game_port || null,
+ instance.game_port || undefined,
instance.status,
);
}
@@ -290,8 +290,8 @@ class ControlConnection extends BaseConnection {
list.push(new lib.InstanceDetails(
instance.config.get("instance.name"),
instance.id,
- instance.config.get("instance.assigned_host"),
- instance.game_port || null,
+ instance.config.get("instance.assigned_host") || undefined,
+ instance.game_port || undefined,
instance.status,
));
}
@@ -311,8 +311,8 @@ class ControlConnection extends BaseConnection {
new lib.InstanceDetails(
instance.config.get("instance.name"),
instance.id,
- instance.config.get("instance.assigned_host"),
- instance.game_port || null,
+ instance.config.get("instance.assigned_host") || undefined,
+ instance.game_port || undefined,
instance.status,
)
));
diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js
index 07c16fbc..4bdb33c5 100755
--- a/packages/ctl/ctl.js
+++ b/packages/ctl/ctl.js
@@ -83,7 +83,7 @@ class Control extends lib.Link {
controller = false,
hostIds = [],
instanceIds = [],
- maxLevel = null,
+ maxLevel = undefined,
}) {
await this.send(
new lib.LogSetSubscriptionsRequest(
@@ -286,7 +286,11 @@ async function startControl() {
process.exitCode = 1;
} else if (err instanceof lib.RequestError) {
- logger.error(`Error sending request:\n${err.stack}`);
+ if (err.stack) {
+ logger.error(`Error sending request:\n${err.stack}`);
+ } else {
+ logger.error(`Error sending request: ${err.message}`);
+ }
process.exitCode = 1;
} else {
@@ -315,6 +319,9 @@ I version of clusterio. Expect things to break. I
`
);
startControl().catch(err => {
+ if (err.errors) {
+ logger.fatal(JSON.stringify(err.errors, null, 4));
+ }
if (!(err instanceof lib.StartupError)) {
logger.fatal(`
+------------------------------------------------------------+
diff --git a/packages/ctl/src/commands.js b/packages/ctl/src/commands.js
index 35e675be..f3c5a9d1 100644
--- a/packages/ctl/src/commands.js
+++ b/packages/ctl/src/commands.js
@@ -237,9 +237,9 @@ hostCommands.add(new lib.Command({
yargs.option("id", { type: "number", nargs: 1, describe: "Host id" });
}],
handler: async function(args, control) {
- let hostId = typeof args.id === "number" ? args.id : null;
+ let hostId = typeof args.id === "number" ? args.id : undefined;
let response = await control.send(new lib.HostGenerateTokenRequest(hostId));
- print(response.token);
+ print(response);
},
}));
@@ -480,9 +480,9 @@ instanceCommands.add(new lib.Command({
}));
async function loadMapSettings(args) {
- let seed = args.seed !== undefined ? args.seed : null;
- let mapGenSettings = null;
- let mapSettings = null;
+ let seed = args.seed;
+ let mapGenSettings;
+ let mapSettings;
if (args.mapExchangeString) {
let parsed = lib.readMapExchangeString(args.mapExchangeString);
mapGenSettings = parsed.map_gen_settings;
@@ -1551,7 +1551,7 @@ logCommands.add(new lib.Command({
"controller": { describe: "Query log of the controller", nargs: 0, type: "boolean", default: false },
"host": { describe: "Query log of given host", nargs: 1, type: "string", default: null },
"instance": { describe: "Query log of given instance", nargs: 1, type: "string", default: null },
- "max-level": { describe: "Maximum log level to return", nargs: 1, type: "string", default: null },
+ "max-level": { describe: "Maximum log level to return", nargs: 1, type: "string", default: undefined },
"limit": { describe: "Max number of entries to return", nargs: 1, type: "number", default: 1000 },
"start": { describe: "Limit from the start instead of the end", nargs: 0, type: "boolean", default: false },
});
diff --git a/packages/host/src/Host.js b/packages/host/src/Host.js
index c92ddc0b..01852403 100644
--- a/packages/host/src/Host.js
+++ b/packages/host/src/Host.js
@@ -457,7 +457,7 @@ class Host extends lib.Link {
let instanceConnection = this.instanceConnections.get(instanceId);
this.send(
new lib.InstanceStatusChangedEvent(
- instanceId, instanceConnection ? instanceConnection.status : "stopped", null
+ instanceId, instanceConnection ? instanceConnection.status : "stopped", undefined
)
);
diff --git a/packages/host/src/Instance.js b/packages/host/src/Instance.js
index 2d19f98f..132873fc 100644
--- a/packages/host/src/Instance.js
+++ b/packages/host/src/Instance.js
@@ -438,7 +438,7 @@ rcon.print(game.table_to_json(players))`.replace(/\r?\n/g, " ");
new lib.InstanceStatusChangedEvent(
this.id,
status,
- this.server && this.server.gamePort || this.config.get("factorio.game_port") || null,
+ this.server && this.server.gamePort || this.config.get("factorio.game_port") || undefined,
),
);
}
diff --git a/packages/host/src/server.js b/packages/host/src/server.js
index 2237e7ae..73090b45 100644
--- a/packages/host/src/server.js
+++ b/packages/host/src/server.js
@@ -796,9 +796,11 @@ class FactorioServer extends events.EventEmitter {
[
"--config", this.writePath("config.ini"),
"--create", this.writePath("saves", name),
- ...(seed !== null ? ["--map-gen-seed", seed] : []),
- ...(mapGenSettings !== null ? ["--map-gen-settings", this.writePath("map-gen-settings.json")] : []),
- ...(mapSettings !== null ? ["--map-settings", this.writePath("map-settings.json")] : []),
+ /* eslint-disable eqeqeq, no-eq-null */
+ ...(seed != null ? ["--map-gen-seed", seed] : []),
+ ...(mapGenSettings != null ? ["--map-gen-settings", this.writePath("map-gen-settings.json")] : []),
+ ...(mapSettings != null ? ["--map-settings", this.writePath("map-settings.json")] : []),
+ /* eslint-enable eqeqeq, no-eq-null */
...(this.verboseLogging ? ["--verbose"] : []),
],
{
@@ -886,9 +888,11 @@ class FactorioServer extends events.EventEmitter {
[
"--config", this.writePath("config.ini"),
"--start-server-load-scenario", scenario,
- ...(seed !== null ? ["--map-gen-seed", seed] : []),
- ...(mapGenSettings !== null ? ["--map-gen-settings", this.writePath("map-gen-settings.json")] : []),
- ...(mapSettings !== null ? ["--map-settings", this.writePath("map-settings.json")] : []),
+ /* eslint-disable eqeqeq, no-eq-null */
+ ...(seed != null ? ["--map-gen-seed", seed] : []),
+ ...(mapGenSettings != null ? ["--map-gen-settings", this.writePath("map-gen-settings.json")] : []),
+ ...(mapSettings != null ? ["--map-settings", this.writePath("map-settings.json")] : []),
+ /* eslint-enable eqeqeq, no-eq-null */
"--port", this.gamePort,
"--rcon-port", this.rconPort,
"--rcon-password", this.rconPassword,
diff --git a/packages/lib/.gitignore b/packages/lib/.gitignore
deleted file mode 100644
index 922aef1f..00000000
--- a/packages/lib/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-src/data/message_validate.js
diff --git a/packages/lib/.npmignore b/packages/lib/.npmignore
deleted file mode 100644
index e69de29b..00000000
diff --git a/packages/lib/browser.js b/packages/lib/browser.js
index 29cce7f5..1f2d0428 100644
--- a/packages/lib/browser.js
+++ b/packages/lib/browser.js
@@ -1,15 +1,15 @@
-export * from "./src/config";
-export * from "./src/data";
-export * from "./src/errors";
-export * from "./src/factorio/exchange_string";
-export * from "./src/helpers";
-export * from "./src/ini";
-export * from "./src/link";
-export * from "./src/logging";
-export * from "./src/plugin";
-export * from "./src/schema";
-export * from "./src/users";
+export * from "./dist/src/config";
+export * from "./dist/src/data";
+export * from "./dist/src/errors";
+export * from "./dist/src/factorio/exchange_string";
+export * from "./dist/src/helpers";
+export * from "./dist/src/ini";
+export * from "./dist/src/link";
+export * from "./dist/src/logging";
+export * from "./dist/src/plugin";
+export * from "./dist/src/schema";
+export * from "./dist/src/users";
-export { default as ExponentialBackoff } from "./src/ExponentialBackoff";
-export { default as PlayerStats } from "./src/PlayerStats";
-export { default as RateLimiter } from "./src/RateLimiter";
+export { default as ExponentialBackoff } from "./dist/src/ExponentialBackoff";
+export { default as PlayerStats } from "./dist/src/PlayerStats";
+export { default as RateLimiter } from "./dist/src/RateLimiter";
diff --git a/packages/lib/index.js b/packages/lib/index.js
deleted file mode 100644
index 2fce1f00..00000000
--- a/packages/lib/index.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * Shared library for Clusterio
- * @module lib
- */
-"use strict";
-const libBuildMod = require("./build_mod");
-const libCommand = require("./src/command");
-const libConfig = require("./src/config");
-const libData = require("./src/data");
-const libDatabase = require("./src/database");
-const libErrors = require("./src/errors");
-const libFactorio = require("./src/factorio");
-const libFileOps = require("./src/file_ops");
-const libHash = require("./src/hash");
-const libHelpers = require("./src/helpers");
-const libIni = require("./src/ini");
-const libLink = require("./src/link");
-const libLogging = require("./src/logging");
-const libLoggingUtils = require("./src/logging_utils");
-const libLuaTools = require("./src/lua_tools");
-const libPlugin = require("./src/plugin");
-const libPluginLoader = require("./src/plugin_loader");
-const libPrometheus = require("./src/prometheus");
-const libSchema = require("./src/schema");
-const libSharedCommands = require("./src/shared_commands");
-const libStream = require("./src/stream");
-const libUsers = require("./src/users");
-const libZipOps = require("./src/zip_ops");
-
-const ExponentialBackoff = require("./src/ExponentialBackoff");
-const PlayerStats = require("./src/PlayerStats");
-const RateLimiter = require("./src/RateLimiter");
-
-
-module.exports = {
- ...libBuildMod,
- ...libCommand,
- ...libConfig,
- ...libData,
- ...libDatabase,
- ...libErrors,
- ...libFactorio,
- ...libFileOps,
- ...libHash,
- ...libHelpers,
- ...libIni,
- ...libLink,
- ...libLogging,
- ...libLoggingUtils,
- ...libLuaTools,
- ...libPlugin,
- ...libPluginLoader,
- ...libPrometheus,
- ...libSchema,
- ...libSharedCommands,
- ...libStream,
- ...libUsers,
- ...libZipOps,
-
- ExponentialBackoff,
- PlayerStats,
- RateLimiter,
-};
diff --git a/packages/lib/index.ts b/packages/lib/index.ts
new file mode 100644
index 00000000..14b567e0
--- /dev/null
+++ b/packages/lib/index.ts
@@ -0,0 +1,31 @@
+/**
+ * Shared library for Clusterio
+ * @module lib
+ */
+export * from "./build_mod";
+export * from "./src/command";
+export * from "./src/config";
+export * from "./src/data";
+export * from "./src/database";
+export * from "./src/errors";
+export * from "./src/factorio";
+export * from "./src/file_ops";
+export * from "./src/hash";
+export * from "./src/helpers";
+export * from "./src/ini";
+export * from "./src/link";
+export * from "./src/logging";
+export * from "./src/logging_utils";
+export * from "./src/lua_tools";
+export * from "./src/plugin";
+export * from "./src/plugin_loader";
+export * from "./src/prometheus";
+export * from "./src/schema";
+export * from "./src/shared_commands";
+export * from "./src/stream";
+export * from "./src/users";
+export * from "./src/zip_ops";
+
+export { default as ExponentialBackoff } from "./src/ExponentialBackoff";
+export { default as PlayerStats } from "./src/PlayerStats";
+export { default as RateLimiter } from "./src/RateLimiter";
diff --git a/packages/lib/package.json b/packages/lib/package.json
index ce052530..8bc6d749 100644
--- a/packages/lib/package.json
+++ b/packages/lib/package.json
@@ -5,9 +5,10 @@
"repository": "https://github.com/clusterio/clusterio",
"license": "MIT",
"scripts": {
- "prepare": "pnpm run compile_validator",
+ "prepare": "tsc --build && pnpm run compile_validator",
"compile_validator": "node scripts/compile_validator.js"
},
+ "main": "dist/index.js",
"browser": "browser.js",
"keywords": [
"factorio"
@@ -16,6 +17,7 @@
"node": ">=12"
},
"dependencies": {
+ "@sinclair/typebox": "^0.30.4",
"ajv": "^8.12.0",
"chalk": "^4.1.2",
"fast-deep-equal": "^3.1.3",
@@ -31,5 +33,12 @@
},
"publishConfig": {
"access": "public"
+ },
+ "devDependencies": {
+ "@types/fs-extra": "^11.0.1",
+ "@types/node": "^20.4.5",
+ "@types/triple-beam": "^1.3.2",
+ "@types/ws": "^8.5.5",
+ "typescript": "^5.1.6"
}
}
diff --git a/packages/lib/scripts/compile_validator.js b/packages/lib/scripts/compile_validator.js
index bc90dcf4..61421e01 100644
--- a/packages/lib/scripts/compile_validator.js
+++ b/packages/lib/scripts/compile_validator.js
@@ -7,9 +7,9 @@ const standaloneCode = require("ajv/dist/standalone").default;
/* eslint-disable node/no-sync */
// Provide an empty file for message_core to load
-fs.outputFileSync(path.join(__dirname, "../src/data/message_validate.js"), "");
+fs.outputFileSync(path.join(__dirname, "../dist/src/data/message_validate.js"), "");
-const { Message } = require("../src/data/messages_core");
+const { Message } = require("../dist/src/data/messages_core");
const ajv = new Ajv({
allowUnionTypes: true,
@@ -23,6 +23,6 @@ const ajv = new Ajv({
const validate = ajv.compile(Message.jsonSchema);
let moduleCode = standaloneCode(ajv, validate);
fs.outputFileSync(
- path.join(__dirname, "../src/data/message_validate.js"),
- `// generated by scripts/compile_validator.js\n/* eslint-disable */\n${moduleCode}`
+ path.join(__dirname, "../dist/src/data/message_validate.js"),
+ `// generated by scripts/compile_validator.js\n// @ts-nocheck\n/* eslint-disable */\n${moduleCode}`
);
diff --git a/packages/lib/src/ExponentialBackoff.js b/packages/lib/src/ExponentialBackoff.ts
similarity index 70%
rename from packages/lib/src/ExponentialBackoff.js
rename to packages/lib/src/ExponentialBackoff.ts
index 5af3033f..1e5550b5 100644
--- a/packages/lib/src/ExponentialBackoff.js
+++ b/packages/lib/src/ExponentialBackoff.ts
@@ -1,6 +1,3 @@
-"use strict";
-
-
/**
* Helper class for implementing the exponential backoff algorithm
*
@@ -14,49 +11,48 @@
* the passed value of `max`. The value for the delay will reset back to
* `base` if more time than the value for `reset` has passed between two
* invocations of delay.
- *
- * @alias module:lib.ExponentialBackoff
*/
-class ExponentialBackoff {
+export default class ExponentialBackoff {
+ /**
+ * Base delay in seconds. The first delay will on average be this
+ * long, but can be anywhere between 0 and 2 times this value.
+ */
+ base = 1;
+ /**
+ * Maximum delay in seconds. A delay will not take more than this
+ * value.
+ */
+ max = 60;
+ /**
+ * Time in seconds between two invocations of delay which will cause
+ * it to start over with `base` instead of doubling.
+ */
+ reset: number;
+
+ private _exp = 0;
+ private _lastInvocationTime = Date.now();
+
/**
* Construct ExponentialBackoff helper
*
* The options passed may also be modified on the instance at runtime.
*
- * @param {object=} options -
+ * @param options -
* Options for this exponential backoff helper
- * @param {number=} [options.base=1] -
+ * @param [options.base=1] -
* Base delay in seconds. The first delay will on average be this
* long, but can be anywhere between 0 and 2 times this value.
- * @param {number=} [options.max=60] -
+ * @param [options.max=60] -
* Maximum delay in seconds. A delay will not take more than this
* value.
- * @param {number=} [options.reset=2*max] -
+ * @param [options.reset=2*max] -
* Time in seconds between two invocations of delay which will cause
* it to start over with `base` instead of doubling.
*/
- constructor(options = {}) {
- /**
- * Base delay in seconds. The first delay will on average be this
- * long, but can be anywhere between 0 and 2 times this value.
- * @type {number}
- */
+ constructor(options: { base?: number, max?: number, reset?: number } = {}) {
this.base = options.base || 1;
- /**
- * Maximum delay in seconds. A delay will not take more than this
- * value.
- * @type {number}
- */
this.max = options.max || 60;
- /**
- * Time in seconds between two invocations of delay which will cause
- * it to start over with `base` instead of doubling.
- * @type {number}
- */
this.reset = options.reset || 2 * this.max;
-
- this._exp = 0;
- this._lastInvocationTime = Date.now();
}
/**
@@ -66,7 +62,7 @@ class ExponentialBackoff {
* algorithm. This is a value between 0 and min(2 * options.base *
* 2retries, optinos.max).
*
- * @returns {number} time in milliseconds to wait.
+ * @returns time in milliseconds to wait.
*/
delay() {
let invocationTime = Date.now();
diff --git a/packages/lib/src/PlayerStats.js b/packages/lib/src/PlayerStats.ts
similarity index 66%
rename from packages/lib/src/PlayerStats.js
rename to packages/lib/src/PlayerStats.ts
index 1c7c873b..f3f96691 100644
--- a/packages/lib/src/PlayerStats.js
+++ b/packages/lib/src/PlayerStats.ts
@@ -1,52 +1,43 @@
-"use strict";
+import { Type, Static } from "@sinclair/typebox";
/**
* Stastics collected about a player.
- * @alias module:lib.PlayerStats
*/
-class PlayerStats {
+export default class PlayerStats {
/**
* Count of the number of times this player has been seen joining this server.
- * @type {number}
*/
joinCount = 0;
/**
* Time in ms this player has been seen online on this instance.
- * @type {number}
*/
onlineTimeMs = 0;
/**
* Timestamp the player was last seen joining.
- * @type {Date=}
*/
- lastJoinAt;
+ lastJoinAt?: Date;
/**
* Timestamp the player was last seen leaving.
- * @type {Date=}
*/
- lastLeaveAt;
+ lastLeaveAt?: Date;
/**
* Reason the player was last seen leaving with.
- * @type {string=}
*/
- lastLeaveReason;
+ lastLeaveReason?: string;
- static jsonSchema = {
- type: "object",
- properties: {
- "join_count": { type: "integer" },
- "online_time_ms": { type: "number" },
- "last_join_at": { type: "number" },
- "last_leave_at": { type: "number" },
- "last_leave_reason": { type: "string" },
- },
- };
+ static jsonSchema = Type.Object({
+ "join_count": Type.Optional(Type.Integer()),
+ "online_time_ms": Type.Optional(Type.Number()),
+ "last_join_at": Type.Optional(Type.Number()),
+ "last_leave_at": Type.Optional(Type.Number()),
+ "last_leave_reason": Type.Optional(Type.String()),
+ });
- constructor(json = {}) {
+ constructor(json: Static = {}) {
if (json["join_count"]) {
this.joinCount = json["join_count"];
}
@@ -62,12 +53,12 @@ class PlayerStats {
}
}
- static fromJSON(json) {
+ static fromJSON(json: Static) {
return new this(json);
}
toJSON() {
- let json = {};
+ let json: Static = {};
if (this.joinCount) {
json["join_count"] = this.joinCount;
}
@@ -84,5 +75,3 @@ class PlayerStats {
return json;
}
}
-
-module.exports = PlayerStats;
diff --git a/packages/lib/src/RateLimiter.js b/packages/lib/src/RateLimiter.ts
similarity index 70%
rename from packages/lib/src/RateLimiter.js
rename to packages/lib/src/RateLimiter.ts
index 7a82d0c1..24390c6b 100644
--- a/packages/lib/src/RateLimiter.js
+++ b/packages/lib/src/RateLimiter.ts
@@ -1,6 +1,3 @@
-"use strict";
-
-
/**
* Helper class for rate limiting actions
*
@@ -8,6 +5,7 @@
* limited on invocations.
*
* @example
+ * ```ts
* const rateLimiter = RateLimiter({
* action: () => { console.log("action"); },
* maxRate: 1,
@@ -19,36 +17,35 @@
* // and one more time 1 second later for 99 other activations that were
* // exceeding the rate limit.
* }
- * @alias module:lib.RateLimiter
+ * ```
*/
-class RateLimiter {
+export default class RateLimiter {
+ /**
+ * Maximum rate of activations per second.
+ */
+ maxRate: number;
+ /**
+ * Callback invoked at most `maxRate` per second on activation.
+ */
+ action?: Function;
+
+ private _lastRun = 0;
+ private _runTimeout?: NodeJS.Timeout;
+
/**
* Construct RateLimiter helper
*
* The options passed may also be modified on the instance at runtime.
*
- * @param {object=} options - Options for this rate limiter
- * @param {number=} options.maxRate -
+ * @param options - Options for this rate limiter
+ * @param options.maxRate -
* Maximum rate of activations per second.
- * @param {function()=} options.action -
+ * @param options.action -
* Callback invoked at maste `maxRate` per second on activation.
*/
- constructor(options = {}) {
- /**
- * Maximum rate of activations per second.
- * @type {number}
- */
+ constructor(options: { maxRate?: number, action?: Function } = {}) {
this.maxRate = options.maxRate || 1;
-
- /**
- * Callback invoked at most `maxRate` per second on activation.
- * @type {function()}
- */
- this.action = options.action || null;
-
- this._lastRun = 0;
- this._runTimeout = null;
- this.lastProgressBroadcast = Date.now();
+ this.action = options.action || undefined;
}
/**
@@ -59,16 +56,18 @@ class RateLimiter {
* invoked immediatly, otherwise a timeout is registered to invoke the
* action at next point in time where it will be within the rate limit.
*
- * @returns {boolean} true if activation was within the rate limit.
+ * @returns true if activation was within the rate limit.
*/
activate() {
let now = Date.now();
if (now < this._lastRun + 1000 / this.maxRate) {
- if (!this._runTimeout && this.action !== null) {
+ if (!this._runTimeout && this.action) {
this._runTimeout = setTimeout(() => {
- this._runTimeout = null;
+ this._runTimeout = undefined;
this._lastRun = Date.now();
- this.action();
+ if (this.action) {
+ this.action();
+ }
}, this._lastRun + 1000 / this.maxRate - now);
}
return false;
@@ -77,11 +76,11 @@ class RateLimiter {
// We may end up activating before the timeout does.
if (this._runTimeout) {
clearTimeout(this._runTimeout);
- this._runTimeout = null;
+ this._runTimeout = undefined;
}
this._lastRun = now;
- if (this.action !== null) {
+ if (this.action) {
this.action();
}
return true;
@@ -100,5 +99,3 @@ class RateLimiter {
}
}
}
-
-module.exports = RateLimiter;
diff --git a/packages/lib/src/command.js b/packages/lib/src/command.ts
similarity index 68%
rename from packages/lib/src/command.js
rename to packages/lib/src/command.ts
index 972f6969..d2173ed0 100644
--- a/packages/lib/src/command.js
+++ b/packages/lib/src/command.ts
@@ -6,29 +6,37 @@
* @author Hornwitser
* @module lib/command
*/
-"use strict";
-const libData = require("./data");
-const libLink = require("./link");
-const libErrors = require("./errors");
+import * as libData from "./data";
+import * as libErrors from "./errors";
+import type { Link } from "./link";
+
+
+export type CommandHandler = (args: Record, control: Link) => Promise;
+export type CommandDefinition = [string | string[], string?, Function?];
/**
* Represents a command that can be runned by clusterioctl
- * @static
*/
-class Command {
+export class Command {
+ private _handler: CommandHandler;
+ private _definition: CommandDefinition;
+
+ name: string;
+ alias: string[];
+
/**
* Define an executable command.
*
- * @param {Object} cmd - Command definiton.
- * @param {Array} cmd.definiton -
+ * @param cmd - Command definiton.
+ * @param cmd.definiton -
* Arguments to pass to yargs .command method to define this
* command.
- * @param {function(args, control)} handler -
+ * @param cmd.handler -
* Async function invoked when the command is executed. Is given
* the parsed args and a reference to the {@link
* module:ctl/ctl.Control} instance.
*/
- constructor({ definition, handler }) {
+ constructor({ definition, handler }: { definition: CommandDefinition, handler: CommandHandler }) {
if (definition[0] instanceof Array) {
this.name = definition[0][0].split(" ")[0];
this.alias = definition[0].slice(1);
@@ -40,11 +48,11 @@ class Command {
this._handler = handler;
}
- register(yargs) {
+ register(yargs: any) {
yargs.command(...this._definition);
}
- async run(args, control) {
+ async run(args: Record, control: Link) {
await this._handler(args, control);
}
}
@@ -56,20 +64,23 @@ class Command {
* CommandTrees. This is used by clusterioctl to hold the full tree of
* available commands, you may extend this tree by using a control plugin,
* see {@link module:lib.BaseControlPlugin#addCommands}
- *
- * @static
*/
-class CommandTree {
+export class CommandTree {
+ public name: string;
+ public alias: string[];
+ public description: string;
+ public subCommands: Map;
+
/**
* Define a command containing sub commands.
*
- * @param {Object} cmd - Command definition
- * @param {string} cmd.name - Name of the command.
- * @param {Array} cmd.alias - Aliases for this tree.
- * @param {description} cmd.description -
+ * @param cmd - Command definition
+ * @param cmd.name - Name of the command.
+ * @param cmd.alias - Aliases for this tree.
+ * @param cmd.description -
* Descripton to provide for this command tree node.
*/
- constructor({ name, alias, description }) {
+ constructor({ name, alias, description }: { name: string, alias: string[], description: string }) {
if (typeof name !== "string") {
throw new Error("name must be a string");
}
@@ -83,10 +94,10 @@ class CommandTree {
/**
* Add a command or command tree to this tree
*
- * @param {module:lib.Command|module:lib.CommandTree} command -
+ * @param command -
* The command to add to this command tree.
*/
- add(command) {
+ add(command: Command | CommandTree) {
if (this.subCommands.has(command.name)) {
throw new Error(`Command ${command.name} already exists`);
}
@@ -102,13 +113,13 @@ class CommandTree {
/**
* Get a command or command tree from this tree
*
- * @param {string} name -
+ * @param name -
* The name of the command or command tree to retrieve.
- * @return {?module:lib.Command|module:lib.CommandTree}
+ * @return
* The command to add to this command tree.
*/
- get(name) {
- return this.subCommands.get(name) || null;
+ get(name: string) {
+ return this.subCommands.get(name);
}
/**
@@ -117,10 +128,10 @@ class CommandTree {
* Traverses the the tree of sub-commands recursively and adds all of
* them to the given yargs parser.
*
- * @param {Object} yargs - yargs parser to register with.
+ * @param yargs - yargs parser to register with.
*/
- register(yargs) {
- yargs.command([this.name].concat(this.alias), this.description, (yargs) => {
+ register(yargs: any) {
+ yargs.command([this.name].concat(this.alias), this.description, (yargs: any) => {
for (let [name, command] of this.subCommands) {
// Check if the entry is not an alias.
if (name === command.name) {
@@ -141,13 +152,12 @@ class CommandTree {
* Resolves a string with either an host name or an id into an integer with
* the host ID.
*
- * @param {module:lib.Link} client - link to controller to query host on.
- * @param {string} hostName - string with name or id of host.
- * @returns {Promise} host ID.
- * @static
+ * @param client - link to controller to query host on.
+ * @param hostName - string with name or id of host.
+ * @returns host ID.
*/
-async function resolveHost(client, hostName) {
- let hostId;
+export async function resolveHost(client: Link, hostName: string) {
+ let hostId: number | undefined;
if (/^-?\d+$/.test(hostName)) {
hostId = parseInt(hostName, 10);
} else {
@@ -173,13 +183,12 @@ async function resolveHost(client, hostName) {
* Resolves a string with either an instance name or an id into an integer
* with the instance ID.
*
- * @param {module:lib.Link} client - link to controller to query instance on.
- * @param {string} instanceName - string with name or id of instance.
- * @returns {Promise} instance ID.
- * @static
+ * @param client - link to controller to query instance on.
+ * @param instanceName - string with name or id of instance.
+ * @returns instance ID.
*/
-async function resolveInstance(client, instanceName) {
- let instanceId;
+export async function resolveInstance(client: Link, instanceName: string) {
+ let instanceId: number | undefined;
if (/^-?\d+$/.test(instanceName)) {
instanceId = parseInt(instanceName, 10);
} else {
@@ -205,14 +214,13 @@ async function resolveInstance(client, instanceName) {
* Resolevs a string with either a mod pack name or an id into an integer
* with the mod pack ID.
*
- * @param {module:lib.Link} client -
+ * @param client -
* link to controller to query mod pack on.
- * @param {string} modPackName - string with name or id of mod pack.
- * @returns {Promise} mod pack ID.
- * @static
+ * @param modPackName - string with name or id of mod pack.
+ * @returns mod pack ID.
*/
-async function resolveModPack(client, modPackName) {
- let modPackId;
+export async function resolveModPack(client: Link, modPackName: string) {
+ let modPackId: number | undefined;
if (/^-?\d+/.test(modPackName)) {
modPackId = parseInt(modPackName, 10);
} else {
@@ -238,15 +246,14 @@ async function resolveModPack(client, modPackName) {
* Resolves a string with either a role name or an id into an object
* representing the role.
*
- * @param {module:lib.Link} client - link to controller to query role on.
- * @param {string} roleName - string with name or id of role.
- * @returns {Promise