grim-server 0.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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +186 -0
  3. package/dist/artifacts/cache.d.ts +6 -0
  4. package/dist/artifacts/cache.d.ts.map +1 -0
  5. package/dist/artifacts/cache.js +73 -0
  6. package/dist/artifacts/cache.js.map +1 -0
  7. package/dist/artifacts/grim.d.ts +3 -0
  8. package/dist/artifacts/grim.d.ts.map +1 -0
  9. package/dist/artifacts/grim.js +94 -0
  10. package/dist/artifacts/grim.js.map +1 -0
  11. package/dist/artifacts/http.d.ts +8 -0
  12. package/dist/artifacts/http.d.ts.map +1 -0
  13. package/dist/artifacts/http.js +51 -0
  14. package/dist/artifacts/http.js.map +1 -0
  15. package/dist/artifacts/index.d.ts +5 -0
  16. package/dist/artifacts/index.d.ts.map +1 -0
  17. package/dist/artifacts/index.js +4 -0
  18. package/dist/artifacts/index.js.map +1 -0
  19. package/dist/artifacts/paper.d.ts +4 -0
  20. package/dist/artifacts/paper.d.ts.map +1 -0
  21. package/dist/artifacts/paper.js +56 -0
  22. package/dist/artifacts/paper.js.map +1 -0
  23. package/dist/artifacts/types.d.ts +21 -0
  24. package/dist/artifacts/types.d.ts.map +1 -0
  25. package/dist/artifacts/types.js +2 -0
  26. package/dist/artifacts/types.js.map +1 -0
  27. package/dist/artifacts.d.ts +2 -0
  28. package/dist/artifacts.d.ts.map +1 -0
  29. package/dist/artifacts.js +2 -0
  30. package/dist/artifacts.js.map +1 -0
  31. package/dist/cli.d.ts +3 -0
  32. package/dist/cli.d.ts.map +1 -0
  33. package/dist/cli.js +57 -0
  34. package/dist/cli.js.map +1 -0
  35. package/dist/config.d.ts +31 -0
  36. package/dist/config.d.ts.map +1 -0
  37. package/dist/config.js +174 -0
  38. package/dist/config.js.map +1 -0
  39. package/dist/index.d.ts +4 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +4 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/server/artifacts.d.ts +9 -0
  44. package/dist/server/artifacts.d.ts.map +1 -0
  45. package/dist/server/artifacts.js +65 -0
  46. package/dist/server/artifacts.js.map +1 -0
  47. package/dist/server/index.d.ts +7 -0
  48. package/dist/server/index.d.ts.map +1 -0
  49. package/dist/server/index.js +17 -0
  50. package/dist/server/index.js.map +1 -0
  51. package/dist/server/java.d.ts +2 -0
  52. package/dist/server/java.d.ts.map +1 -0
  53. package/dist/server/java.js +72 -0
  54. package/dist/server/java.js.map +1 -0
  55. package/dist/server/launch.d.ts +4 -0
  56. package/dist/server/launch.d.ts.map +1 -0
  57. package/dist/server/launch.js +35 -0
  58. package/dist/server/launch.js.map +1 -0
  59. package/dist/server/process.d.ts +4 -0
  60. package/dist/server/process.d.ts.map +1 -0
  61. package/dist/server/process.js +48 -0
  62. package/dist/server/process.js.map +1 -0
  63. package/dist/server/properties.d.ts +3 -0
  64. package/dist/server/properties.d.ts.map +1 -0
  65. package/dist/server/properties.js +45 -0
  66. package/dist/server/properties.js.map +1 -0
  67. package/dist/server/types.d.ts +18 -0
  68. package/dist/server/types.d.ts.map +1 -0
  69. package/dist/server/types.js +2 -0
  70. package/dist/server/types.js.map +1 -0
  71. package/package.json +59 -0
  72. package/vendor/grim.json +10 -0
  73. package/vendor/grimac-bukkit-2.3.73.jar +0 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Grim Mineflayer contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # grim-server
