@wumx-labs/noxaeapi-sdk 0.1.0 → 0.2.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/README.md +18 -1
- package/dist/index.cjs +149 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +113 -25
- package/dist/index.d.ts +113 -25
- package/dist/index.js +149 -40
- package/dist/index.js.map +1 -1
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -69,6 +69,23 @@ try {
|
|
|
69
69
|
}
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
## Request encoding
|
|
73
|
+
|
|
74
|
+
The server is a Javalin app, and most endpoints read their body with
|
|
75
|
+
`ctx.formParam(...)` — i.e. `application/x-www-form-urlencoded` — rather
|
|
76
|
+
than JSON. The SDK follows the same split:
|
|
77
|
+
|
|
78
|
+
- **Form-urlencoded**: everything in `economy`, `players`, `server`
|
|
79
|
+
(except `luckperms`/`noxauth`), `worlds`, `plugins`, and `placeholders`.
|
|
80
|
+
- **JSON**: `client.luckperms.*` and `client.noxauth.checkPassword` only —
|
|
81
|
+
these are read server-side with `ctx.bodyAsClass(...)`.
|
|
82
|
+
|
|
83
|
+
If you're adding a new SDK method, check which one the corresponding
|
|
84
|
+
Javalin handler uses before wiring it up, and pass `form: true` to
|
|
85
|
+
`http.request(...)` if it's form-urlencoded (this is also the more common
|
|
86
|
+
case). Getting this wrong won't throw a type error — the request just
|
|
87
|
+
silently sends the wrong content type and the server won't see the field.
|
|
88
|
+
|
|
72
89
|
## Optional modules
|
|
73
90
|
|
|
74
91
|
Some modules only work depending on the target server's setup:
|
|
@@ -97,4 +114,4 @@ new NoxAeApiClient({
|
|
|
97
114
|
|
|
98
115
|
## License
|
|
99
116
|
|
|
100
|
-
MIT
|
|
117
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -107,7 +107,7 @@ var HttpEngine = class {
|
|
|
107
107
|
this.fetchImpl = fetchImpl;
|
|
108
108
|
}
|
|
109
109
|
buildUrl(path, query) {
|
|
110
|
-
const url = new URL(`${this.baseUrl}/${path.replace(/^\/+/, "")}`);
|
|
110
|
+
const url = new URL(`${this.baseUrl}/v1/${path.replace(/^\/+/, "")}`);
|
|
111
111
|
if (query) {
|
|
112
112
|
for (const [key, value] of Object.entries(query)) {
|
|
113
113
|
if (value !== void 0 && value !== null) {
|
|
@@ -130,11 +130,20 @@ var HttpEngine = class {
|
|
|
130
130
|
...this.extraHeaders
|
|
131
131
|
};
|
|
132
132
|
if (this.apiKey) headers["key"] = this.apiKey;
|
|
133
|
-
|
|
133
|
+
let encodedBody;
|
|
134
|
+
if (opts.body !== void 0) {
|
|
135
|
+
if (opts.form) {
|
|
136
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
137
|
+
encodedBody = encodeFormBody(opts.body);
|
|
138
|
+
} else {
|
|
139
|
+
headers["Content-Type"] = "application/json";
|
|
140
|
+
encodedBody = JSON.stringify(opts.body);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
134
143
|
const response = await this.fetchImpl(url, {
|
|
135
144
|
method,
|
|
136
145
|
headers,
|
|
137
|
-
body:
|
|
146
|
+
body: encodedBody,
|
|
138
147
|
signal: controller.signal
|
|
139
148
|
});
|
|
140
149
|
clearTimeout(timeout);
|
|
@@ -194,6 +203,19 @@ var HttpEngine = class {
|
|
|
194
203
|
throw lastError instanceof Error ? lastError : new Error("Request failed after retries");
|
|
195
204
|
}
|
|
196
205
|
};
|
|
206
|
+
function encodeFormBody(body) {
|
|
207
|
+
const params = new URLSearchParams();
|
|
208
|
+
if (body && typeof body === "object") {
|
|
209
|
+
for (const [key, value] of Object.entries(body)) {
|
|
210
|
+
if (value === void 0 || value === null) continue;
|
|
211
|
+
params.set(
|
|
212
|
+
key,
|
|
213
|
+
typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value)
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return params.toString();
|
|
218
|
+
}
|
|
197
219
|
function safeJsonParse(text) {
|
|
198
220
|
if (!text) return void 0;
|
|
199
221
|
try {
|
|
@@ -238,13 +260,18 @@ var PlayersModule = class {
|
|
|
238
260
|
/** Kick an online player, optionally with a reason. */
|
|
239
261
|
kick(uuid, reason) {
|
|
240
262
|
return this.http.request("POST", `players/${encodeURIComponent(uuid)}/kick`, {
|
|
241
|
-
body: reason ? { reason } : void 0
|
|
263
|
+
body: reason ? { reason } : void 0,
|
|
264
|
+
form: true
|
|
242
265
|
});
|
|
243
266
|
}
|
|
244
|
-
/**
|
|
245
|
-
|
|
267
|
+
/**
|
|
268
|
+
* Ban a player, optionally with a reason and an ISO-8601 expiry
|
|
269
|
+
* (e.g. "2030-01-01T00:00:00Z"). Omit `expiry` for a permanent ban.
|
|
270
|
+
*/
|
|
271
|
+
ban(uuid, reason, expiry) {
|
|
246
272
|
return this.http.request("POST", `players/${encodeURIComponent(uuid)}/ban`, {
|
|
247
|
-
body: reason ? { reason } : void 0
|
|
273
|
+
body: reason || expiry ? { reason, expiry } : void 0,
|
|
274
|
+
form: true
|
|
248
275
|
});
|
|
249
276
|
}
|
|
250
277
|
/** Remove a player's ban. */
|
|
@@ -254,13 +281,15 @@ var PlayersModule = class {
|
|
|
254
281
|
/** Teleport a player to a location. */
|
|
255
282
|
teleport(uuid, location) {
|
|
256
283
|
return this.http.request("POST", `players/${encodeURIComponent(uuid)}/teleport`, {
|
|
257
|
-
body: location
|
|
284
|
+
body: location,
|
|
285
|
+
form: true
|
|
258
286
|
});
|
|
259
287
|
}
|
|
260
288
|
/** Change a player's gamemode. */
|
|
261
289
|
setGamemode(uuid, gamemode) {
|
|
262
290
|
return this.http.request("PUT", `players/${encodeURIComponent(uuid)}/gamemode`, {
|
|
263
|
-
body: { gamemode }
|
|
291
|
+
body: { gamemode },
|
|
292
|
+
form: true
|
|
264
293
|
});
|
|
265
294
|
}
|
|
266
295
|
/** Get kill/death/playtime/block stats for a player. */
|
|
@@ -291,11 +320,11 @@ var EconomyModule = class {
|
|
|
291
320
|
}
|
|
292
321
|
/** Pay an amount to a player (adds to their balance). */
|
|
293
322
|
pay(uuid, amount) {
|
|
294
|
-
return this.http.request("POST", "economy/pay", { body: { uuid, amount } });
|
|
323
|
+
return this.http.request("POST", "economy/pay", { body: { uuid, amount }, form: true });
|
|
295
324
|
}
|
|
296
325
|
/** Debit an amount from a player (subtracts from their balance). */
|
|
297
326
|
debit(uuid, amount) {
|
|
298
|
-
return this.http.request("POST", "economy/debit", { body: { uuid, amount } });
|
|
327
|
+
return this.http.request("POST", "economy/debit", { body: { uuid, amount }, form: true });
|
|
299
328
|
}
|
|
300
329
|
};
|
|
301
330
|
|
|
@@ -314,23 +343,40 @@ var ServerModule = class {
|
|
|
314
343
|
return this.http.request("GET", "server");
|
|
315
344
|
}
|
|
316
345
|
/**
|
|
317
|
-
* Run a console command on the server.
|
|
346
|
+
* Run a console command on the server, returning its console output.
|
|
318
347
|
* This is a privileged endpoint — requires a write-enabled API key.
|
|
348
|
+
*
|
|
349
|
+
* `waitMs` is how long to wait for output before returning (server
|
|
350
|
+
* default 500ms if omitted). The server returns the joined output as a
|
|
351
|
+
* plain JSON string, not `{ lines }`.
|
|
319
352
|
*/
|
|
320
|
-
exec(command) {
|
|
321
|
-
return this.http.request("POST", "server/exec", {
|
|
353
|
+
exec(command, waitMs) {
|
|
354
|
+
return this.http.request("POST", "server/exec", {
|
|
355
|
+
body: { command, time: waitMs },
|
|
356
|
+
form: true
|
|
357
|
+
});
|
|
322
358
|
}
|
|
323
359
|
/** List server operators. */
|
|
324
360
|
getOps() {
|
|
325
361
|
return this.http.request("GET", "server/ops");
|
|
326
362
|
}
|
|
327
|
-
/**
|
|
363
|
+
/**
|
|
364
|
+
* Grant operator status to a player.
|
|
365
|
+
*
|
|
366
|
+
* Server-side (`ServerApi.opPlayer`) reads `ctx.formParam("playerUuid")`,
|
|
367
|
+
* not "uuid" — the field name matters here.
|
|
368
|
+
*/
|
|
328
369
|
opPlayer(uuid) {
|
|
329
|
-
return this.http.request("POST", "server/ops", { body: { uuid } });
|
|
370
|
+
return this.http.request("POST", "server/ops", { body: { playerUuid: uuid }, form: true });
|
|
330
371
|
}
|
|
331
|
-
/**
|
|
372
|
+
/**
|
|
373
|
+
* Revoke operator status from a player.
|
|
374
|
+
*
|
|
375
|
+
* Server-side (`ServerApi.deopPlayer`) reads this from the query string
|
|
376
|
+
* (`ctx.queryParam("playerUuid")`), not the request body.
|
|
377
|
+
*/
|
|
332
378
|
deopPlayer(uuid) {
|
|
333
|
-
return this.http.request("DELETE", "server/ops", {
|
|
379
|
+
return this.http.request("DELETE", "server/ops", { query: { playerUuid: uuid } });
|
|
334
380
|
}
|
|
335
381
|
/** Get the current whitelist. */
|
|
336
382
|
getWhitelist() {
|
|
@@ -338,11 +384,16 @@ var ServerModule = class {
|
|
|
338
384
|
}
|
|
339
385
|
/** Add a player to the whitelist. */
|
|
340
386
|
addToWhitelist(uuid, name) {
|
|
341
|
-
return this.http.request("POST", "server/whitelist", { body: { uuid, name } });
|
|
387
|
+
return this.http.request("POST", "server/whitelist", { body: { uuid, name }, form: true });
|
|
342
388
|
}
|
|
343
|
-
/**
|
|
389
|
+
/**
|
|
390
|
+
* Remove a player from the whitelist.
|
|
391
|
+
*
|
|
392
|
+
* Server-side (`ServerApi.whitelistDelete`) reads `uuid`/`name` from the
|
|
393
|
+
* query string, not the request body.
|
|
394
|
+
*/
|
|
344
395
|
removeFromWhitelist(uuid) {
|
|
345
|
-
return this.http.request("DELETE", "server/whitelist", {
|
|
396
|
+
return this.http.request("DELETE", "server/whitelist", { query: { uuid } });
|
|
346
397
|
}
|
|
347
398
|
/**
|
|
348
399
|
* Restart the server.
|
|
@@ -365,7 +416,7 @@ var ServerModule = class {
|
|
|
365
416
|
}
|
|
366
417
|
/** Ban an IP address. */
|
|
367
418
|
banIp(ip, reason) {
|
|
368
|
-
return this.http.request("POST", "server/ban-ip", { body: { ip, reason } });
|
|
419
|
+
return this.http.request("POST", "server/ban-ip", { body: { ip, reason }, form: true });
|
|
369
420
|
}
|
|
370
421
|
/** Get a scoreboard objective's scores by objective name. */
|
|
371
422
|
getObjective(name) {
|
|
@@ -378,22 +429,33 @@ var ServerModule = class {
|
|
|
378
429
|
/** Set a score for an entry on an objective. */
|
|
379
430
|
setScore(objective, entry, value) {
|
|
380
431
|
return this.http.request("POST", `scoreboard/${encodeURIComponent(objective)}/score`, {
|
|
381
|
-
body: { entry, value }
|
|
432
|
+
body: { entry, value },
|
|
433
|
+
form: true
|
|
382
434
|
});
|
|
383
435
|
}
|
|
384
|
-
/**
|
|
436
|
+
/**
|
|
437
|
+
* Reset (remove) a score for an entry on an objective.
|
|
438
|
+
*
|
|
439
|
+
* Server-side (`ServerApi.resetScore`) reads `entry` from the query
|
|
440
|
+
* string, not the request body.
|
|
441
|
+
*/
|
|
385
442
|
resetScore(objective, entry) {
|
|
386
443
|
return this.http.request("DELETE", `scoreboard/${encodeURIComponent(objective)}/score`, {
|
|
387
|
-
|
|
444
|
+
query: { entry }
|
|
388
445
|
});
|
|
389
446
|
}
|
|
390
447
|
/** Broadcast a message to every player on the server. */
|
|
391
448
|
broadcast(message) {
|
|
392
|
-
return this.http.request("POST", "chat/broadcast", { body: { message } });
|
|
449
|
+
return this.http.request("POST", "chat/broadcast", { body: { message }, form: true });
|
|
393
450
|
}
|
|
394
|
-
/**
|
|
451
|
+
/**
|
|
452
|
+
* Send a private message to a specific player.
|
|
453
|
+
*
|
|
454
|
+
* Server-side (`ServerApi.tellPost`) reads `ctx.formParam("playerUuid")`,
|
|
455
|
+
* not "uuid".
|
|
456
|
+
*/
|
|
395
457
|
tell(uuid, message) {
|
|
396
|
-
return this.http.request("POST", "chat/tell", { body: { uuid, message } });
|
|
458
|
+
return this.http.request("POST", "chat/tell", { body: { playerUuid: uuid, message }, form: true });
|
|
397
459
|
}
|
|
398
460
|
};
|
|
399
461
|
|
|
@@ -427,16 +489,24 @@ var WorldsModule = class {
|
|
|
427
489
|
download(uuid) {
|
|
428
490
|
return this.http.request("GET", `worlds/${encodeURIComponent(uuid)}/download`);
|
|
429
491
|
}
|
|
430
|
-
/** Set the in-game time for a world. */
|
|
492
|
+
/** Set the in-game time for a world (0-24000). */
|
|
431
493
|
setTime(uuid, time) {
|
|
432
494
|
return this.http.request("POST", `worlds/${encodeURIComponent(uuid)}/time`, {
|
|
433
|
-
body: { time }
|
|
495
|
+
body: { time },
|
|
496
|
+
form: true
|
|
434
497
|
});
|
|
435
498
|
}
|
|
436
|
-
/**
|
|
499
|
+
/**
|
|
500
|
+
* Set the weather for a world.
|
|
501
|
+
*
|
|
502
|
+
* Server-side (`WorldApi.setWorldWeather`) reads a single
|
|
503
|
+
* `ctx.formParam("weather")` enum string — "clear" | "rain" | "thunder" —
|
|
504
|
+
* not separate storm/thundering booleans.
|
|
505
|
+
*/
|
|
437
506
|
setWeather(uuid, weather) {
|
|
438
507
|
return this.http.request("POST", `worlds/${encodeURIComponent(uuid)}/weather`, {
|
|
439
|
-
body: weather
|
|
508
|
+
body: { weather },
|
|
509
|
+
form: true
|
|
440
510
|
});
|
|
441
511
|
}
|
|
442
512
|
/** Get entity counts within a specific world. */
|
|
@@ -456,11 +526,15 @@ var PluginsModule = class {
|
|
|
456
526
|
return this.http.request("GET", "plugins");
|
|
457
527
|
}
|
|
458
528
|
/**
|
|
459
|
-
* Install a plugin from a URL
|
|
529
|
+
* Install a plugin by downloading it from a direct URL.
|
|
460
530
|
* This is a privileged endpoint — requires a write-enabled API key.
|
|
531
|
+
*
|
|
532
|
+
* Server-side (`PluginApi.installPlugin`) reads
|
|
533
|
+
* `ctx.formParam("downloadUrl")`, not "source", and the request must be
|
|
534
|
+
* form-urlencoded.
|
|
461
535
|
*/
|
|
462
|
-
install(
|
|
463
|
-
return this.http.request("POST", "plugins", { body: {
|
|
536
|
+
install(downloadUrl) {
|
|
537
|
+
return this.http.request("POST", "plugins", { body: { downloadUrl }, form: true });
|
|
464
538
|
}
|
|
465
539
|
/** Enable a plugin by name. */
|
|
466
540
|
enable(name) {
|
|
@@ -489,12 +563,18 @@ var PlaceholdersModule = class {
|
|
|
489
563
|
}
|
|
490
564
|
http;
|
|
491
565
|
/**
|
|
492
|
-
* Replace PlaceholderAPI-style placeholders (e.g. "%player_name%")
|
|
493
|
-
* player, returning the resolved string.
|
|
566
|
+
* Replace PlaceholderAPI-style placeholders (e.g. "%player_name%") in
|
|
567
|
+
* `message` for a player, returning the resolved string.
|
|
568
|
+
*
|
|
569
|
+
* Server-side this is `PAPIApi.replacePlaceholders`, which reads
|
|
570
|
+
* `ctx.formParam("message")` and `ctx.formParam("uuid")` — the field is
|
|
571
|
+
* literally named "message", not "text", and the whole body must be
|
|
572
|
+
* form-urlencoded.
|
|
494
573
|
*/
|
|
495
|
-
replace(uuid,
|
|
574
|
+
replace(uuid, message) {
|
|
496
575
|
return this.http.request("POST", "placeholders/replace", {
|
|
497
|
-
body: { uuid,
|
|
576
|
+
body: { uuid, message },
|
|
577
|
+
form: true
|
|
498
578
|
});
|
|
499
579
|
}
|
|
500
580
|
};
|
|
@@ -585,9 +665,35 @@ var NoxAuthModule = class {
|
|
|
585
665
|
}
|
|
586
666
|
};
|
|
587
667
|
|
|
668
|
+
// src/modules/skills.ts
|
|
669
|
+
var SkillsModule = class {
|
|
670
|
+
constructor(http) {
|
|
671
|
+
this.http = http;
|
|
672
|
+
}
|
|
673
|
+
http;
|
|
674
|
+
/**
|
|
675
|
+
* Get mcMMO skill levels and power level for a player.
|
|
676
|
+
* Only works for **online** players — mcMMO's public ExperienceAPI has
|
|
677
|
+
* no offline lookup, so this throws `NoxAeApiNotFoundError` if the
|
|
678
|
+
* player isn't currently connected, and `NoxAeApiServerError` (503)
|
|
679
|
+
* if mcMMO isn't loaded on the target server.
|
|
680
|
+
*/
|
|
681
|
+
getMcmmoSkills(uuid) {
|
|
682
|
+
return this.http.request("GET", `skills/mcmmo/player/${encodeURIComponent(uuid)}`);
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Get AuraSkills skill levels and power level for a player.
|
|
686
|
+
* Works for offline players. Throws `NoxAeApiServerError` (503) if
|
|
687
|
+
* AuraSkills isn't loaded on the target server.
|
|
688
|
+
*/
|
|
689
|
+
getAuraSkills(uuid) {
|
|
690
|
+
return this.http.request("GET", `skills/auraskills/player/${encodeURIComponent(uuid)}`);
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
|
|
588
694
|
// src/socket.ts
|
|
589
695
|
function toWsUrl(baseUrl, route, apiKey) {
|
|
590
|
-
const url = new URL(`${baseUrl.replace(/\/+$/, "")}/${route.replace(/^\/+/, "")}`);
|
|
696
|
+
const url = new URL(`${baseUrl.replace(/\/+$/, "")}/v1/ws/${route.replace(/^\/+/, "")}`);
|
|
591
697
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
592
698
|
if (apiKey) url.searchParams.set("key", apiKey);
|
|
593
699
|
return url.toString();
|
|
@@ -690,6 +796,8 @@ var NoxAeApiClient = class _NoxAeApiClient {
|
|
|
690
796
|
luckperms;
|
|
691
797
|
/** Only works if `noxauth.enabled: true` is set in the server config. */
|
|
692
798
|
noxauth;
|
|
799
|
+
/** Requires mcMMO and/or AuraSkills to be loaded on the target server. */
|
|
800
|
+
skills;
|
|
693
801
|
http;
|
|
694
802
|
baseUrl;
|
|
695
803
|
apiKey;
|
|
@@ -706,6 +814,7 @@ var NoxAeApiClient = class _NoxAeApiClient {
|
|
|
706
814
|
this.placeholders = new PlaceholdersModule(this.http);
|
|
707
815
|
this.luckperms = new LuckPermsModule(this.http);
|
|
708
816
|
this.noxauth = new NoxAuthModule(this.http);
|
|
817
|
+
this.skills = new SkillsModule(this.http);
|
|
709
818
|
}
|
|
710
819
|
/**
|
|
711
820
|
* Build a client from environment variables:
|