@djwoodz/satisfactory-dedicated-server-https-api-client
v0.1.0
Published
A zero dependency Node.js client library for the HTTPS API of the Satisfactory Dedicated Server.
Downloads
6
Maintainers
Readme
Satisfactory Dedicated Server HTTPS API Client
A low-level, zero dependency Node.js client library for the HTTPS API of the Satisfactory Dedicated Server.
Installation
npm i @djwoodz/satisfactory-dedicated-server-https-api-client
Example Usage
// import module
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
// create apiClient
const apiClient = new APIClient({
address: '127.0.0.1',
port: 7777,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
// health check using await
const { data } = await apiClient.healthCheck();
console.log(data);
// health check using .then()
apiClient.healthCheck()
.then((data) => {
console.log(data);
});
APIClient Constructor Options
Name | Type | Default | Description ----|------|---------|------------- address | string | '127.0.0.1' | The address of the Dedicated Server port | number | 7777 | The port number of the Dedicated Server https | object | { request: { timeout:30000 } } | Options for HTTPS functions authenticationToken | string | | The authentication token to be set for requests
APIClient Functions
API Functions
These map to the 'API Functions' in the DedicatedServerAPIDocs.md
file (available under the 'CommunityResources' directory of the installed Satisfactory game):
| Method Signature | Description | | --- | --- | | healthCheck(clientCustomData?: string) → {Promise.<*>} | Performs a health check on the server | | verifyAuthenticationToken() → {Promise.<*>} | Verifies the authentication token currently set for the API Client | | passwordlessLogin(minimumPrivilegeLevel: PrivilegeLevel) → {Promise.<*>} | Performs a passwordless login | | passwordLogin(minimumPrivilegeLevel: PrivilegeLevel, password: string) → {Promise.<*>} | Performs a password-based login | | queryServerState() → {Promise.<*>} | Queries the state of the server | | getServerOptions() → {Promise.<*>} | Gets the options for the server | | getAdvancedGameSettings() → {Promise.<*>} | Gets the advanced game settings for the server | | applyAdvancedGameSettings(appliedAdvancedGameSettings: object) → {Promise.<*>} | Applies the provided advanced game settings to the server | | claimServer(serverName: string, adminPassword: string) → {Promise.<*>} | Stakes a claim on the server | | renameServer(serverName: string) → {Promise.<*>} | Renames the server | | setClientPassword(password: string) → {Promise.<*>} | Sets the client password for the server | | setAdminPassword(password: string) → {Promise.<*>} | Sets the admin password for the server | | setAutoLoadSessionName(sessionName: string) → {Promise.<*>} | Sets the session name to automatically load when joining the server | | runCommand(command: string) → {Promise.<*>} | Runs a command on the server | | shutdown() → {Promise.<*>} | Requests the server to shut down | | applyServerOptions(updatedServerOptions: object.<string, string>) → {Promise.<*>} | Applies new server options to the server | | createNewGame(newGameData: object) → {Promise.<*>} | Creates a new game on the server | | saveGame(saveName: string) → {Promise.<*>} | Saves the game on the server using the provided name | | deleteSaveFile(saveName: string) → {Promise.<*>} | Deletes a save file from the server | | deleteSaveSession(sessionName: string) → {Promise.<*>} | Deletes all save files from the server belonging to the given session name | | enumerateSessions() → {Promise.<*>} | Enumerates all sessions on the server | | loadGame(saveName: string, enableAdvancedGameSettings?: boolean) → {Promise.<*>} | Loads a save game with the given name from the server | | uploadSaveGame(buffer: Buffer, saveName: string, loadSaveGame?: boolean, enableAdvancedGameSettings?: boolean) → {Promise.<*>} | Upload a save game file to the server using the given and name | | downloadSaveGame(saveName: string) → {Promise.<Buffer>} | Downloads a save game with the given name from the server |
Other Functions
The client also has several other functions:
| Method Signature | Description | | --- | --- | | setAPIClientAuthenticationToken(authenticationToken: string) | Sets the API Client's authentication token | | (static) getAuthenticationTokenPrivilegeLevel(authenticationToken: string) → {PrivilegeLevel} | Parses a given authentication token and returns its privilege level | | (static) getCertificates(options?) → {Promise.<object>} | Retrieves the server and CA certificates from a remote server via HTTPS |
Enumerations
PrivilegeLevel
Privilege Level Enumeration representing different privilege levels granted by an authentication token.
| Enumerator | Description | | --- | --- | | PrivilegeLevel.NotAuthenticated | Not authenticated | | PrivilegeLevel.Client | Authenticated with Client privileges | | PrivilegeLevel.Administrator | Authenticated with Admin privileges | | PrivilegeLevel.InitialAdmin | Authenticated as Initial Admin with privileges to claim the server | | PrivilegeLevel.APIToken | Authenticated as Third Party Application |
StatusCode
Status Code Enumeration representing different HTTP response codes.
| Enumerator | Description | | --- | --- | | StatusCode.OK | Status Code for Ok 200 | | StatusCode.CREATED | Status Code for Created 201 | | StatusCode.ACCEPTED | Status Code for Accepted 202 | | StatusCode.NO_CONTENT | Status Code for No Content 204 | | StatusCode.BAD_REQUEST | Status Code for Bad Request 400 | | StatusCode.DENIED | Status Code for Denied 401 | | StatusCode.FORBIDDEN | Status Code for Forbidden 403 | | StatusCode.NOT_FOUND | Status Code for Not Found 404 | | StatusCode.UNSUPPORTED_MEDIA | Status Code for Unsupported Media 415 | | StatusCode.SERVER_ERROR | Status Code for Server Error 500 |
Basic Examples
Health Check
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const main = async () => {
const apiClient = new APIClient({
address,
port,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.healthCheck());
};
main();
Query Server State
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.queryServerState());
};
main();
Verify Authentication Token
const { APIClient, StatusCode } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
const { status } = await apiClient.verifyAuthenticationToken();
if (status === StatusCode.NO_CONTENT) {
console.log('The authentication token is valid.');
} else {
console.error('The authentication token is invalid.');
}
};
main();
Passwordless Login
const { APIClient, StatusCode } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const main = async () => {
const apiClient = new APIClient({
address,
port,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
// Client passwordless login (when Client password is not set)
const { status, data } = await apiClient.passwordlessLogin(PrivilegeLevel.Client);
if (status === StatusCode.OK && data?.authenticationToken) {
// update the API Client to use the authentication token
apiClient.setAPIClientAuthenticationToken(data.authenticationToken);
// check the authentication token is valid
if (apiClient.verifyAuthenticationToken(data.authenticationToken)) {
// perform operation permissable at Client privilege level
console.log(await apiClient.queryServerState());
}
}
};
main();
Password Login
const { APIClient, StatusCode } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const main = async () => {
const apiClient = new APIClient({
address,
port,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
// Client password login (when Client password is set)
const { status, data } = await apiClient.passwordLogin(PrivilegeLevel.Client, 'My Client Password');
if (status === StatusCode.OK && data?.authenticationToken) {
// update the API Client to use the authentication token
apiClient.setAPIClientAuthenticationToken(data.authenticationToken);
// check the authentication token is valid
if (apiClient.verifyAuthenticationToken(data.authenticationToken)) {
// perform operation permissable at Client privilege level
console.log(await apiClient.queryServerState());
}
}
};
main();
Get Server Options
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.getServerOptions());
};
main();
Get Advanced Game Settings
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.getAdvancedGameSettings());
};
main();
Apply Advanced Game Settings
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.applyAdvancedGameSettings({
'FG.PlayerRules.GodMode': true,
'FG.PlayerRules.FlightMode': true,
}));
};
main();
Rename Server
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.renameServer('My Server'));
};
main();
Set Client Password
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.setClientPassword('My Client Password'));
};
main();
Set Admin Password
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.setAdminPassword('My Admin Password'));
};
main();
Set Auto Load Session Name
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.setAutoLoadSessionName('My Session'));
console.log((await apiClient.queryServerState()).data.serverGameState.autoLoadSessionName);
};
main();
Run Command
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.runCommand('FG.NetworkQuality'));
};
main();
Shutdown
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.shutdown());
};
main();
Apply Server Options
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.applyServerOptions({ 'FG.AutosaveInterval': '600' }));
};
main();
Create New Game
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.createNewGame({
SessionName: 'My Session',
}));
};
main();
Save Game
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.saveGame('My Save'));
};
main();
Delete Save File
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.deleteSaveFile('My Save'));
};
main();
Delete Save Session
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.deleteSaveSession('My Session'));
};
main();
Enumerate Sessions
Here is an example of how you can iterate all save names against all sessions:
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
const { data } = await apiClient.enumerateSessions();
const { currentSessionIndex } = data;
data.sessions.forEach((session, index) => {
console.log(`Session: ${session.sessionName}${(index === currentSessionIndex ? ' (Current)' : '')}`);
session.saveHeaders.forEach(({ saveName }) => {
console.log(` Save Name: ${saveName}`);
});
});
};
main();
Example output:
Session: My Session (Current)
Save Name: My Save
Load Game
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
console.log(await apiClient.loadGame('My Save'));
};
main();
Upload Save Game
const fs = require('fs');
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
try {
const buffer = fs.readFileSync('My Save 1.sav');
console.log(await apiClient.uploadSaveGame(buffer, 'My Save 1', true));
} catch (error) {
console.error('Error reading the file:', error);
}
};
main();
Download Save Game
const fs = require('fs');
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
try {
const buffer = await apiClient.downloadSaveGame('My Save 2');
fs.writeFileSync('My Save 2.sav', buffer);
console.log('Buffer written to file successfully!');
} catch (error) {
console.error('Error writing to file', error);
}
};
main();
Set API Client Authentication Token
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const authenticationToken = 'some API token';
const main = async () => {
const apiClient = new APIClient({
address,
port,
authenticationToken,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
apiClient.setAPIClientAuthenticationToken('some other token');
};
main();
Get Authentication Token Privilege Level
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
console.log(APIClient.getAuthenticationTokenPrivilegeLevel('some API token'));
Advanced Examples
Claim Server
Here is an example of how to claim a new server (set server name and admin password), set the client password and generate an API Token:
const { APIClient, StatusCode, PrivilegeLevel } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const serverName = 'My Server';
const adminPassword = 'My Admin Password';
const clientPassword = 'My Client Password';
const main = async () => {
const apiClient = new APIClient({
address,
port,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
try {
// passwordless login
{
const {
status,
data,
} = await apiClient.passwordlessLogin(PrivilegeLevel.InitialAdmin);
// check passwordlessLogin returned the 'Ok' status code
if (status === StatusCode.OK) {
// get the initial authentication token
const authenticationToken = data?.authenticationToken;
if (authenticationToken) {
// check the token is an InitialAdmin token
const privilegeLevel = APIClient.getAuthenticationTokenPrivilegeLevel(authenticationToken);
if (privilegeLevel === PrivilegeLevel.InitialAdmin) {
console.log(`${PrivilegeLevel.InitialAdmin} token obtained.`);
// update the API Client to use the InitialAdmin authentication token
apiClient.setAPIClientAuthenticationToken(authenticationToken);
} else {
throw new Error(`authentication token was not ${PrivilegeLevel.InitialAdmin}: ${privilegeLevel}.`);
}
} else {
throw new Error('passwordlessLogin did not return an authentication token.');
}
} else {
throw new Error(`passwordlessLogin status code was: ${status?.code}.`);
}
}
// claim the server
{
const {
status,
data,
} = await apiClient.claimServer(serverName, adminPassword);
// check claimServer returned the 'Ok' status code
if (status === StatusCode.OK) {
// get the authentication token
const authenticationToken = data?.authenticationToken;
if (authenticationToken) {
// check the token is an Administrator token
const privilegeLevel = APIClient.getAuthenticationTokenPrivilegeLevel(authenticationToken);
if (privilegeLevel === PrivilegeLevel.Administrator) {
console.log(`Server claimed (named and admin password set). ${PrivilegeLevel.Administrator} token obtained.`);
// update the API Client to use the Administrator authentication token
apiClient.setAPIClientAuthenticationToken(authenticationToken);
} else {
throw new Error(`authentication token was not ${PrivilegeLevel.Administrator}: ${privilegeLevel}.`);
}
} else {
throw new Error('claimServer did not return an authentication token.');
}
} else {
throw new Error(`claimServer status code was: ${status?.code}.`);
}
}
// set the client password
{
const {
status,
} = await apiClient.setClientPassword(clientPassword);
// check setClientPassword returned the 'No Content' status code
if (status === StatusCode.NO_CONTENT) {
console.log('Client password set.');
} else {
throw new Error('Client password was not set.');
}
}
// generate API token
{
const {
status,
data,
} = await apiClient.runCommand('server.GenerateAPIToken');
// check runCommand returned the 'Ok' status code and had a result
if (status === StatusCode.OK && data?.commandResult) {
console.log(`server.GenerateAPIToken command result: ${data?.commandResult}`);
} else {
throw new Error('server.GenerateAPIToken command failed');
}
}
} catch (error) {
console.error(`An error occurred: ${error.message}`);
}
};
main();
Get Certificates
APIClient.getCertificates()
is a static utility function that can obtain the certificate(s) from the server.
Here is an example of how you might use it:
const fs = require('fs');
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const main = async () => {
const { server, ca } = await APIClient.getCertificates({
address,
port,
https: {
request: {
rejectUnauthorized: false, // accepts any CA, not secure
},
},
});
if (server?.pem) {
try {
console.log(`Server cert fingerprint512: ${server.cert?.fingerprint512}`);
fs.writeFileSync('serverCert.pem', server.pem);
console.log('Written server certificate to file successfully!');
} catch (error) {
console.error('Error writing to file', error);
}
}
if (ca?.pem) {
try {
console.log(`CA cert fingerprint512: ${ca.cert?.fingerprint512}`);
fs.writeFileSync('caCert.pem', ca.pem);
console.log('Written CA certificate to file successfully!');
} catch (error) {
console.error('Error writing to file', error);
}
}
};
main();
Then, instead of setting rejectUnauthorized: false
, you can use the results from getCertificates()
with the ca
and checkServerIdentity
options when creating a new APIClient
. The latter is handy for Dedicated Servers that use self-signed certificates.
For example, you can check the host and certificate fingerprint like this:
const fs = require('fs');
const { APIClient } = require('@djwoodz/satisfactory-dedicated-server-https-api-client');
const address = '127.0.0.1';
const port = 7777;
const fingerprint512 = 'some fingerprint';
const ca = fs.readFileSync('serverCert.pem');
const checkServerIdentity = (host, cert) => {
if (host !== address || cert?.fingerprint512 !== fingerprint512) {
throw new Error('Server identity check failed');
}
};
const main = async () => {
const apiClient = new APIClient({
address,
port,
https: {
request: {
ca,
checkServerIdentity,
},
},
});
console.log(await apiClient.healthCheck());
};
main();