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.
- package/LICENSE +21 -0
- package/README.md +186 -0
- package/dist/artifacts/cache.d.ts +6 -0
- package/dist/artifacts/cache.d.ts.map +1 -0
- package/dist/artifacts/cache.js +73 -0
- package/dist/artifacts/cache.js.map +1 -0
- package/dist/artifacts/grim.d.ts +3 -0
- package/dist/artifacts/grim.d.ts.map +1 -0
- package/dist/artifacts/grim.js +94 -0
- package/dist/artifacts/grim.js.map +1 -0
- package/dist/artifacts/http.d.ts +8 -0
- package/dist/artifacts/http.d.ts.map +1 -0
- package/dist/artifacts/http.js +51 -0
- package/dist/artifacts/http.js.map +1 -0
- package/dist/artifacts/index.d.ts +5 -0
- package/dist/artifacts/index.d.ts.map +1 -0
- package/dist/artifacts/index.js +4 -0
- package/dist/artifacts/index.js.map +1 -0
- package/dist/artifacts/paper.d.ts +4 -0
- package/dist/artifacts/paper.d.ts.map +1 -0
- package/dist/artifacts/paper.js +56 -0
- package/dist/artifacts/paper.js.map +1 -0
- package/dist/artifacts/types.d.ts +21 -0
- package/dist/artifacts/types.d.ts.map +1 -0
- package/dist/artifacts/types.js +2 -0
- package/dist/artifacts/types.js.map +1 -0
- package/dist/artifacts.d.ts +2 -0
- package/dist/artifacts.d.ts.map +1 -0
- package/dist/artifacts.js +2 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +57 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +31 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +174 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/server/artifacts.d.ts +9 -0
- package/dist/server/artifacts.d.ts.map +1 -0
- package/dist/server/artifacts.js +65 -0
- package/dist/server/artifacts.js.map +1 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +17 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/java.d.ts +2 -0
- package/dist/server/java.d.ts.map +1 -0
- package/dist/server/java.js +72 -0
- package/dist/server/java.js.map +1 -0
- package/dist/server/launch.d.ts +4 -0
- package/dist/server/launch.d.ts.map +1 -0
- package/dist/server/launch.js +35 -0
- package/dist/server/launch.js.map +1 -0
- package/dist/server/process.d.ts +4 -0
- package/dist/server/process.d.ts.map +1 -0
- package/dist/server/process.js +48 -0
- package/dist/server/process.js.map +1 -0
- package/dist/server/properties.d.ts +3 -0
- package/dist/server/properties.d.ts.map +1 -0
- package/dist/server/properties.js +45 -0
- package/dist/server/properties.js.map +1 -0
- package/dist/server/types.d.ts +18 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +2 -0
- package/dist/server/types.js.map +1 -0
- package/package.json +59 -0
- package/vendor/grim.json +10 -0
- 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":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAkB,EAClB,QAAgB,EAChB,UAA4B,EAAE;IAE9B,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,IAAI,MAAM,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC;QAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAClF,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,IAAI,UAAU,EAAE,OAAO,CAAC;IAClE,IAAI,CAAC;QACH,MAAM,cAAc,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QACnD,IACE,QAAQ,CAAC,MAAM;YACf,CAAC,MAAM,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,KAAK,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,EACvE,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,mCAAmC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YACtE,IAAI,MAAM,KAAK,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACrD,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,SAAS,4BAA4B,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7F,CAAC;QACH,CAAC;QACD,MAAM,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAChC,OAAO,EAAE,GAAG,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACvC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAAY,EACZ,YAA0C,QAAQ;IAElD,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACnC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,gBAAgB,CAAC,IAAI,CAAC;QAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrE,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;AAC1C,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,QAAkB,EAClB,IAAY,EACZ,OAAyB;IAEzB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAC5B,QAAQ,CAAC,GAAG,EACZ,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,aAAa,EAAE,EAAE,EAC5C,OAAO,CACR,CAAC;IACF,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,sBAAsB,QAAQ,CAAC,IAAI,UAAU,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,MAAM,QAAQ,CACZ,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,IAA2D,CAAC,EACtF,iBAAiB,CAAC,IAAI,CAAC,CACxB,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,IAAY,EAAE,QAAkB;IAC7D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAClC,IAAI,QAAQ,CAAC,MAAM;YAAE,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACrF,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACtB,OAAO,CACL,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;gBACnD,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,CACtC,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;IACxE,IAAI,CAAC,UAAU,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -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":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGxC,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,gBAAwB,EACxB,UAA4B,EAAE;IAE9B,IAAI,aAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAChC,oEAAoE,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,EAC5H,OAAO,CACR,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QACD,MAAM,QAAQ,GAAG,QAAQ;aACtB,MAAM,CAAC,CAAC,KAAK,EAA4B,EAAE,CAAC,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;aACvF,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,IAAI,GACR,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAChF,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QAClE,IAAI,QAAQ,IAAI,IAAI,EAAE,GAAG,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM;gBACjC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAiB,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;gBAC7D,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI;oBAChB,CAAC,CAAC,EAAE,SAAS,EAAE,MAAe,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;oBACzD,CAAC,CAAC,SAAS,CAAC;YAChB,MAAM,QAAQ,GAAa;gBACzB,IAAI,EAAE,IAAI,CAAC,QAAQ;gBACnB,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,OAAO,EAAE,QAAQ,CAAC,cAAc;gBAChC,MAAM,EAAE,UAAU;gBAClB,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAClC,CAAC;YACF,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC1F,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,aAAa,GAAG,KAAK,CAAC;IACxB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAChC,sEAAsE,EACtE,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,6BAA6B,EAAE,EAAE,CACnE,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAA0B,EAAE,CAC9D,eAAe,CAAC,KAAK,EAAE,gBAAgB,CAAC,CACzC,CAAC;QACF,MAAM,KAAK,GAAG,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,sDAAsD,gBAAgB,EAAE,CAAC,CAAC;QAC5F,CAAC;QACD,MAAM,QAAQ,GAAa;YACzB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,GAAG,EAAE,KAAK,CAAC,oBAAoB;YAC/B,OAAO,EAAE,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,gBAAgB;YACnF,MAAM,EAAE,QAAQ;YAChB,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC;gBACrC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE;gBAChE,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;QACF,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1F,CAAC;IAAC,OAAO,aAAa,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,aAAa,YAAY,KAAK,CAAC,CAAC,CAAC,cAAc,aAAa,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5F,MAAM,IAAI,KAAK,CACb,yCAAyC,gBAAgB,IAAI,MAAM,YACjE,aAAa,YAAY,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAC/E,EAAE,CACH,CAAC;IACJ,CAAC;AACH,CAAC;AAkCD,SAAS,iBAAiB,CAAC,KAAc,EAAE,gBAAwB;IACjE,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,OAAO,GAAG,KAAiC,CAAC;IAClD,OAAO,CACL,OAAO,OAAO,CAAC,cAAc,KAAK,QAAQ;QAC1C,OAAO,OAAO,CAAC,YAAY,KAAK,QAAQ;QACxC,OAAO,OAAO,CAAC,cAAc,KAAK,QAAQ;QAC1C,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QACpC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAChD,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;QAC9B,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAC9B,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAC7D;QACD,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAC7B,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,CAAkB,EAAE,CAAkB;IACrE,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,OAAO,CACL,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC;QAC3C,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,CAC5D,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,KAAc,EAAE,OAAe;IACtD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,OAAO,GAAG,KAA+B,CAAC;IAChD,MAAM,IAAI,GAAG,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,IAAI,OAAO,CAAC,IAAI,IAAI,EAAE,IAAI,OAAO,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;IACrF,OAAO,CACL,OAAO,CAAC,KAAK,KAAK,IAAI;QACtB,OAAO,CAAC,UAAU,KAAK,IAAI;QAC3B,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CACvB,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,OAAsB;IACzC,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CACxB,CAAC,KAAK,EAAE,EAAE,CACR,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QAC9B,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAC1B,OAAO,KAAK,CAAC,oBAAoB,KAAK,QAAQ;QAC9C,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAC/C,CAAC;AACJ,CAAC"}
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/artifacts/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../src/artifacts.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
|
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|