@caleb-collar/steamcmd 1.0.0-alpha.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/steamcmd.js DELETED
@@ -1,404 +0,0 @@
1
- /**
2
- * @module steamcmd
3
- * @description Node.js wrapper for SteamCMD - download, install, and manage Steam applications
4
- * @author Björn Dahlgren
5
- * @license MIT
6
- * @see https://github.com/dahlgren/node-steamcmd
7
- */
8
-
9
- const fs = require('fs')
10
- const path = require('path')
11
- const { promisify } = require('util')
12
- const { EventEmitter } = require('events')
13
-
14
- const download = require('./download')
15
- const env = require('./env')
16
- const install = require('./install')
17
-
18
- const access = promisify(fs.access)
19
- const readdir = promisify(fs.readdir)
20
- const readFile = promisify(fs.readFile)
21
-
22
- /**
23
- * Custom error class for SteamCMD operations
24
- */
25
- class SteamCmdError extends Error {
26
- constructor (message, code, cause) {
27
- super(message)
28
- this.name = 'SteamCmdError'
29
- this.code = code
30
- if (cause) {
31
- this.cause = cause
32
- }
33
- }
34
- }
35
-
36
- /**
37
- * Check if SteamCMD is installed and executable
38
- * @returns {Promise<boolean>} True if SteamCMD is available
39
- */
40
- async function isInstalled () {
41
- const executablePath = env.executable()
42
- if (!executablePath) return false
43
-
44
- try {
45
- await access(executablePath, (fs.constants || fs).X_OK)
46
- return true
47
- } catch {
48
- return false
49
- }
50
- }
51
-
52
- /**
53
- * Ensure SteamCMD is installed, downloading if necessary
54
- * @param {Object} [options] - Options
55
- * @param {Function} [options.onProgress] - Download progress callback
56
- * @returns {Promise<void>}
57
- * @throws {SteamCmdError} If download fails
58
- */
59
- async function ensureInstalled (options) {
60
- options = options || {}
61
- const installed = await isInstalled()
62
- if (installed) return
63
-
64
- console.log('SteamCMD needs to be installed')
65
-
66
- try {
67
- await download({ onProgress: options.onProgress })
68
- console.log('SteamCMD was installed')
69
- } catch (err) {
70
- throw new SteamCmdError(
71
- 'Failed to install SteamCMD',
72
- 'INSTALL_FAILED',
73
- err
74
- )
75
- }
76
- }
77
-
78
- /**
79
- * Install a Steam application or Workshop item
80
- *
81
- * @param {Object} options - Installation options
82
- * @param {number|string} [options.applicationId] - Steam application ID to install
83
- * @param {number|string} [options.workshopId] - Workshop item ID to install (requires applicationId)
84
- * @param {string} [options.path] - Installation directory
85
- * @param {string} [options.username] - Steam username for authentication
86
- * @param {string} [options.password] - Steam password for authentication
87
- * @param {string} [options.steamGuardCode] - Steam Guard code for two-factor authentication
88
- * @param {string} [options.platform] - Target platform ('windows', 'macos', 'linux')
89
- * @param {Function} [options.onProgress] - Progress callback(progress) with { phase, percent, bytesDownloaded, totalBytes }
90
- * @param {Function} [options.onOutput] - Output callback(data, type) where type is 'stdout' or 'stderr'
91
- * @param {Function} [callback] - Optional callback(err). If omitted, returns a Promise.
92
- * @returns {Promise<void>|undefined} Promise if no callback provided
93
- *
94
- * @example
95
- * // Promise-based usage with progress
96
- * await steamcmd.install({
97
- * applicationId: 740,
98
- * path: './server',
99
- * onProgress: (p) => console.log(`${p.phase}: ${p.percent}%`)
100
- * });
101
- *
102
- * @example
103
- * // Callback-based usage (legacy)
104
- * steamcmd.install({ applicationId: 740 }, (err) => {
105
- * if (err) console.error(err);
106
- * });
107
- */
108
- function steamCmdInstall (options, callback) {
109
- // Support Promise-based usage
110
- if (typeof callback !== 'function') {
111
- return steamCmdInstallAsync(options)
112
- }
113
-
114
- // Legacy callback-based usage
115
- steamCmdInstallAsync(options)
116
- .then(() => callback(null))
117
- .catch((err) => callback(err))
118
- }
119
-
120
- /**
121
- * Async implementation of install
122
- * @private
123
- */
124
- async function steamCmdInstallAsync (options) {
125
- // Validate options early
126
- if (!options || typeof options !== 'object') {
127
- throw new SteamCmdError('Options must be an object', 'INVALID_OPTIONS')
128
- }
129
-
130
- // Ensure SteamCMD is installed (pass download progress)
131
- await ensureInstalled({ onProgress: options.onProgress })
132
-
133
- // Run installation
134
- const executablePath = env.executable()
135
- try {
136
- await install(executablePath, options)
137
- } catch (err) {
138
- throw new SteamCmdError(
139
- `Installation failed: ${err.message}`,
140
- 'RUN_FAILED',
141
- err
142
- )
143
- }
144
- }
145
-
146
- /**
147
- * Get information about the SteamCMD installation
148
- * @returns {Object} SteamCMD paths and status
149
- */
150
- function getInfo () {
151
- return {
152
- directory: env.directory(),
153
- executable: env.executable(),
154
- platform: env.platform(),
155
- isSupported: env.isPlatformSupported()
156
- }
157
- }
158
-
159
- /**
160
- * Parse Steam app manifest file (.acf)
161
- * @param {string} manifestPath - Path to the manifest file
162
- * @returns {Promise<Object>} Parsed manifest data
163
- * @private
164
- */
165
- async function parseAppManifest (manifestPath) {
166
- const content = await readFile(manifestPath, 'utf8')
167
- const result = {}
168
-
169
- // Simple VDF parser for app manifests
170
- const lines = content.split('\n')
171
- for (const line of lines) {
172
- const match = line.match(/"(\w+)"\s+"([^"]*)"/)
173
- if (match) {
174
- result[match[1]] = match[2]
175
- }
176
- }
177
-
178
- return result
179
- }
180
-
181
- /**
182
- * Get a list of installed Steam applications in a directory
183
- * @param {Object} options - Options
184
- * @param {string} options.path - Installation directory to scan
185
- * @returns {Promise<Array<Object>>} Array of installed app information
186
- *
187
- * @example
188
- * const apps = await steamcmd.getInstalledApps({ path: './server' });
189
- * // [{ appId: 740, name: 'Counter-Strike Global Offensive - Dedicated Server', ... }]
190
- */
191
- async function getInstalledApps (options) {
192
- if (!options || !options.path) {
193
- throw new SteamCmdError('path option is required', 'INVALID_OPTIONS')
194
- }
195
-
196
- const steamappsDir = path.join(options.path, 'steamapps')
197
- const apps = []
198
-
199
- try {
200
- await access(steamappsDir, fs.constants.R_OK)
201
- } catch {
202
- // No steamapps directory, return empty array
203
- return apps
204
- }
205
-
206
- try {
207
- const files = await readdir(steamappsDir)
208
- const manifestFiles = files.filter(
209
- (f) => f.startsWith('appmanifest_') && f.endsWith('.acf')
210
- )
211
-
212
- for (const file of manifestFiles) {
213
- try {
214
- const manifest = await parseAppManifest(path.join(steamappsDir, file))
215
- apps.push({
216
- appId: parseInt(manifest.appid, 10),
217
- name: manifest.name || 'Unknown',
218
- installDir: manifest.installdir || null,
219
- sizeOnDisk: parseInt(manifest.SizeOnDisk || '0', 10),
220
- buildId: parseInt(manifest.buildid || '0', 10),
221
- lastUpdated: manifest.LastUpdated
222
- ? new Date(parseInt(manifest.LastUpdated, 10) * 1000)
223
- : null,
224
- state: parseInt(manifest.StateFlags || '0', 10)
225
- })
226
- } catch {
227
- // Skip invalid manifest files
228
- }
229
- }
230
- } catch {
231
- // Error reading directory
232
- }
233
-
234
- return apps
235
- }
236
-
237
- /**
238
- * Update an installed Steam application
239
- * @param {Object} options - Update options
240
- * @param {number|string} options.applicationId - Steam application ID to update
241
- * @param {string} [options.path] - Installation directory
242
- * @param {string} [options.username] - Steam username for authentication
243
- * @param {string} [options.password] - Steam password for authentication
244
- * @param {string} [options.steamGuardCode] - Steam Guard code
245
- * @param {string} [options.platform] - Target platform
246
- * @param {Function} [options.onProgress] - Progress callback
247
- * @param {Function} [options.onOutput] - Output callback
248
- * @returns {Promise<void>}
249
- *
250
- * @example
251
- * await steamcmd.update({
252
- * applicationId: 740,
253
- * path: './server',
254
- * onProgress: (p) => console.log(`${p.phase}: ${p.percent}%`)
255
- * });
256
- */
257
- async function update (options) {
258
- if (!options || !options.applicationId) {
259
- throw new SteamCmdError(
260
- 'applicationId option is required',
261
- 'INVALID_OPTIONS'
262
- )
263
- }
264
-
265
- // update is essentially the same as install - SteamCMD handles both
266
- return steamCmdInstallAsync(options)
267
- }
268
-
269
- /**
270
- * Validate an installed Steam application
271
- * @param {Object} options - Validation options
272
- * @param {number|string} options.applicationId - Steam application ID to validate
273
- * @param {string} [options.path] - Installation directory
274
- * @param {string} [options.username] - Steam username for authentication
275
- * @param {string} [options.password] - Steam password for authentication
276
- * @param {string} [options.steamGuardCode] - Steam Guard code
277
- * @param {Function} [options.onProgress] - Progress callback
278
- * @param {Function} [options.onOutput] - Output callback
279
- * @returns {Promise<void>}
280
- *
281
- * @example
282
- * await steamcmd.validate({
283
- * applicationId: 740,
284
- * path: './server'
285
- * });
286
- */
287
- async function validate (options) {
288
- if (!options || !options.applicationId) {
289
- throw new SteamCmdError(
290
- 'applicationId option is required',
291
- 'INVALID_OPTIONS'
292
- )
293
- }
294
-
295
- // validate is the same as install - SteamCMD always validates
296
- return steamCmdInstallAsync(options)
297
- }
298
-
299
- /**
300
- * Get the installed version (build ID) of a Steam application
301
- * @param {Object} options - Options
302
- * @param {number|string} options.applicationId - Steam application ID
303
- * @param {string} options.path - Installation directory
304
- * @returns {Promise<Object|null>} Version information or null if not installed
305
- *
306
- * @example
307
- * const version = await steamcmd.getInstalledVersion({
308
- * applicationId: 740,
309
- * path: './server'
310
- * });
311
- * // { appId: 740, buildId: 12345678, lastUpdated: Date }
312
- */
313
- async function getInstalledVersion (options) {
314
- if (!options || !options.applicationId || !options.path) {
315
- throw new SteamCmdError(
316
- 'applicationId and path options are required',
317
- 'INVALID_OPTIONS'
318
- )
319
- }
320
-
321
- const appId = Number(options.applicationId)
322
- const manifestPath = path.join(
323
- options.path,
324
- 'steamapps',
325
- `appmanifest_${appId}.acf`
326
- )
327
-
328
- try {
329
- await access(manifestPath, fs.constants.R_OK)
330
- const manifest = await parseAppManifest(manifestPath)
331
-
332
- return {
333
- appId: parseInt(manifest.appid, 10),
334
- name: manifest.name || 'Unknown',
335
- buildId: parseInt(manifest.buildid || '0', 10),
336
- lastUpdated: manifest.LastUpdated
337
- ? new Date(parseInt(manifest.LastUpdated, 10) * 1000)
338
- : null
339
- }
340
- } catch {
341
- return null
342
- }
343
- }
344
-
345
- /**
346
- * Create an EventEmitter for SteamCMD operations with real-time progress
347
- * @param {string} operation - Operation type ('install', 'update', 'validate')
348
- * @param {Object} options - Operation options
349
- * @returns {EventEmitter} Emitter that fires 'progress', 'output', 'error', and 'complete' events
350
- *
351
- * @example
352
- * const emitter = steamcmd.createProgressEmitter('install', { applicationId: 740 });
353
- * emitter.on('progress', (p) => console.log(`${p.phase}: ${p.percent}%`));
354
- * emitter.on('output', (data, type) => console.log(`[${type}] ${data}`));
355
- * emitter.on('complete', () => console.log('Done!'));
356
- * emitter.on('error', (err) => console.error(err));
357
- */
358
- function createProgressEmitter (operation, options) {
359
- const emitter = new EventEmitter()
360
-
361
- process.nextTick(async () => {
362
- try {
363
- // Ensure SteamCMD is installed first
364
- await ensureInstalled({
365
- onProgress: (progress) => emitter.emit('progress', progress)
366
- })
367
-
368
- // Run the operation
369
- const executablePath = env.executable()
370
- const operationOptions = {
371
- ...options,
372
- onProgress: (progress) => emitter.emit('progress', progress),
373
- onOutput: (data, type) => emitter.emit('output', data, type)
374
- }
375
-
376
- await install(executablePath, operationOptions)
377
- emitter.emit('complete')
378
- } catch (err) {
379
- emitter.emit('error', err)
380
- }
381
- })
382
-
383
- return emitter
384
- }
385
-
386
- module.exports = {
387
- install: steamCmdInstall,
388
- isInstalled,
389
- ensureInstalled,
390
- getInfo,
391
- SteamCmdError,
392
- // New functions
393
- getInstalledApps,
394
- update,
395
- validate,
396
- getInstalledVersion,
397
- createProgressEmitter,
398
- // Re-export error classes for consumers
399
- DownloadError: download.DownloadError,
400
- InstallError: install.InstallError,
401
- // Re-export progress helpers
402
- downloadWithProgress: download.downloadWithProgress,
403
- installWithProgress: install.installWithProgress
404
- }
package/src/steamcmd.mjs DELETED
@@ -1,28 +0,0 @@
1
- /**
2
- * @module steamcmd
3
- * @description ESM wrapper for steamcmd module
4
- */
5
-
6
- import { createRequire } from "module";
7
- const require = createRequire(import.meta.url);
8
-
9
- const steamcmd = require("./steamcmd.js");
10
-
11
- // Named exports
12
- export const install = steamcmd.install;
13
- export const isInstalled = steamcmd.isInstalled;
14
- export const ensureInstalled = steamcmd.ensureInstalled;
15
- export const getInfo = steamcmd.getInfo;
16
- export const SteamCmdError = steamcmd.SteamCmdError;
17
- export const DownloadError = steamcmd.DownloadError;
18
- export const InstallError = steamcmd.InstallError;
19
- export const downloadWithProgress = steamcmd.downloadWithProgress;
20
- export const installWithProgress = steamcmd.installWithProgress;
21
- export const getInstalledApps = steamcmd.getInstalledApps;
22
- export const update = steamcmd.update;
23
- export const validate = steamcmd.validate;
24
- export const getInstalledVersion = steamcmd.getInstalledVersion;
25
- export const createProgressEmitter = steamcmd.createProgressEmitter;
26
-
27
- // Default export
28
- export default steamcmd;