2
+
3
+ A self-contained Minecraft server launcher for Paper + Grim anticheat.
4
+
5
+ ## Features
6
+
7
+ - Downloads and caches Paper server jars and Grim anticheat jars automatically
8
+ - Resolves Java automatically from an explicit setting, `JAVA_HOME`, or the system `PATH`
9
+ - Creates and updates a local `grim-server.config.json` file for server settings
10
+ - Starts a server in a dedicated directory without removing worlds or config state
11
+ - Exposes a small library for programmatic server startup and artifact discovery
12
+
13
+ ## Installation
14
+
15
+ ```sh
16
+ npm install -g grim-server
17
+ ```
18
+
19
+ ## Quick start
20
+
21
+ ```sh
22
+ mkdir my-server && cd my-server
23
+ grim-server init
24
+ grim-server start
25
+ ```
26
+
27
+ This creates `grim-server.config.json` in the current directory and starts the configured server using the resolved Java runtime.
28
+
29
+ ## Commands
30
+
31
+ ```text
32
+ grim-server init
33
+ grim-server start [minecraft-version]
34
+ grim-server versions
35
+ grim-server verify [minecraft-version]
36
+ ```
37
+
38
+ ### `grim-server init`
39
+
40
+ Creates a default config file:
41
+
42
+ ```json
43
+ {
44
+ "version": "1.21.11",
45
+ "serverDir": ".grim-server",
46
+ "cacheDir": ".grim-cache",
47
+ "port": 25565,
48
+ "motd": "Grim Minecraft Server",
49
+ "onlineMode": false,
50
+ "allowFlight": true,
51
+ "memory": {
52
+ "min": "1G",
53
+ "max": "2G"
54
+ }
55
+ }
56
+ ```
57
+
58
+ ### `grim-server start [minecraft-version]`
59
+
60
+ Starts a Paper server with Grim enabled. If a version is provided, it overrides `config.version` for that run.
61
+
62
+ ### `grim-server versions`
63
+
64
+ Lists available Paper versions from the upstream API.
65
+
66
+ ### `grim-server verify [minecraft-version]`
67
+
68
+ Resolves the Paper and Grim artifacts for the selected version and prints their metadata.
69
+
70
+ ## Configuration
71
+
72
+ `grim-server.config.json` lives next to the project root or the working directory used when launching the CLI. You can also pass partial overrides programmatically when calling the library.
73
+
74
+ ### Supported fields
75
+
76
+ - `version`: Paper Minecraft version to use (for example `1.21.11`)
77
+ - `serverDir`: Directory that stores the server world and generated configs
78
+ - `cacheDir`: Directory used for downloaded jar artifacts
79
+ - `port`: Minecraft port, between `1` and `65535`
80
+ - `motd`: Server MOTD shown in the client
81
+ - `onlineMode`: Toggle Mojang authentication / online mode
82
+ - `allowFlight`: Allow flight in-game
83
+ - `memory.min`: Minimum Java heap size
84
+ - `memory.max`: Maximum Java heap size
85
+ - `serverProperties`: Any Minecraft `server.properties` key/value, including keys added by newer Minecraft or Paper versions
86
+ - `javaArgs`: Additional JVM arguments
87
+ - `environment`: Environment variables passed to the server process
88
+ - `captureOutput`: Capture child-process streams for programmatic logging
89
+ - `java`: Optional explicit Java executable or path override
90
+ - `paperJar`: Optional custom Paper jar path
91
+ - `grimJar`: Optional custom Grim jar path
92
+
93
+ ### Example
94
+
95
+ ```json
96
+ {
97
+ "version": "1.21.7",
98
+ "serverDir": "./worlds/dev",
99
+ "cacheDir": "./.cache",
100
+ "port": 25565,
101
+ "motd": "Local Grim dev server",
102
+ "onlineMode": false,
103
+ "allowFlight": true,
104
+ "serverProperties": {
105
+ "difficulty": "hard",
106
+ "gamemode": "survival",
107
+ "view-distance": 10,
108
+ "simulation-distance": 10,
109
+ "spawn-protection": 0,
110
+ "enable-command-block": true,
111
+ "white-list": false
112
+ },
113
+ "javaArgs": ["-XX:+UseG1GC"],
114
+ "environment": {
115
+ "LANG": "en_US.UTF-8"
116
+ },
117
+ "captureOutput": true,
118
+ "memory": {
119
+ "min": "512M",
120
+ "max": "1G"
121
+ }
122
+ }
123
+ ```
124
+
125
+ ## Java and runtime resolution
126
+
127
+ Java is resolved in this order:
128
+
129
+ 1. Explicit `java` config value
130
+ 2. Bundled runtime in `.runtime/current` or a matching extracted JDK directory
131
+ 3. `JAVA_HOME`
132
+ 4. System `PATH`
133
+ 5. Platform default Java command as a final fallback
134
+
135
+ Java 21 must be installed separately, or supplied through the `java` configuration field or `JAVA_HOME`. The optional `bundle:runtime` script can download a local development runtime, but it is not included in the npm package.
136
+
137
+ ## Artifact discovery
138
+
139
+ Paper builds are discovered from the official Paper API, and Grim releases are resolved from Modrinth with GitHub releases as a fallback. Downloaded jars are cached locally and verified with published checksums before use.
140
+
141
+ ## Library usage
142
+
143
+ ```ts
144
+ import { startServer } from 'grim-server';
145
+
146
+ const server = await startServer({
147
+ version: '1.21.11',
148
+ port: 25565,
149
+ motd: 'Local dev server',
150
+ onlineMode: false,
151
+ });
152
+
153
+ server.on('close', (code) => {
154
+ console.log(`server exited with code ${code}`);
155
+ });
156
+ ```
157
+
158
+ The package also exports helpers for configuration, artifact cache management, Java resolution, and server startup.
159
+
160
+ The returned server handle is the underlying `ChildProcess` with convenience methods:
161
+
162
+ ```ts
163
+ server.say('Server is ready');
164
+ server.command('weather clear');
165
+ server.stop();
166
+ server.killServer();
167
+ server.onLine((line) => console.log('[minecraft]', line));
168
+ server.onLog((line, stream) => console.log(`[${stream}]`, line));
169
+ server.on('exit', (code, signal) => console.log({ code, signal }));
170
+ server.on('error', (error) => console.error(error));
171
+ ```
172
+
173
+ Unknown or future Minecraft/Paper properties are passed through unchanged. Existing files in
174
+ `serverDir` are preserved, and only the explicitly managed properties plus values in
175
+ `serverProperties` are updated.
176
+
177
+ ## Development
178
+
179
+ ```sh
180
+ npm install
181
+ npm run check
182
+ ```
183
+
184
+ ## License
185
+
186
+ Paper and Grim remain subject to their own licenses. This project is distributed under the MIT license.
@@ -0,0 +1,6 @@
1
+ import type { Artifact, DiscoveryOptions } from './types.js';
2
+ export declare function cacheArtifact(artifact: Artifact, cacheDir: string, options?: DiscoveryOptions): Promise<Artifact & {
3
+ path: string;
4
+ }>;
5
+ export declare function hashFile(file: string, algorithm?: 'sha256' | 'sha1' | 'sha512'): Promise<string>;
6
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/artifacts/cache.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE7D,wBAAsB,aAAa,CACjC,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA0BtC;AAED,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,QAAQ,GAAG,MAAM,GAAG,QAAmB,GACjD,OAAO,CAAC,MAAM,CAAC,CAIjB"}
@@ -0,0 +1,73 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { createReadStream, createWriteStream } from 'node:fs';
3
+ import { access, mkdir, rename, rm, stat } from 'node:fs/promises';
4
+ import { Readable } from 'node:stream';
5
+ import { pipeline } from 'node:stream/promises';
6
+ import path from 'node:path';
7
+ import { request } from './http.js';
8
+ export async function cacheArtifact(artifact, cacheDir, options = {}) {
9
+ await mkdir(cacheDir, { recursive: true });
10
+ const target = path.join(cacheDir, safeName(artifact.name));
11
+ if (await matchesChecksum(target, artifact))
12
+ return { ...artifact, path: target };
13
+ await rm(target, { force: true });
14
+ const temporary = `${target}.${process.pid}.${randomUUID()}.part`;
15
+ try {
16
+ await downloadToFile(artifact, temporary, options);
17
+ if (artifact.sha256 &&
18
+ (await hashFile(temporary, 'sha256')) !== artifact.sha256.toLowerCase()) {
19
+ throw new Error(`SHA-256 verification failed for ${artifact.name}`);
20
+ }
21
+ if (artifact.checksum) {
22
+ const actual = await hashFile(temporary, artifact.checksum.algorithm);
23
+ if (actual !== artifact.checksum.value.toLowerCase()) {
24
+ throw new Error(`${artifact.checksum.algorithm} verification failed for ${artifact.name}`);
25
+ }
26
+ }
27
+ await rename(temporary, target);
28
+ return { ...artifact, path: target };
29
+ }
30
+ catch (error) {
31
+ await rm(temporary, { force: true });
32
+ throw error;
33
+ }
34
+ }
35
+ export async function hashFile(file, algorithm = 'sha256') {
36
+ const hash = createHash(algorithm);
37
+ for await (const chunk of createReadStream(file))
38
+ hash.update(chunk);
39
+ return hash.digest('hex').toLowerCase();
40
+ }
41
+ async function downloadToFile(artifact, file, options) {
42
+ const response = await request(artifact.url, { headers: { 'User-Agent': 'grim-server' } }, options);
43
+ if (!response.ok || !response.body) {
44
+ throw new Error(`Unable to download ${artifact.name}: HTTP ${response.status}`);
45
+ }
46
+ await pipeline(Readable.fromWeb(response.body), createWriteStream(file));
47
+ }
48
+ async function matchesChecksum(file, artifact) {
49
+ try {
50
+ const info = await stat(file);
51
+ if (info.size === 0)
52
+ return false;
53
+ if (artifact.sha256)
54
+ return (await hashFile(file)) === artifact.sha256.toLowerCase();
55
+ if (artifact.checksum) {
56
+ return ((await hashFile(file, artifact.checksum.algorithm)) ===
57
+ artifact.checksum.value.toLowerCase());
58
+ }
59
+ await access(file);
60
+ return true;
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
66
+ function safeName(name) {
67
+ const normalized = path.basename(name).replace(/[^a-zA-Z0-9._-]/g, '_');
68
+ if (!normalized || normalized === '.' || normalized === '..') {
69
+ throw new Error('Artifact name is invalid');
70
+ }
71
+ return normalized;
72
+ }
73
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/artifacts/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Artifact, DiscoveryOptions } from './types.js';
2
+ export declare function resolveGrim(minecraftVersion: string, options?: DiscoveryOptions): Promise<Artifact>;
3
+ //# sourceMappingURL=grim.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grim.d.ts","sourceRoot":"","sources":["../../src/artifacts/grim.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE7D,wBAAsB,WAAW,CAC/B,gBAAgB,EAAE,MAAM,EACxB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,QAAQ,CAAC,CAmEnB"}
@@ -0,0 +1,94 @@
1
+ import { cacheArtifact } from './cache.js';
2
+ import { requestJson } from './http.js';
3
+ export async function resolveGrim(minecraftVersion, options = {}) {
4
+ let modrinthError;
5
+ try {
6
+ const versions = await requestJson(`https://api.modrinth.com/v2/project/grimac/version?game_versions=${encodeURIComponent(JSON.stringify([minecraftVersion]))}`, options);
7
+ if (!Array.isArray(versions)) {
8
+ throw new Error('Modrinth discovery returned an invalid response');
9
+ }
10
+ const selected = versions
11
+ .filter((value) => isModrinthVersion(value, minecraftVersion))
12
+ .sort(compareModrinthVersions)[0];
13
+ const file = selected?.files.find((entry) => entry.primary && /\.jar$/i.test(entry.filename)) ??
14
+ selected?.files.find((entry) => /\.jar$/i.test(entry.filename));
15
+ if (selected && file?.url) {
16
+ const checksum = file.hashes.sha512
17
+ ? { algorithm: 'sha512', value: file.hashes.sha512 }
18
+ : file.hashes.sha1
19
+ ? { algorithm: 'sha1', value: file.hashes.sha1 }
20
+ : undefined;
21
+ const artifact = {
22
+ name: file.filename,
23
+ url: file.url,
24
+ version: selected.version_number,
25
+ source: 'modrinth',
26
+ ...(checksum ? { checksum } : {}),
27
+ };
28
+ return options.cacheDir ? cacheArtifact(artifact, options.cacheDir, options) : artifact;
29
+ }
30
+ }
31
+ catch (error) {
32
+ modrinthError = error;
33
+ }
34
+ try {
35
+ const releases = await requestJson('https://api.github.com/repos/GrimAnticheat/Grim/releases?per_page=30', { ...options, headers: { Accept: 'application/vnd.github+json' } });
36
+ if (!Array.isArray(releases)) {
37
+ throw new Error('GitHub release discovery returned an invalid response');
38
+ }
39
+ const release = releases.find((value) => isGithubRelease(value, minecraftVersion));
40
+ const asset = release && githubAsset(release);
41
+ if (!asset) {
42
+ throw new Error(`No Grim release asset is compatible with Minecraft ${minecraftVersion}`);
43
+ }
44
+ const artifact = {
45
+ name: asset.name,
46
+ url: asset.browser_download_url,
47
+ version: typeof release.tag_name === 'string' ? release.tag_name : minecraftVersion,
48
+ source: 'github',
49
+ ...(asset.digest?.startsWith('sha256:')
50
+ ? { sha256: asset.digest.slice('sha256:'.length).toLowerCase() }
51
+ : {}),
52
+ };
53
+ return options.cacheDir ? cacheArtifact(artifact, options.cacheDir, options) : artifact;
54
+ }
55
+ catch (fallbackError) {
56
+ const reason = modrinthError instanceof Error ? ` Modrinth: ${modrinthError.message}.` : '';
57
+ throw new Error(`Unable to discover Grim for Minecraft ${minecraftVersion}.${reason} GitHub: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`);
58
+ }
59
+ }
60
+ function isModrinthVersion(value, minecraftVersion) {
61
+ if (!value || typeof value !== 'object')
62
+ return false;
63
+ const version = value;
64
+ return (typeof version.version_number === 'string' &&
65
+ typeof version.version_type === 'string' &&
66
+ typeof version.date_published === 'string' &&
67
+ Array.isArray(version.game_versions) &&
68
+ version.game_versions.includes(minecraftVersion) &&
69
+ Array.isArray(version.loaders) &&
70
+ version.loaders.some((loader) => ['paper', 'bukkit', 'spigot'].includes(loader.toLowerCase())) &&
71
+ Array.isArray(version.files));
72
+ }
73
+ function compareModrinthVersions(a, b) {
74
+ const rank = (type) => (type === 'release' ? 0 : type === 'beta' ? 1 : 2);
75
+ return (rank(a.version_type) - rank(b.version_type) ||
76
+ Date.parse(b.date_published) - Date.parse(a.date_published));
77
+ }
78
+ function isGithubRelease(value, version) {
79
+ if (!value || typeof value !== 'object')
80
+ return false;
81
+ const release = value;
82
+ const text = `${release.tag_name ?? ''} ${release.name ?? ''} ${release.body ?? ''}`;
83
+ return (release.draft !== true &&
84
+ release.prerelease !== true &&
85
+ Array.isArray(release.assets) &&
86
+ text.includes(version));
87
+ }
88
+ function githubAsset(release) {
89
+ return release.assets.find((asset) => typeof asset.name === 'string' &&
90
+ /\.jar$/i.test(asset.name) &&
91
+ typeof asset.browser_download_url === 'string' &&
92
+ (asset.size === undefined || asset.size > 0));
93
+ }
94
+ //# sourceMappingURL=grim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grim.js","sourceRoot":"","sources":["../../src/artifacts/grim.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { DiscoveryOptions } from './types.js';
2
+ declare const defaultFetch: (input: string | URL, init?: RequestInit) => Promise<Response>;
3
+ export declare function requestJson(url: string, options?: DiscoveryOptions & {
4
+ headers?: HeadersInit;
5
+ }): Promise<unknown>;
6
+ export declare function request(input: string | URL, init: RequestInit, options?: DiscoveryOptions): Promise<Response>;
7
+ export { defaultFetch };
8
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/artifacts/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,QAAA,MAAM,YAAY,GAAI,OAAO,MAAM,GAAG,GAAG,EAAE,OAAO,WAAW,KAAG,OAAO,CAAC,QAAQ,CAC5D,CAAC;AAErB,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,gBAAgB,GAAG;IAAE,OAAO,CAAC,EAAE,WAAW,CAAA;CAAO,GACzD,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED,wBAAsB,OAAO,CAC3B,KAAK,EAAE,MAAM,GAAG,GAAG,EACnB,IAAI,EAAE,WAAW,EACjB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,QAAQ,CAAC,CASnB;AA4BD,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,51 @@
1
+ const defaultFetch = (input, init) => fetch(input, init);
2
+ export async function requestJson(url, options = {}) {
3
+ const response = await request(url, {
4
+ headers: { 'User-Agent': 'grim-server', ...options.headers },
5
+ }, options);
6
+ if (!response.ok)
7
+ throw new Error(`Discovery request failed: HTTP ${response.status}`);
8
+ return response.json();
9
+ }
10
+ export async function request(input, init, options = {}) {
11
+ const controller = new AbortController();
12
+ const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? 15_000);
13
+ const signal = combineSignals(options.signal, controller.signal);
14
+ try {
15
+ return await withRetries(() => (options.fetch ?? defaultFetch)(input, { ...init, signal }));
16
+ }
17
+ finally {
18
+ clearTimeout(timeout);
19
+ }
20
+ }
21
+ async function withRetries(requester) {
22
+ let lastError;
23
+ for (let attempt = 0; attempt < 3; attempt += 1) {
24
+ try {
25
+ const response = await requester();
26
+ if (response.ok || response.status < 500)
27
+ return response;
28
+ lastError = new Error(`HTTP ${response.status}`);
29
+ }
30
+ catch (error) {
31
+ lastError = error;
32
+ }
33
+ await new Promise((resolve) => setTimeout(resolve, 250 * 2 ** attempt));
34
+ }
35
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
36
+ }
37
+ function combineSignals(...signals) {
38
+ const available = signals.filter((signal) => signal !== undefined);
39
+ if (available.length === 1 && available[0])
40
+ return available[0];
41
+ const controller = new AbortController();
42
+ for (const signal of available) {
43
+ if (signal.aborted)
44
+ controller.abort(signal.reason);
45
+ else
46
+ signal.addEventListener('abort', () => controller.abort(signal.reason), { once: true });
47
+ }
48
+ return controller.signal;
49
+ }
50
+ export { defaultFetch };
51
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/artifacts/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { cacheArtifact, hashFile } from './cache.js';
2
+ export { listPaperVersions, resolvePaper } from './paper.js';
3
+ export { resolveGrim } from './grim.js';
4
+ export type { Artifact, Checksum, DiscoveryOptions, HttpClient } from './types.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { cacheArtifact, hashFile } from './cache.js';
2
+ export { listPaperVersions, resolvePaper } from './paper.js';
3
+ export { resolveGrim } from './grim.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Artifact, DiscoveryOptions } from './types.js';
2
+ export declare function listPaperVersions(options?: DiscoveryOptions): Promise<string[]>;
3
+ export declare function resolvePaper(version: string, options?: DiscoveryOptions): Promise<Artifact>;
4
+ //# sourceMappingURL=paper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paper.d.ts","sourceRoot":"","sources":["../../src/artifacts/paper.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE7D,wBAAsB,iBAAiB,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAYzF;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,QAAQ,CAAC,CA6BnB"}
@@ -0,0 +1,56 @@
1
+ import { cacheArtifact } from './cache.js';
2
+ import { requestJson } from './http.js';
3
+ export async function listPaperVersions(options = {}) {
4
+ const response = await requestJson('https://fill.papermc.io/v3/projects/paper', options);
5
+ if (!response || typeof response !== 'object') {
6
+ throw new Error('Paper version discovery returned an invalid response');
7
+ }
8
+ const versions = response.versions;
9
+ if (!versions || typeof versions !== 'object' || Array.isArray(versions)) {
10
+ throw new Error('Paper version discovery returned an invalid response');
11
+ }
12
+ return Object.values(versions).flatMap((value) => Array.isArray(value) ? value.filter((entry) => typeof entry === 'string') : []);
13
+ }
14
+ export async function resolvePaper(version, options = {}) {
15
+ if (version === 'latest') {
16
+ const available = await listPaperVersions(options);
17
+ const selected = available[0];
18
+ if (!selected)
19
+ throw new Error('Paper discovery returned no versions');
20
+ version = selected;
21
+ }
22
+ const response = await requestJson(`https://fill.papermc.io/v3/projects/paper/versions/${encodeURIComponent(version)}/builds`, options);
23
+ if (!Array.isArray(response))
24
+ throw new Error('Paper discovery returned an invalid response');
25
+ const builds = response.filter(isPaperBuild);
26
+ if (builds.length === 0) {
27
+ throw new Error(`No Paper builds are available for Minecraft ${version}`);
28
+ }
29
+ const stable = builds.filter((build) => build.channel.toUpperCase() === 'STABLE');
30
+ const selected = [...(stable.length > 0 ? stable : builds)].sort((a, b) => b.id - a.id)[0];
31
+ if (!selected)
32
+ throw new Error(`No usable Paper build is available for Minecraft ${version}`);
33
+ const download = selected.downloads['server:default'];
34
+ const artifact = {
35
+ name: download.name,
36
+ url: download.url,
37
+ version,
38
+ sha256: download.checksums.sha256.toLowerCase(),
39
+ source: 'paper',
40
+ build: selected.id,
41
+ };
42
+ return options.cacheDir ? cacheArtifact(artifact, options.cacheDir, options) : artifact;
43
+ }
44
+ function isPaperBuild(value) {
45
+ if (!value || typeof value !== 'object')
46
+ return false;
47
+ const build = value;
48
+ const download = build.downloads?.['server:default'];
49
+ return (Number.isInteger(build.id) &&
50
+ typeof build.channel === 'string' &&
51
+ !!download &&
52
+ typeof download.name === 'string' &&
53
+ typeof download.url === 'string' &&
54
+ typeof download.checksums?.sha256 === 'string');
55
+ }
56
+ //# sourceMappingURL=paper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paper.js","sourceRoot":"","sources":["../../src/artifacts/paper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export type Checksum = {
2
+ algorithm: 'sha256' | 'sha1' | 'sha512';
3
+ value: string;
4
+ };
5
+ export type Artifact = {
6
+ name: string;
7
+ url: string;
8
+ version: string;
9
+ sha256?: string;
10
+ checksum?: Checksum;
11
+ source: 'paper' | 'modrinth' | 'github';
12
+ build?: number;
13
+ };
14
+ export type HttpClient = (input: string | URL, init?: RequestInit) => Promise<Response>;
15
+ export type DiscoveryOptions = {
16
+ fetch?: HttpClient;
17
+ cacheDir?: string;
18
+ signal?: AbortSignal;
19
+ timeoutMs?: number;
20
+ };
21
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/artifacts/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG;IACrB,SAAS,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IACxC,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAExF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/artifacts/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export * from './artifacts/index.js';
2
+ //# sourceMappingURL=artifacts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../src/artifacts.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './artifacts/index.js';
2
+ //# sourceMappingURL=artifacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../src/artifacts.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}