@minecraft-docker/mcctl 1.6.0 → 1.6.1

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.
Files changed (141) hide show
  1. package/dist/application/index.d.ts +2 -0
  2. package/dist/application/index.d.ts.map +1 -0
  3. package/dist/application/index.js +5 -0
  4. package/dist/application/index.js.map +1 -0
  5. package/dist/commands/backup.d.ts +16 -0
  6. package/dist/commands/backup.d.ts.map +1 -0
  7. package/dist/commands/backup.js +182 -0
  8. package/dist/commands/backup.js.map +1 -0
  9. package/dist/commands/ban.d.ts +14 -0
  10. package/dist/commands/ban.d.ts.map +1 -0
  11. package/dist/commands/ban.js +418 -0
  12. package/dist/commands/ban.js.map +1 -0
  13. package/dist/commands/config.d.ts +18 -0
  14. package/dist/commands/config.d.ts.map +1 -0
  15. package/dist/commands/config.js +106 -0
  16. package/dist/commands/config.js.map +1 -0
  17. package/dist/commands/create.d.ts +22 -0
  18. package/dist/commands/create.d.ts.map +1 -0
  19. package/dist/commands/create.js +83 -0
  20. package/dist/commands/create.js.map +1 -0
  21. package/dist/commands/delete.d.ts +17 -0
  22. package/dist/commands/delete.d.ts.map +1 -0
  23. package/dist/commands/delete.js +71 -0
  24. package/dist/commands/delete.js.map +1 -0
  25. package/dist/commands/exec.d.ts +10 -0
  26. package/dist/commands/exec.d.ts.map +1 -0
  27. package/dist/commands/exec.js +29 -0
  28. package/dist/commands/exec.js.map +1 -0
  29. package/dist/commands/index.d.ts +18 -0
  30. package/dist/commands/index.d.ts.map +1 -0
  31. package/dist/commands/index.js +18 -0
  32. package/dist/commands/index.js.map +1 -0
  33. package/dist/commands/init.d.ts +9 -0
  34. package/dist/commands/init.d.ts.map +1 -0
  35. package/dist/commands/init.js +186 -0
  36. package/dist/commands/init.js.map +1 -0
  37. package/dist/commands/kick.d.ts +12 -0
  38. package/dist/commands/kick.d.ts.map +1 -0
  39. package/dist/commands/kick.js +71 -0
  40. package/dist/commands/kick.js.map +1 -0
  41. package/dist/commands/migrate.d.ts +18 -0
  42. package/dist/commands/migrate.d.ts.map +1 -0
  43. package/dist/commands/migrate.js +470 -0
  44. package/dist/commands/migrate.js.map +1 -0
  45. package/dist/commands/op.d.ts +12 -0
  46. package/dist/commands/op.d.ts.map +1 -0
  47. package/dist/commands/op.js +220 -0
  48. package/dist/commands/op.js.map +1 -0
  49. package/dist/commands/player-online.d.ts +11 -0
  50. package/dist/commands/player-online.d.ts.map +1 -0
  51. package/dist/commands/player-online.js +151 -0
  52. package/dist/commands/player-online.js.map +1 -0
  53. package/dist/commands/player.d.ts +18 -0
  54. package/dist/commands/player.d.ts.map +1 -0
  55. package/dist/commands/player.js +352 -0
  56. package/dist/commands/player.js.map +1 -0
  57. package/dist/commands/server-backup.d.ts +36 -0
  58. package/dist/commands/server-backup.d.ts.map +1 -0
  59. package/dist/commands/server-backup.js +320 -0
  60. package/dist/commands/server-backup.js.map +1 -0
  61. package/dist/commands/server-restore.d.ts +13 -0
  62. package/dist/commands/server-restore.d.ts.map +1 -0
  63. package/dist/commands/server-restore.js +294 -0
  64. package/dist/commands/server-restore.js.map +1 -0
  65. package/dist/commands/status.d.ts +13 -0
  66. package/dist/commands/status.d.ts.map +1 -0
  67. package/dist/commands/status.js +325 -0
  68. package/dist/commands/status.js.map +1 -0
  69. package/dist/commands/whitelist.d.ts +12 -0
  70. package/dist/commands/whitelist.d.ts.map +1 -0
  71. package/dist/commands/whitelist.js +316 -0
  72. package/dist/commands/whitelist.js.map +1 -0
  73. package/dist/commands/world.d.ts +16 -0
  74. package/dist/commands/world.d.ts.map +1 -0
  75. package/dist/commands/world.js +135 -0
  76. package/dist/commands/world.js.map +1 -0
  77. package/dist/domain/index.d.ts +2 -0
  78. package/dist/domain/index.d.ts.map +1 -0
  79. package/dist/domain/index.js +7 -0
  80. package/dist/domain/index.js.map +1 -0
  81. package/dist/index.d.ts +3 -0
  82. package/dist/index.d.ts.map +1 -0
  83. package/dist/index.js +609 -0
  84. package/dist/index.js.map +1 -0
  85. package/dist/infrastructure/adapters/ClackPromptAdapter.d.ts +29 -0
  86. package/dist/infrastructure/adapters/ClackPromptAdapter.d.ts.map +1 -0
  87. package/dist/infrastructure/adapters/ClackPromptAdapter.js +419 -0
  88. package/dist/infrastructure/adapters/ClackPromptAdapter.js.map +1 -0
  89. package/dist/infrastructure/adapters/index.d.ts +3 -0
  90. package/dist/infrastructure/adapters/index.d.ts.map +1 -0
  91. package/dist/infrastructure/adapters/index.js +5 -0
  92. package/dist/infrastructure/adapters/index.js.map +1 -0
  93. package/dist/infrastructure/di/container.d.ts +47 -0
  94. package/dist/infrastructure/di/container.d.ts.map +1 -0
  95. package/dist/infrastructure/di/container.js +140 -0
  96. package/dist/infrastructure/di/container.js.map +1 -0
  97. package/dist/infrastructure/di/index.d.ts +2 -0
  98. package/dist/infrastructure/di/index.d.ts.map +1 -0
  99. package/dist/infrastructure/di/index.js +2 -0
  100. package/dist/infrastructure/di/index.js.map +1 -0
  101. package/dist/infrastructure/index.d.ts +4 -0
  102. package/dist/infrastructure/index.d.ts.map +1 -0
  103. package/dist/infrastructure/index.js +7 -0
  104. package/dist/infrastructure/index.js.map +1 -0
  105. package/dist/lib/mojang-api.d.ts +51 -0
  106. package/dist/lib/mojang-api.d.ts.map +1 -0
  107. package/dist/lib/mojang-api.js +136 -0
  108. package/dist/lib/mojang-api.js.map +1 -0
  109. package/dist/lib/player-cache.d.ts +79 -0
  110. package/dist/lib/player-cache.d.ts.map +1 -0
  111. package/dist/lib/player-cache.js +302 -0
  112. package/dist/lib/player-cache.js.map +1 -0
  113. package/dist/lib/player-json.d.ts +69 -0
  114. package/dist/lib/player-json.d.ts.map +1 -0
  115. package/dist/lib/player-json.js +96 -0
  116. package/dist/lib/player-json.js.map +1 -0
  117. package/dist/lib/prompts/action-select.d.ts +23 -0
  118. package/dist/lib/prompts/action-select.d.ts.map +1 -0
  119. package/dist/lib/prompts/action-select.js +124 -0
  120. package/dist/lib/prompts/action-select.js.map +1 -0
  121. package/dist/lib/prompts/index.d.ts +7 -0
  122. package/dist/lib/prompts/index.d.ts.map +1 -0
  123. package/dist/lib/prompts/index.js +7 -0
  124. package/dist/lib/prompts/index.js.map +1 -0
  125. package/dist/lib/prompts/player-select.d.ts +25 -0
  126. package/dist/lib/prompts/player-select.d.ts.map +1 -0
  127. package/dist/lib/prompts/player-select.js +122 -0
  128. package/dist/lib/prompts/player-select.js.map +1 -0
  129. package/dist/lib/prompts/server-select.d.ts +26 -0
  130. package/dist/lib/prompts/server-select.d.ts.map +1 -0
  131. package/dist/lib/prompts/server-select.js +99 -0
  132. package/dist/lib/prompts/server-select.js.map +1 -0
  133. package/dist/lib/rcon.d.ts +53 -0
  134. package/dist/lib/rcon.d.ts.map +1 -0
  135. package/dist/lib/rcon.js +131 -0
  136. package/dist/lib/rcon.js.map +1 -0
  137. package/dist/lib/shell.d.ts +109 -0
  138. package/dist/lib/shell.d.ts.map +1 -0
  139. package/dist/lib/shell.js +318 -0
  140. package/dist/lib/shell.js.map +1 -0
  141. package/package.json +2 -2
