@minecraft-docker/mcctl-api 1.7.6

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 (82) hide show
  1. package/README.md +142 -0
  2. package/dist/app.d.ts +7 -0
  3. package/dist/app.d.ts.map +1 -0
  4. package/dist/app.js +83 -0
  5. package/dist/app.js.map +1 -0
  6. package/dist/config/index.d.ts +32 -0
  7. package/dist/config/index.d.ts.map +1 -0
  8. package/dist/config/index.js +124 -0
  9. package/dist/config/index.js.map +1 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +20 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/lib/rcon.d.ts +35 -0
  15. package/dist/lib/rcon.d.ts.map +1 -0
  16. package/dist/lib/rcon.js +90 -0
  17. package/dist/lib/rcon.js.map +1 -0
  18. package/dist/plugins/auth.d.ts +32 -0
  19. package/dist/plugins/auth.d.ts.map +1 -0
  20. package/dist/plugins/auth.js +194 -0
  21. package/dist/plugins/auth.js.map +1 -0
  22. package/dist/plugins/swagger.d.ts +170 -0
  23. package/dist/plugins/swagger.d.ts.map +1 -0
  24. package/dist/plugins/swagger.js +211 -0
  25. package/dist/plugins/swagger.js.map +1 -0
  26. package/dist/routes/auth.d.ts +12 -0
  27. package/dist/routes/auth.d.ts.map +1 -0
  28. package/dist/routes/auth.js +144 -0
  29. package/dist/routes/auth.js.map +1 -0
  30. package/dist/routes/backup.d.ts +9 -0
  31. package/dist/routes/backup.d.ts.map +1 -0
  32. package/dist/routes/backup.js +271 -0
  33. package/dist/routes/backup.js.map +1 -0
  34. package/dist/routes/console.d.ts +6 -0
  35. package/dist/routes/console.d.ts.map +1 -0
  36. package/dist/routes/console.js +90 -0
  37. package/dist/routes/console.js.map +1 -0
  38. package/dist/routes/players.d.ts +9 -0
  39. package/dist/routes/players.d.ts.map +1 -0
  40. package/dist/routes/players.js +353 -0
  41. package/dist/routes/players.js.map +1 -0
  42. package/dist/routes/router.d.ts +10 -0
  43. package/dist/routes/router.d.ts.map +1 -0
  44. package/dist/routes/router.js +55 -0
  45. package/dist/routes/router.js.map +1 -0
  46. package/dist/routes/servers/actions.d.ts +6 -0
  47. package/dist/routes/servers/actions.d.ts.map +1 -0
  48. package/dist/routes/servers/actions.js +65 -0
  49. package/dist/routes/servers/actions.js.map +1 -0
  50. package/dist/routes/servers.d.ts +10 -0
  51. package/dist/routes/servers.d.ts.map +1 -0
  52. package/dist/routes/servers.js +403 -0
  53. package/dist/routes/servers.js.map +1 -0
  54. package/dist/routes/worlds.d.ts +10 -0
  55. package/dist/routes/worlds.d.ts.map +1 -0
  56. package/dist/routes/worlds.js +341 -0
  57. package/dist/routes/worlds.js.map +1 -0
  58. package/dist/schemas/backup.d.ts +47 -0
  59. package/dist/schemas/backup.d.ts.map +1 -0
  60. package/dist/schemas/backup.js +43 -0
  61. package/dist/schemas/backup.js.map +1 -0
  62. package/dist/schemas/player.d.ts +46 -0
  63. package/dist/schemas/player.d.ts.map +1 -0
  64. package/dist/schemas/player.js +46 -0
  65. package/dist/schemas/player.js.map +1 -0
  66. package/dist/schemas/router.d.ts +42 -0
  67. package/dist/schemas/router.d.ts.map +1 -0
  68. package/dist/schemas/router.js +26 -0
  69. package/dist/schemas/router.js.map +1 -0
  70. package/dist/schemas/server.d.ts +139 -0
  71. package/dist/schemas/server.d.ts.map +1 -0
  72. package/dist/schemas/server.js +124 -0
  73. package/dist/schemas/server.js.map +1 -0
  74. package/dist/schemas/world.d.ts +142 -0
  75. package/dist/schemas/world.d.ts.map +1 -0
  76. package/dist/schemas/world.js +124 -0
  77. package/dist/schemas/world.js.map +1 -0
  78. package/dist/utils/docker-compose.d.ts +23 -0
  79. package/dist/utils/docker-compose.d.ts.map +1 -0
  80. package/dist/utils/docker-compose.js +100 -0
  81. package/dist/utils/docker-compose.js.map +1 -0
  82. package/package.json +69 -0
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Authentication Routes
3
+ *
4
+ * Handles user authentication for the mcctl-console.
5
+ * Validates credentials against users.yaml file.
6
+ */
7
+ import { join } from 'node:path';
8
+ import { YamlUserRepository, Username } from '@minecraft-docker/shared';
9
+ /**
10
+ * Register authentication routes
11
+ */
12
+ export default async function authRoutes(app) {
13
+ /**
14
+ * POST /api/auth/login
15
+ *
16
+ * Authenticate user with username and password.
17
+ * Returns user info on success, 401 on failure.
18
+ */
19
+ app.post('/api/auth/login', {
20
+ schema: {
21
+ description: 'Authenticate user with credentials',
22
+ tags: ['auth'],
23
+ body: {
24
+ type: 'object',
25
+ required: ['username', 'password'],
26
+ properties: {
27
+ username: { type: 'string', description: 'Username' },
28
+ password: { type: 'string', description: 'Password' },
29
+ },
30
+ },
31
+ response: {
32
+ 200: {
33
+ description: 'Authentication successful',
34
+ type: 'object',
35
+ properties: {
36
+ id: { type: 'string' },
37
+ username: { type: 'string' },
38
+ role: { type: 'string' },
39
+ name: { type: 'string' },
40
+ },
41
+ },
42
+ 401: {
43
+ description: 'Authentication failed',
44
+ type: 'object',
45
+ properties: {
46
+ error: { type: 'string' },
47
+ message: { type: 'string' },
48
+ },
49
+ },
50
+ },
51
+ },
52
+ }, async (request, reply) => {
53
+ const { username, password } = request.body;
54
+ if (!username || !password) {
55
+ return reply.status(401).send({
56
+ error: 'Unauthorized',
57
+ message: 'Username and password are required',
58
+ });
59
+ }
60
+ try {
61
+ // Get users.yaml path from MCCTL_ROOT
62
+ const mcctlRoot = process.env['MCCTL_ROOT'] || process.cwd();
63
+ const usersPath = join(mcctlRoot, 'users.yaml');
64
+ const userRepo = new YamlUserRepository(usersPath);
65
+ // Find user by username
66
+ const usernameVO = Username.create(username);
67
+ const user = await userRepo.findByUsername(usernameVO);
68
+ if (!user) {
69
+ app.log.warn({ username }, 'Login failed: user not found');
70
+ return reply.status(401).send({
71
+ error: 'Unauthorized',
72
+ message: 'Invalid username or password',
73
+ });
74
+ }
75
+ // Verify password
76
+ const isValid = await userRepo.verifyPassword(password, user.passwordHash);
77
+ if (!isValid) {
78
+ app.log.warn({ username }, 'Login failed: invalid password');
79
+ return reply.status(401).send({
80
+ error: 'Unauthorized',
81
+ message: 'Invalid username or password',
82
+ });
83
+ }
84
+ app.log.info({ username, role: user.role }, 'Login successful');
85
+ // Return user info (without password hash)
86
+ return reply.send({
87
+ id: user.id,
88
+ username: user.username.value,
89
+ role: user.role,
90
+ name: user.username.value, // Use username as display name
91
+ });
92
+ }
93
+ catch (error) {
94
+ app.log.error(error, 'Login error');
95
+ return reply.status(500).send({
96
+ error: 'Internal Server Error',
97
+ message: 'Authentication service error',
98
+ });
99
+ }
100
+ });
101
+ /**
102
+ * GET /api/auth/me
103
+ *
104
+ * Get current user info (requires authentication via X-User header from BFF proxy).
105
+ */
106
+ app.get('/api/auth/me', {
107
+ schema: {
108
+ description: 'Get current authenticated user info',
109
+ tags: ['auth'],
110
+ response: {
111
+ 200: {
112
+ description: 'User info',
113
+ type: 'object',
114
+ properties: {
115
+ username: { type: 'string' },
116
+ role: { type: 'string' },
117
+ },
118
+ },
119
+ 401: {
120
+ description: 'Not authenticated',
121
+ type: 'object',
122
+ properties: {
123
+ error: { type: 'string' },
124
+ message: { type: 'string' },
125
+ },
126
+ },
127
+ },
128
+ },
129
+ }, async (request, reply) => {
130
+ const username = request.headers['x-user'];
131
+ const role = request.headers['x-role'];
132
+ if (!username) {
133
+ return reply.status(401).send({
134
+ error: 'Unauthorized',
135
+ message: 'Not authenticated',
136
+ });
137
+ }
138
+ return reply.send({
139
+ username,
140
+ role: role || 'user',
141
+ });
142
+ });
143
+ }
144
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/routes/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { FastifyPluginAsync } from 'fastify';
2
+ /**
3
+ * Backup management routes plugin
4
+ */
5
+ declare const backupPlugin: FastifyPluginAsync;
6
+ declare const _default: FastifyPluginAsync;
7
+ export default _default;
8
+ export { backupPlugin };
9
+ //# sourceMappingURL=backup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../../src/routes/backup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,kBAAkB,EAAgC,MAAM,SAAS,CAAC;AA+B5F;;GAEG;AACH,QAAA,MAAM,YAAY,EAAE,kBAsRnB,CAAC;;AAEF,wBAGG;AAEH,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,271 @@
1
+ import fp from 'fastify-plugin';
2
+ import { exec } from 'child_process';
3
+ import { promisify } from 'util';
4
+ import { existsSync } from 'fs';
5
+ import { join } from 'path';
6
+ import { config } from '../config/index.js';
7
+ import { BackupStatusResponseSchema, BackupPushRequestSchema, BackupPushResponseSchema, BackupHistoryResponseSchema, BackupRestoreRequestSchema, BackupRestoreResponseSchema, ErrorResponseSchema, } from '../schemas/backup.js';
8
+ const execPromise = promisify(exec);
9
+ /**
10
+ * Backup management routes plugin
11
+ */
12
+ const backupPlugin = async (fastify) => {
13
+ const platformPath = config.platformPath;
14
+ const worldsPath = join(platformPath, 'worlds');
15
+ // Helper to check if backup is configured
16
+ const isBackupConfigured = () => {
17
+ const repo = process.env['BACKUP_GITHUB_REPO'];
18
+ const token = process.env['BACKUP_GITHUB_TOKEN'];
19
+ if (!repo || !token) {
20
+ return { configured: false };
21
+ }
22
+ return {
23
+ configured: true,
24
+ repository: repo,
25
+ branch: process.env['BACKUP_GITHUB_BRANCH'] || 'main',
26
+ };
27
+ };
28
+ /**
29
+ * GET /api/backup/status
30
+ * Get backup configuration status
31
+ */
32
+ fastify.get('/api/backup/status', {
33
+ schema: {
34
+ description: 'Get backup configuration status',
35
+ tags: ['backup'],
36
+ response: {
37
+ 200: BackupStatusResponseSchema,
38
+ 500: ErrorResponseSchema,
39
+ },
40
+ },
41
+ }, async (_request, reply) => {
42
+ try {
43
+ const status = isBackupConfigured();
44
+ // Get last backup date if configured
45
+ let lastBackup;
46
+ if (status.configured && existsSync(worldsPath)) {
47
+ try {
48
+ const { stdout } = await execPromise('git log -1 --format=%cI', {
49
+ cwd: worldsPath,
50
+ timeout: 5000,
51
+ });
52
+ lastBackup = stdout.trim() || undefined;
53
+ }
54
+ catch {
55
+ // Git not initialized or no commits
56
+ }
57
+ }
58
+ return reply.send({
59
+ configured: status.configured,
60
+ repository: status.repository,
61
+ branch: status.branch,
62
+ lastBackup,
63
+ });
64
+ }
65
+ catch (error) {
66
+ fastify.log.error(error, 'Failed to get backup status');
67
+ return reply.code(500).send({ error: 'InternalServerError', message: 'Failed to get backup status' });
68
+ }
69
+ });
70
+ /**
71
+ * POST /api/backup/push
72
+ * Push backup to GitHub
73
+ */
74
+ fastify.post('/api/backup/push', {
75
+ schema: {
76
+ description: 'Push worlds backup to GitHub',
77
+ tags: ['backup'],
78
+ body: BackupPushRequestSchema,
79
+ response: {
80
+ 200: BackupPushResponseSchema,
81
+ 400: ErrorResponseSchema,
82
+ 500: ErrorResponseSchema,
83
+ },
84
+ },
85
+ }, async (request, reply) => {
86
+ const { message } = request.body;
87
+ try {
88
+ const status = isBackupConfigured();
89
+ if (!status.configured) {
90
+ return reply.code(400).send({
91
+ error: 'BadRequest',
92
+ message: 'Backup not configured. Set BACKUP_GITHUB_REPO and BACKUP_GITHUB_TOKEN environment variables.',
93
+ });
94
+ }
95
+ if (!existsSync(worldsPath)) {
96
+ return reply.code(400).send({
97
+ error: 'BadRequest',
98
+ message: 'Worlds directory not found',
99
+ });
100
+ }
101
+ // Run backup script or git commands
102
+ const scriptPath = join(platformPath, 'scripts', 'backup.sh');
103
+ let command;
104
+ if (existsSync(scriptPath)) {
105
+ command = `bash "${scriptPath}" push ${message ? `--message "${message}"` : ''}`;
106
+ }
107
+ else {
108
+ // Direct git commands
109
+ const commitMessage = message || `Backup ${new Date().toISOString()}`;
110
+ command = `cd "${worldsPath}" && git add -A && git commit -m "${commitMessage}" && git push`;
111
+ }
112
+ const { stdout } = await execPromise(command, {
113
+ cwd: platformPath,
114
+ timeout: 120000, // 2 minute timeout
115
+ env: {
116
+ ...process.env,
117
+ MCCTL_ROOT: platformPath,
118
+ },
119
+ });
120
+ // Get commit hash
121
+ let commitHash;
122
+ try {
123
+ const { stdout: hashOut } = await execPromise('git rev-parse --short HEAD', { cwd: worldsPath });
124
+ commitHash = hashOut.trim();
125
+ }
126
+ catch {
127
+ // Ignore
128
+ }
129
+ return reply.send({
130
+ success: true,
131
+ commitHash,
132
+ message: 'Backup pushed successfully',
133
+ });
134
+ }
135
+ catch (error) {
136
+ const execError = error;
137
+ fastify.log.error(error, 'Failed to push backup');
138
+ // Check for "nothing to commit" which is not an error
139
+ if (execError.stderr?.includes('nothing to commit') || execError.message?.includes('nothing to commit')) {
140
+ return reply.send({
141
+ success: true,
142
+ message: 'No changes to backup',
143
+ });
144
+ }
145
+ return reply.code(500).send({
146
+ error: 'InternalServerError',
147
+ message: execError.stderr || execError.message || 'Failed to push backup',
148
+ });
149
+ }
150
+ });
151
+ /**
152
+ * GET /api/backup/history
153
+ * Get backup history (git commits)
154
+ */
155
+ fastify.get('/api/backup/history', {
156
+ schema: {
157
+ description: 'Get backup history (git commits)',
158
+ tags: ['backup'],
159
+ response: {
160
+ 200: BackupHistoryResponseSchema,
161
+ 400: ErrorResponseSchema,
162
+ 500: ErrorResponseSchema,
163
+ },
164
+ },
165
+ }, async (_request, reply) => {
166
+ try {
167
+ const status = isBackupConfigured();
168
+ if (!status.configured) {
169
+ return reply.code(400).send({
170
+ error: 'BadRequest',
171
+ message: 'Backup not configured',
172
+ });
173
+ }
174
+ if (!existsSync(worldsPath)) {
175
+ return reply.send({ commits: [], total: 0 });
176
+ }
177
+ // Get git log
178
+ const { stdout } = await execPromise('git log --format="%H|%s|%cI|%an" -n 20', { cwd: worldsPath, timeout: 10000 });
179
+ const commits = stdout.trim().split('\n')
180
+ .filter(Boolean)
181
+ .map(line => {
182
+ const [hash, message, date, author] = line.split('|');
183
+ return {
184
+ hash: hash?.substring(0, 7) || '',
185
+ message: message || '',
186
+ date: date || '',
187
+ author,
188
+ };
189
+ });
190
+ return reply.send({ commits, total: commits.length });
191
+ }
192
+ catch (error) {
193
+ const execError = error;
194
+ // Check for "not a git repository"
195
+ if (execError.stderr?.includes('not a git repository')) {
196
+ return reply.send({ commits: [], total: 0 });
197
+ }
198
+ fastify.log.error(error, 'Failed to get backup history');
199
+ return reply.code(500).send({ error: 'InternalServerError', message: 'Failed to get backup history' });
200
+ }
201
+ });
202
+ /**
203
+ * POST /api/backup/restore
204
+ * Restore from backup
205
+ */
206
+ fastify.post('/api/backup/restore', {
207
+ schema: {
208
+ description: 'Restore worlds from a backup commit',
209
+ tags: ['backup'],
210
+ body: BackupRestoreRequestSchema,
211
+ response: {
212
+ 200: BackupRestoreResponseSchema,
213
+ 400: ErrorResponseSchema,
214
+ 500: ErrorResponseSchema,
215
+ },
216
+ },
217
+ }, async (request, reply) => {
218
+ const { commitHash } = request.body;
219
+ try {
220
+ const status = isBackupConfigured();
221
+ if (!status.configured) {
222
+ return reply.code(400).send({
223
+ error: 'BadRequest',
224
+ message: 'Backup not configured',
225
+ });
226
+ }
227
+ if (!existsSync(worldsPath)) {
228
+ return reply.code(400).send({
229
+ error: 'BadRequest',
230
+ message: 'Worlds directory not found',
231
+ });
232
+ }
233
+ // Run backup restore script or git commands
234
+ const scriptPath = join(platformPath, 'scripts', 'backup.sh');
235
+ let command;
236
+ if (existsSync(scriptPath)) {
237
+ command = `bash "${scriptPath}" restore "${commitHash}"`;
238
+ }
239
+ else {
240
+ // Direct git command
241
+ command = `cd "${worldsPath}" && git checkout ${commitHash} .`;
242
+ }
243
+ await execPromise(command, {
244
+ cwd: platformPath,
245
+ timeout: 120000,
246
+ env: {
247
+ ...process.env,
248
+ MCCTL_ROOT: platformPath,
249
+ },
250
+ });
251
+ return reply.send({
252
+ success: true,
253
+ message: `Restored to commit ${commitHash}`,
254
+ });
255
+ }
256
+ catch (error) {
257
+ const execError = error;
258
+ fastify.log.error(error, 'Failed to restore backup');
259
+ return reply.code(500).send({
260
+ error: 'InternalServerError',
261
+ message: execError.stderr || execError.message || 'Failed to restore backup',
262
+ });
263
+ }
264
+ });
265
+ };
266
+ export default fp(backupPlugin, {
267
+ name: 'backup-routes',
268
+ fastify: '5.x',
269
+ });
270
+ export { backupPlugin };
271
+ //# sourceMappingURL=backup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.js","sourceRoot":"","sources":["../../src/routes/backup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { FastifyPluginAsync } from 'fastify';
2
+ declare const consoleRoutes: FastifyPluginAsync;
3
+ declare const _default: FastifyPluginAsync;
4
+ export default _default;
5
+ export { consoleRoutes };
6
+ //# sourceMappingURL=console.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/routes/console.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,kBAAkB,EAAE,MAAM,SAAS,CAAC;AA0E9D,QAAA,MAAM,aAAa,EAAE,kBA6CpB,CAAC;;AAMF,wBAGG;AAEH,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,90 @@
1
+ import fp from 'fastify-plugin';
2
+ import { execRcon } from '../lib/rcon.js';
3
+ // ============================================================
4
+ // JSON Schema for validation
5
+ // ============================================================
6
+ const execCommandSchema = {
7
+ body: {
8
+ type: 'object',
9
+ required: ['command'],
10
+ properties: {
11
+ command: {
12
+ type: 'string',
13
+ minLength: 1,
14
+ description: 'RCON command to execute',
15
+ },
16
+ },
17
+ },
18
+ params: {
19
+ type: 'object',
20
+ required: ['id'],
21
+ properties: {
22
+ id: {
23
+ type: 'string',
24
+ description: 'Server ID (name)',
25
+ },
26
+ },
27
+ },
28
+ response: {
29
+ 200: {
30
+ type: 'object',
31
+ properties: {
32
+ output: { type: 'string' },
33
+ exitCode: { type: 'number' },
34
+ },
35
+ },
36
+ 400: {
37
+ type: 'object',
38
+ properties: {
39
+ error: { type: 'string' },
40
+ message: { type: 'string' },
41
+ },
42
+ },
43
+ },
44
+ };
45
+ // ============================================================
46
+ // Plugin Implementation
47
+ // ============================================================
48
+ const consoleRoutes = async (fastify) => {
49
+ /**
50
+ * POST /servers/:id/console/exec
51
+ * Execute an RCON command on the specified server
52
+ */
53
+ fastify.post('/servers/:id/console/exec', {
54
+ schema: execCommandSchema,
55
+ }, async (request, reply) => {
56
+ const { id: serverId } = request.params;
57
+ const { command } = request.body;
58
+ // Validation is handled by schema, but double-check for safety
59
+ if (!command || command.trim().length === 0) {
60
+ return reply.code(400).send({
61
+ error: 'ValidationError',
62
+ message: 'Command is required and cannot be empty',
63
+ });
64
+ }
65
+ fastify.log.info({ serverId, command }, 'Executing RCON command');
66
+ try {
67
+ const result = await execRcon(serverId, command);
68
+ return reply.send({
69
+ output: result.output.trim(),
70
+ exitCode: result.exitCode,
71
+ });
72
+ }
73
+ catch (error) {
74
+ fastify.log.error({ serverId, command, error }, 'RCON execution failed');
75
+ return reply.code(500).send({
76
+ error: 'RconExecutionError',
77
+ message: error instanceof Error ? error.message : 'Unknown error',
78
+ });
79
+ }
80
+ });
81
+ };
82
+ // ============================================================
83
+ // Export
84
+ // ============================================================
85
+ export default fp(consoleRoutes, {
86
+ name: 'console-routes',
87
+ fastify: '5.x',
88
+ });
89
+ export { consoleRoutes };
90
+ //# sourceMappingURL=console.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"console.js","sourceRoot":"","sources":["../../src/routes/console.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { FastifyPluginAsync } from 'fastify';
2
+ /**
3
+ * Player management routes plugin
4
+ */
5
+ declare const playersPlugin: FastifyPluginAsync;
6
+ declare const _default: FastifyPluginAsync;
7
+ export default _default;
8
+ export { playersPlugin };
9
+ //# sourceMappingURL=players.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"players.d.ts","sourceRoot":"","sources":["../../src/routes/players.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,kBAAkB,EAAgC,MAAM,SAAS,CAAC;AA4C5F;;GAEG;AACH,QAAA,MAAM,aAAa,EAAE,kBA6VpB,CAAC;;AAEF,wBAGG;AAEH,OAAO,EAAE,aAAa,EAAE,CAAC"}