@@ -0,0 +1,2 @@
1
+ export { type ICreateServerUseCase, type CreateServerConfig, type IDeleteServerUseCase, type IServerStatusUseCase, type IWorldManagementUseCase, type IBackupUseCase, type IPlayerLookupUseCase, type IPromptPort, type IShellPort, type CreateServerOptions, type LogsOptions, type ShellResult, type IServerRepository, type ServerConfigData, type IWorldRepository, type WorldLockData, type IDocProvider, type DocServerTypeInfo, type DocEnvVarInfo, type DocVersionInfo, type DocMemoryInfo, CreateServerUseCase, DeleteServerUseCase, ServerStatusUseCase, WorldManagementUseCase, BackupUseCase, PlayerLookupUseCase, } from '@minecraft-docker/shared';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/application/index.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,KAAK,oBAAoB,EAEzB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,aAAa,EAElB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,aAAa,EACb,mBAAmB,GACpB,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,5 @@
1
+ // Re-export from shared package for backward compatibility
2
+ export {
3
+ // Use Cases
4
+ CreateServerUseCase, DeleteServerUseCase, ServerStatusUseCase, WorldManagementUseCase, BackupUseCase, PlayerLookupUseCase, } from '@minecraft-docker/shared';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/application/index.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,OAAO;AAwBL,YAAY;AACZ,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,aAAa,EACb,mBAAmB,GACpB,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Backup command options
3
+ */
4
+ export interface BackupCommandOptions {
5
+ root?: string;
6
+ subCommand?: string;
7
+ message?: string;
8
+ commitHash?: string;
9
+ json?: boolean;
10
+ auto?: boolean;
11
+ }
12
+ /**
13
+ * Execute backup command
14
+ */
15
+ export declare function backupCommand(options: BackupCommandOptions): Promise<number>;
16
+ //# sourceMappingURL=backup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../../src/commands/backup.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BlF"}
@@ -0,0 +1,182 @@
1
+ import { Paths, log, colors } from '@minecraft-docker/shared';
2
+ import { getContainer } from '../infrastructure/index.js';
3
+ /**
4
+ * Execute backup command
5
+ */
6
+ export async function backupCommand(options) {
7
+ const paths = new Paths(options.root);
8
+ // Check if initialized
9
+ if (!paths.isInitialized()) {
10
+ log.error('Platform not initialized. Run: mcctl init');
11
+ return 1;
12
+ }
13
+ const container = getContainer(options.root);
14
+ const subCommand = options.subCommand ?? 'status';
15
+ switch (subCommand) {
16
+ case 'status':
17
+ return backupStatus(container, options);
18
+ case 'push':
19
+ return backupPush(container, options);
20
+ case 'history':
21
+ return backupHistory(container, options);
22
+ case 'restore':
23
+ return backupRestore(container, options);
24
+ default:
25
+ log.error(`Unknown backup subcommand: ${subCommand}`);
26
+ console.log('Usage: mcctl backup [status|push|history|restore]');
27
+ return 1;
28
+ }
29
+ }
30
+ /**
31
+ * Show backup status
32
+ */
33
+ async function backupStatus(container, options) {
34
+ const useCase = container.backupUseCase;
35
+ try {
36
+ const status = await useCase.status();
37
+ if (options.json) {
38
+ console.log(JSON.stringify(status, null, 2));
39
+ return 0;
40
+ }
41
+ console.log('');
42
+ console.log(colors.bold('Backup Configuration:'));
43
+ console.log('');
44
+ if (!status.configured) {
45
+ console.log(colors.yellow(' Status: Not configured'));
46
+ console.log('');
47
+ console.log(' To enable backups, set in .env:');
48
+ console.log(colors.dim(' BACKUP_GITHUB_TOKEN=your-token'));
49
+ console.log(colors.dim(' BACKUP_GITHUB_REPO=username/repo'));
50
+ console.log('');
51
+ return 0;
52
+ }
53
+ console.log(colors.green(' Status: Configured'));
54
+ if (status.repository) {
55
+ console.log(` Repository: ${colors.cyan(status.repository)}`);
56
+ }
57
+ if (status.branch) {
58
+ console.log(` Branch: ${status.branch}`);
59
+ }
60
+ if (status.lastBackup) {
61
+ console.log(` Last backup: ${status.lastBackup.toLocaleString()}`);
62
+ }
63
+ if (status.autoBackupEnabled !== undefined) {
64
+ console.log(` Auto backup: ${status.autoBackupEnabled ? colors.green('enabled') : colors.dim('disabled')}`);
65
+ }
66
+ console.log('');
67
+ return 0;
68
+ }
69
+ catch (error) {
70
+ const message = error instanceof Error ? error.message : String(error);
71
+ log.error(message);
72
+ return 1;
73
+ }
74
+ }
75
+ /**
76
+ * Push backup to GitHub
77
+ */
78
+ async function backupPush(container, options) {
79
+ const useCase = container.backupUseCase;
80
+ try {
81
+ // If message provided, use direct push
82
+ if (options.message) {
83
+ const result = await useCase.pushWithMessage(options.message);
84
+ if (result.success) {
85
+ console.log('');
86
+ console.log(colors.green('✓ Backup complete!'));
87
+ if (result.commitHash) {
88
+ console.log(` Commit: ${colors.cyan(result.commitHash)}`);
89
+ }
90
+ console.log('');
91
+ return 0;
92
+ }
93
+ else {
94
+ log.error(result.error || 'Backup failed');
95
+ return 1;
96
+ }
97
+ }
98
+ // Interactive mode
99
+ const result = await useCase.push();
100
+ return result.success ? 0 : 1;
101
+ }
102
+ catch (error) {
103
+ const prompt = container.promptPort;
104
+ if (prompt.isCancel(error)) {
105
+ return 0;
106
+ }
107
+ const message = error instanceof Error ? error.message : String(error);
108
+ log.error(message);
109
+ return 1;
110
+ }
111
+ }
112
+ /**
113
+ * Show backup history
114
+ */
115
+ async function backupHistory(container, options) {
116
+ const useCase = container.backupUseCase;
117
+ try {
118
+ const history = await useCase.history();
119
+ if (history.length === 0) {
120
+ console.log('No backup history found');
121
+ return 0;
122
+ }
123
+ if (options.json) {
124
+ console.log(JSON.stringify(history, null, 2));
125
+ return 0;
126
+ }
127
+ console.log('');
128
+ console.log(colors.bold('Backup History:'));
129
+ console.log('');
130
+ for (const entry of history.slice(0, 10)) {
131
+ const hash = colors.cyan(entry.commitHash.substring(0, 7));
132
+ const date = colors.dim(entry.date.toLocaleDateString());
133
+ console.log(` ${hash} ${entry.message} ${date}`);
134
+ }
135
+ if (history.length > 10) {
136
+ console.log(colors.dim(` ... and ${history.length - 10} more`));
137
+ }
138
+ console.log('');
139
+ return 0;
140
+ }
141
+ catch (error) {
142
+ const message = error instanceof Error ? error.message : String(error);
143
+ log.error(message);
144
+ return 1;
145
+ }
146
+ }
147
+ /**
148
+ * Restore from backup
149
+ */
150
+ async function backupRestore(container, options) {
151
+ const useCase = container.backupUseCase;
152
+ try {
153
+ // If commit hash provided, use direct restore
154
+ if (options.commitHash) {
155
+ const result = await useCase.restoreFromCommit(options.commitHash);
156
+ if (result.success) {
157
+ console.log('');
158
+ console.log(colors.green('✓ Restore complete!'));
159
+ console.log(` Restored from: ${colors.cyan(result.commitHash.substring(0, 7))}`);
160
+ console.log('');
161
+ return 0;
162
+ }
163
+ else {
164
+ log.error(result.error || 'Restore failed');
165
+ return 1;
166
+ }
167
+ }
168
+ // Interactive mode
169
+ const result = await useCase.restore();
170
+ return result.success ? 0 : 1;
171
+ }
172
+ catch (error) {
173
+ const prompt = container.promptPort;
174
+ if (prompt.isCancel(error)) {
175
+ return 0;
176
+ }
177
+ const message = error instanceof Error ? error.message : String(error);
178
+ log.error(message);
179
+ return 1;
180
+ }
181
+ }
182
+ //# sourceMappingURL=backup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.js","sourceRoot":"","sources":["../../src/commands/backup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface BanCommandOptions {
2
+ root?: string;
3
+ serverName?: string;
4
+ subCommand?: 'list' | 'add' | 'remove' | 'ip';
5
+ target?: string;
6
+ reason?: string;
7
+ ipAction?: 'list' | 'add' | 'remove';
8
+ json?: boolean;
9
+ }
10
+ /**
11
+ * Manage server bans
12
+ */
13
+ export declare function banCommand(options: BanCommandOptions): Promise<number>;
14
+ //# sourceMappingURL=ban.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ban.d.ts","sourceRoot":"","sources":["../../src/commands/ban.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6D5E"}
@@ -0,0 +1,418 @@
1
+ import { join } from 'node:path';
2
+ import { Paths, log, colors } from '@minecraft-docker/shared';
3
+ import { ShellExecutor } from '../lib/shell.js';
4
+ import { isContainerRunning, execRconWithOutput, getContainerName } from '../lib/rcon.js';
5
+ import { readBannedPlayersJson, writeBannedPlayersJson, readBannedIpsJson, writeBannedIpsJson, findBannedPlayerByName, findBannedIp, createTimestamp, } from '../lib/player-json.js';
6
+ /**
7
+ * Manage server bans
8
+ */
9
+ export async function banCommand(options) {
10
+ const paths = new Paths(options.root);
11
+ if (!paths.isInitialized()) {
12
+ log.error('Platform not initialized. Run: mcctl init');
13
+ return 1;
14
+ }
15
+ if (!options.serverName) {
16
+ log.error('Server name is required');
17
+ log.info('Usage: mcctl ban <server> <list|add|remove|ip> [player/ip] [reason]');
18
+ return 1;
19
+ }
20
+ if (!options.subCommand) {
21
+ log.error('Action is required: list, add, remove, ip');
22
+ log.info('Usage: mcctl ban <server> <list|add|remove|ip> [player/ip] [reason]');
23
+ return 1;
24
+ }
25
+ const shell = new ShellExecutor(paths);
26
+ const config = shell.readConfig(options.serverName);
27
+ if (config === null) {
28
+ log.error(`Server '${options.serverName}' not found`);
29
+ return 1;
30
+ }
31
+ const containerName = getContainerName(options.serverName);
32
+ const isRunning = await isContainerRunning(containerName);
33
+ const bannedPlayersPath = join(paths.servers, options.serverName, 'data', 'banned-players.json');
34
+ const bannedIpsPath = join(paths.servers, options.serverName, 'data', 'banned-ips.json');
35
+ switch (options.subCommand) {
36
+ case 'list':
37
+ return await listBannedPlayers(options, bannedPlayersPath, containerName, isRunning);
38
+ case 'add':
39
+ if (!options.target) {
40
+ log.error('Player name is required for ban');
41
+ log.info('Usage: mcctl ban <server> add <player> [reason]');
42
+ return 1;
43
+ }
44
+ return await banPlayer(options, bannedPlayersPath, containerName, isRunning);
45
+ case 'remove':
46
+ if (!options.target) {
47
+ log.error('Player name is required for unban');
48
+ log.info('Usage: mcctl ban <server> remove <player>');
49
+ return 1;
50
+ }
51
+ return await unbanPlayer(options, bannedPlayersPath, containerName, isRunning);
52
+ case 'ip':
53
+ return await handleIpBan(options, bannedIpsPath, containerName, isRunning);
54
+ default:
55
+ log.error(`Unknown action: ${options.subCommand}`);
56
+ log.info('Valid actions: list, add, remove, ip');
57
+ return 1;
58
+ }
59
+ }
60
+ /**
61
+ * List banned players
62
+ */
63
+ async function listBannedPlayers(options, bannedPlayersPath, containerName, isRunning) {
64
+ let players = [];
65
+ let source = 'json';
66
+ if (isRunning) {
67
+ const result = await execRconWithOutput(containerName, ['banlist', 'players']);
68
+ if (result.code === 0) {
69
+ // Parse output - format varies by MC version
70
+ const match = result.output.match(/:\s*(.+)$/);
71
+ if (match && match[1] && !match[1].includes('There are no')) {
72
+ const names = match[1]
73
+ .split(',')
74
+ .map((s) => s.trim())
75
+ .filter(Boolean);
76
+ players = names.map((name) => ({
77
+ uuid: '',
78
+ name,
79
+ created: '',
80
+ source: 'rcon',
81
+ expires: 'forever',
82
+ reason: '',
83
+ }));
84
+ source = 'rcon';
85
+ }
86
+ }
87
+ }
88
+ // Fallback to JSON
89
+ if (players.length === 0 || source !== 'rcon') {
90
+ players = await readBannedPlayersJson(bannedPlayersPath);
91
+ source = 'json';
92
+ }
93
+ if (options.json) {
94
+ console.log(JSON.stringify({
95
+ server: options.serverName,
96
+ running: isRunning,
97
+ players: players.map((p) => ({
98
+ name: p.name,
99
+ reason: p.reason,
100
+ created: p.created,
101
+ })),
102
+ source,
103
+ }));
104
+ }
105
+ else {
106
+ console.log(colors.bold(`\nBanned Players for ${options.serverName}:\n`));
107
+ if (players.length === 0) {
108
+ console.log(' (none)');
109
+ }
110
+ else {
111
+ for (const player of players) {
112
+ const reason = player.reason ? ` - ${player.reason}` : '';
113
+ console.log(` ${colors.red(player.name)}${colors.dim(reason)}`);
114
+ }
115
+ }
116
+ console.log('');
117
+ if (!isRunning) {
118
+ log.warn('Server is not running. Showing bans from JSON file');
119
+ }
120
+ }
121
+ return 0;
122
+ }
123
+ /**
124
+ * Ban a player
125
+ */
126
+ async function banPlayer(options, bannedPlayersPath, containerName, isRunning) {
127
+ const playerName = options.target;
128
+ const reason = options.reason || 'Banned by operator';
129
+ // Check if already banned
130
+ const bannedPlayers = await readBannedPlayersJson(bannedPlayersPath);
131
+ if (findBannedPlayerByName(bannedPlayers, playerName)) {
132
+ if (options.json) {
133
+ console.log(JSON.stringify({
134
+ success: false,
135
+ error: 'already_banned',
136
+ player: playerName,
137
+ server: options.serverName,
138
+ }));
139
+ }
140
+ else {
141
+ log.warn(`${playerName} is already banned`);
142
+ }
143
+ return 0;
144
+ }
145
+ let rconSuccess = false;
146
+ let rconMessage = '';
147
+ if (isRunning) {
148
+ const rconCmd = reason ? ['ban', playerName, reason] : ['ban', playerName];
149
+ const result = await execRconWithOutput(containerName, rconCmd);
150
+ rconSuccess = result.code === 0;
151
+ rconMessage = result.output.trim();
152
+ }
153
+ // Update JSON file for non-running server
154
+ if (!isRunning) {
155
+ const newEntry = {
156
+ uuid: '', // Will be populated by server on start
157
+ name: playerName,
158
+ created: createTimestamp(),
159
+ source: 'mcctl',
160
+ expires: 'forever',
161
+ reason,
162
+ };
163
+ bannedPlayers.push(newEntry);
164
+ await writeBannedPlayersJson(bannedPlayersPath, bannedPlayers);
165
+ }
166
+ if (options.json) {
167
+ console.log(JSON.stringify({
168
+ success: true,
169
+ player: playerName,
170
+ reason,
171
+ server: options.serverName,
172
+ rcon: isRunning ? { success: rconSuccess, message: rconMessage } : null,
173
+ running: isRunning,
174
+ }));
175
+ }
176
+ else {
177
+ if (isRunning && rconSuccess) {
178
+ console.log(colors.green(`${playerName} has been banned (applied immediately)`));
179
+ }
180
+ else if (isRunning && !rconSuccess) {
181
+ console.log(colors.yellow(`RCON: ${rconMessage}`));
182
+ }
183
+ else {
184
+ console.log(colors.yellow(`Server is not running.`));
185
+ console.log(colors.green(`Ban saved. Will apply on next start.`));
186
+ }
187
+ }
188
+ return 0;
189
+ }
190
+ /**
191
+ * Unban a player
192
+ */
193
+ async function unbanPlayer(options, bannedPlayersPath, containerName, isRunning) {
194
+ const playerName = options.target;
195
+ let rconSuccess = false;
196
+ let rconMessage = '';
197
+ if (isRunning) {
198
+ const result = await execRconWithOutput(containerName, ['pardon', playerName]);
199
+ rconSuccess = result.code === 0;
200
+ rconMessage = result.output.trim();
201
+ }
202
+ // Update JSON file
203
+ const bannedPlayers = await readBannedPlayersJson(bannedPlayersPath);
204
+ const filteredPlayers = bannedPlayers.filter((p) => p.name.toLowerCase() !== playerName.toLowerCase());
205
+ if (filteredPlayers.length !== bannedPlayers.length) {
206
+ await writeBannedPlayersJson(bannedPlayersPath, filteredPlayers);
207
+ }
208
+ if (options.json) {
209
+ console.log(JSON.stringify({
210
+ success: true,
211
+ player: playerName,
212
+ server: options.serverName,
213
+ rcon: isRunning ? { success: rconSuccess, message: rconMessage } : null,
214
+ running: isRunning,
215
+ }));
216
+ }
217
+ else {
218
+ if (isRunning && rconSuccess) {
219
+ console.log(colors.green(`${playerName} has been unbanned (applied immediately)`));
220
+ }
221
+ else if (isRunning && !rconSuccess) {
222
+ console.log(colors.yellow(`RCON: ${rconMessage}`));
223
+ }
224
+ else {
225
+ console.log(colors.yellow(`Server is not running.`));
226
+ console.log(colors.green(`Unban saved. Will apply on next start.`));
227
+ }
228
+ }
229
+ return 0;
230
+ }
231
+ /**
232
+ * Handle IP ban commands
233
+ */
234
+ async function handleIpBan(options, bannedIpsPath, containerName, isRunning) {
235
+ const ipAction = options.ipAction;
236
+ if (!ipAction) {
237
+ log.error('IP action is required: list, add, remove');
238
+ log.info('Usage: mcctl ban <server> ip <list|add|remove> [ip] [reason]');
239
+ return 1;
240
+ }
241
+ switch (ipAction) {
242
+ case 'list':
243
+ return await listBannedIps(options, bannedIpsPath, containerName, isRunning);
244
+ case 'add':
245
+ if (!options.target) {
246
+ log.error('IP address is required');
247
+ log.info('Usage: mcctl ban <server> ip add <ip> [reason]');
248
+ return 1;
249
+ }
250
+ return await banIp(options, bannedIpsPath, containerName, isRunning);
251
+ case 'remove':
252
+ if (!options.target) {
253
+ log.error('IP address is required');
254
+ log.info('Usage: mcctl ban <server> ip remove <ip>');
255
+ return 1;
256
+ }
257
+ return await unbanIp(options, bannedIpsPath, containerName, isRunning);
258
+ default:
259
+ log.error(`Unknown IP action: ${ipAction}`);
260
+ return 1;
261
+ }
262
+ }
263
+ /**
264
+ * List banned IPs
265
+ */
266
+ async function listBannedIps(options, bannedIpsPath, containerName, isRunning) {
267
+ let ips = [];
268
+ let source = 'json';
269
+ if (isRunning) {
270
+ const result = await execRconWithOutput(containerName, ['banlist', 'ips']);
271
+ if (result.code === 0) {
272
+ const match = result.output.match(/:\s*(.+)$/);
273
+ if (match && match[1] && !match[1].includes('There are no')) {
274
+ const ipList = match[1]
275
+ .split(',')
276
+ .map((s) => s.trim())
277
+ .filter(Boolean);
278
+ ips = ipList.map((ip) => ({
279
+ ip,
280
+ created: '',
281
+ source: 'rcon',
282
+ expires: 'forever',
283
+ reason: '',
284
+ }));
285
+ source = 'rcon';
286
+ }
287
+ }
288
+ }
289
+ if (ips.length === 0 || source !== 'rcon') {
290
+ ips = await readBannedIpsJson(bannedIpsPath);
291
+ source = 'json';
292
+ }
293
+ if (options.json) {
294
+ console.log(JSON.stringify({
295
+ server: options.serverName,
296
+ running: isRunning,
297
+ ips: ips.map((entry) => ({
298
+ ip: entry.ip,
299
+ reason: entry.reason,
300
+ created: entry.created,
301
+ })),
302
+ source,
303
+ }));
304
+ }
305
+ else {
306
+ console.log(colors.bold(`\nBanned IPs for ${options.serverName}:\n`));
307
+ if (ips.length === 0) {
308
+ console.log(' (none)');
309
+ }
310
+ else {
311
+ for (const entry of ips) {
312
+ const reason = entry.reason ? ` - ${entry.reason}` : '';
313
+ console.log(` ${colors.red(entry.ip)}${colors.dim(reason)}`);
314
+ }
315
+ }
316
+ console.log('');
317
+ }
318
+ return 0;
319
+ }
320
+ /**
321
+ * Ban an IP
322
+ */
323
+ async function banIp(options, bannedIpsPath, containerName, isRunning) {
324
+ const ip = options.target;
325
+ const reason = options.reason || 'Banned by operator';
326
+ const bannedIps = await readBannedIpsJson(bannedIpsPath);
327
+ if (findBannedIp(bannedIps, ip)) {
328
+ if (options.json) {
329
+ console.log(JSON.stringify({
330
+ success: false,
331
+ error: 'already_banned',
332
+ ip,
333
+ server: options.serverName,
334
+ }));
335
+ }
336
+ else {
337
+ log.warn(`${ip} is already banned`);
338
+ }
339
+ return 0;
340
+ }
341
+ let rconSuccess = false;
342
+ let rconMessage = '';
343
+ if (isRunning) {
344
+ const rconCmd = reason ? ['ban-ip', ip, reason] : ['ban-ip', ip];
345
+ const result = await execRconWithOutput(containerName, rconCmd);
346
+ rconSuccess = result.code === 0;
347
+ rconMessage = result.output.trim();
348
+ }
349
+ if (!isRunning) {
350
+ const newEntry = {
351
+ ip,
352
+ created: createTimestamp(),
353
+ source: 'mcctl',
354
+ expires: 'forever',
355
+ reason,
356
+ };
357
+ bannedIps.push(newEntry);
358
+ await writeBannedIpsJson(bannedIpsPath, bannedIps);
359
+ }
360
+ if (options.json) {
361
+ console.log(JSON.stringify({
362
+ success: true,
363
+ ip,
364
+ reason,
365
+ server: options.serverName,
366
+ rcon: isRunning ? { success: rconSuccess, message: rconMessage } : null,
367
+ running: isRunning,
368
+ }));
369
+ }
370
+ else {
371
+ if (isRunning && rconSuccess) {
372
+ console.log(colors.green(`${ip} has been banned (applied immediately)`));
373
+ }
374
+ else if (!isRunning) {
375
+ console.log(colors.yellow(`Server is not running.`));
376
+ console.log(colors.green(`IP ban saved. Will apply on next start.`));
377
+ }
378
+ }
379
+ return 0;
380
+ }
381
+ /**
382
+ * Unban an IP
383
+ */
384
+ async function unbanIp(options, bannedIpsPath, containerName, isRunning) {
385
+ const ip = options.target;
386
+ let rconSuccess = false;
387
+ let rconMessage = '';
388
+ if (isRunning) {
389
+ const result = await execRconWithOutput(containerName, ['pardon-ip', ip]);
390
+ rconSuccess = result.code === 0;
391
+ rconMessage = result.output.trim();
392
+ }
393
+ const bannedIps = await readBannedIpsJson(bannedIpsPath);
394
+ const filteredIps = bannedIps.filter((entry) => entry.ip !== ip);
395
+ if (filteredIps.length !== bannedIps.length) {
396
+ await writeBannedIpsJson(bannedIpsPath, filteredIps);
397
+ }
398
+ if (options.json) {
399
+ console.log(JSON.stringify({
400
+ success: true,
401
+ ip,
402
+ server: options.serverName,
403
+ rcon: isRunning ? { success: rconSuccess, message: rconMessage } : null,
404
+ running: isRunning,
405
+ }));
406
+ }
407
+ else {
408
+ if (isRunning && rconSuccess) {
409
+ console.log(colors.green(`${ip} has been unbanned (applied immediately)`));
410
+ }
411
+ else if (!isRunning) {
412
+ console.log(colors.yellow(`Server is not running.`));
413
+ console.log(colors.green(`IP unban saved. Will apply on next start.`));
414
+ }
415
+ }
416
+ return 0;
417
+ }
418
+ //# sourceMappingURL=ban.js.map