erlc-v2 1.0.1 → 1.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/README.md +606 -378
- package/index.d.ts +143 -2
- package/package.json +7 -4
- package/src/Client.js +74 -1
- package/src/api/LocalApiServer.js +538 -0
- package/src/events/Poller.js +14 -0
- package/src/events/diff.js +10 -1
- package/src/util/constants.js +11 -0
- package/src/util/errors.js +1 -1
- package/src/util/normalize.js +1 -0
- package/src/util/vehicleSearch.js +120 -0
- package/src/util/webhook.js +204 -0
package/index.d.ts
CHANGED
|
@@ -49,6 +49,17 @@ export interface PollingOptions {
|
|
|
49
49
|
bypassCache?: boolean;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
export interface ApiServerOptions {
|
|
53
|
+
enabled?: boolean;
|
|
54
|
+
host?: string;
|
|
55
|
+
port?: number;
|
|
56
|
+
path?: string;
|
|
57
|
+
webhookPath?: string;
|
|
58
|
+
publicUrl?: string;
|
|
59
|
+
token?: string;
|
|
60
|
+
logRequests?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
52
63
|
export interface ClientOptions {
|
|
53
64
|
serverKey: string;
|
|
54
65
|
globalKey?: string;
|
|
@@ -57,6 +68,7 @@ export interface ClientOptions {
|
|
|
57
68
|
cache?: CacheOptions;
|
|
58
69
|
rateLimit?: RateLimitOptions;
|
|
59
70
|
polling?: PollingOptions;
|
|
71
|
+
api?: ApiServerOptions;
|
|
60
72
|
}
|
|
61
73
|
|
|
62
74
|
export interface ServerFetchFlags {
|
|
@@ -67,6 +79,7 @@ export interface ServerFetchFlags {
|
|
|
67
79
|
killLogs?: boolean;
|
|
68
80
|
commandLogs?: boolean;
|
|
69
81
|
modCalls?: boolean;
|
|
82
|
+
emergencyCalls?: boolean;
|
|
70
83
|
vehicles?: boolean;
|
|
71
84
|
}
|
|
72
85
|
|
|
@@ -85,6 +98,8 @@ export interface CommandExecuteResult {
|
|
|
85
98
|
status: number;
|
|
86
99
|
endpoint: string;
|
|
87
100
|
bucket: string;
|
|
101
|
+
message: string | null;
|
|
102
|
+
commandId: string | null;
|
|
88
103
|
rateLimit: {
|
|
89
104
|
limit: number;
|
|
90
105
|
remaining: number;
|
|
@@ -92,6 +107,102 @@ export interface CommandExecuteResult {
|
|
|
92
107
|
};
|
|
93
108
|
}
|
|
94
109
|
|
|
110
|
+
export interface VehicleData {
|
|
111
|
+
Name?: string;
|
|
112
|
+
Owner?: string;
|
|
113
|
+
Plate?: string;
|
|
114
|
+
Texture?: string | null;
|
|
115
|
+
ColorHex?: string;
|
|
116
|
+
ColorName?: string;
|
|
117
|
+
[key: string]: any;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface EmergencyCallData {
|
|
121
|
+
Team?: string;
|
|
122
|
+
Caller?: number;
|
|
123
|
+
Players?: number[];
|
|
124
|
+
Position?: number[];
|
|
125
|
+
StartedAt?: number;
|
|
126
|
+
CallNumber?: number;
|
|
127
|
+
Description?: string;
|
|
128
|
+
PositionDescriptor?: string;
|
|
129
|
+
[key: string]: any;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface VehicleSearchFilters {
|
|
133
|
+
query?: string;
|
|
134
|
+
search?: string;
|
|
135
|
+
plate?: string;
|
|
136
|
+
owner?: string;
|
|
137
|
+
name?: string;
|
|
138
|
+
color?: string;
|
|
139
|
+
colorName?: string;
|
|
140
|
+
texture?: string;
|
|
141
|
+
exact?: boolean;
|
|
142
|
+
limit?: number;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface ApiServerInfo {
|
|
146
|
+
running: boolean;
|
|
147
|
+
host: string;
|
|
148
|
+
port: number | null;
|
|
149
|
+
path: string;
|
|
150
|
+
webhookPath: string;
|
|
151
|
+
localUrl: string | null;
|
|
152
|
+
webhookUrl: string | null;
|
|
153
|
+
publicUrl: string | null;
|
|
154
|
+
tokenEnabled: boolean;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface WebhookPayload {
|
|
158
|
+
type: "command" | "emergencyCall" | "verification" | "unknown";
|
|
159
|
+
body: Record<string, any>;
|
|
160
|
+
timestamp: string | null;
|
|
161
|
+
signature: string | null;
|
|
162
|
+
rawBody: Buffer | null;
|
|
163
|
+
headers: Record<string, any>;
|
|
164
|
+
server: string | null;
|
|
165
|
+
events: Array<{
|
|
166
|
+
event: string | null;
|
|
167
|
+
origin: string | null;
|
|
168
|
+
eventTimestamp: number | null;
|
|
169
|
+
data: Record<string, any>;
|
|
170
|
+
command: string | null;
|
|
171
|
+
argument: string;
|
|
172
|
+
args: string;
|
|
173
|
+
}>;
|
|
174
|
+
entry: {
|
|
175
|
+
event: string | null;
|
|
176
|
+
origin: string | null;
|
|
177
|
+
eventTimestamp: number | null;
|
|
178
|
+
data: Record<string, any>;
|
|
179
|
+
command: string | null;
|
|
180
|
+
argument: string;
|
|
181
|
+
args: string;
|
|
182
|
+
} | null;
|
|
183
|
+
event: string | null;
|
|
184
|
+
origin: string | null;
|
|
185
|
+
eventTimestamp: number | null;
|
|
186
|
+
data: Record<string, any> | null;
|
|
187
|
+
command: string | null;
|
|
188
|
+
argument: string;
|
|
189
|
+
args: string;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface ApiRequestPayload {
|
|
193
|
+
method: string;
|
|
194
|
+
path: string;
|
|
195
|
+
query: Record<string, string>;
|
|
196
|
+
kind: "route" | "webhook";
|
|
197
|
+
status: number;
|
|
198
|
+
type: string | null;
|
|
199
|
+
body: any;
|
|
200
|
+
note: string;
|
|
201
|
+
tookMs: number;
|
|
202
|
+
ip: string | string[] | null;
|
|
203
|
+
at: string;
|
|
204
|
+
}
|
|
205
|
+
|
|
95
206
|
export interface MapCoordinateBounds {
|
|
96
207
|
minX: number;
|
|
97
208
|
maxX: number;
|
|
@@ -173,7 +284,8 @@ export interface ServerResponse {
|
|
|
173
284
|
killLogs: any[];
|
|
174
285
|
commandLogs: any[];
|
|
175
286
|
modCalls: any[];
|
|
176
|
-
|
|
287
|
+
emergencyCalls: EmergencyCallData[];
|
|
288
|
+
vehicles: VehicleData[];
|
|
177
289
|
raw: Record<string, any>;
|
|
178
290
|
meta: {
|
|
179
291
|
status: number;
|
|
@@ -249,6 +361,9 @@ export class Client extends EventEmitter {
|
|
|
249
361
|
joins: (requestOptions?: RequestOptions) => Promise<any[]>;
|
|
250
362
|
commands: (requestOptions?: RequestOptions) => Promise<any[]>;
|
|
251
363
|
modCalls: (requestOptions?: RequestOptions) => Promise<any[]>;
|
|
364
|
+
emergencyCalls: (
|
|
365
|
+
requestOptions?: RequestOptions,
|
|
366
|
+
) => Promise<EmergencyCallData[]>;
|
|
252
367
|
};
|
|
253
368
|
commands: {
|
|
254
369
|
execute: (
|
|
@@ -257,11 +372,32 @@ export class Client extends EventEmitter {
|
|
|
257
372
|
) => Promise<CommandExecuteResult>;
|
|
258
373
|
};
|
|
259
374
|
vehicles: {
|
|
260
|
-
list: (requestOptions?: RequestOptions) => Promise<
|
|
375
|
+
list: (requestOptions?: RequestOptions) => Promise<VehicleData[]>;
|
|
376
|
+
search: (
|
|
377
|
+
filters?: string | VehicleSearchFilters,
|
|
378
|
+
requestOptions?: RequestOptions,
|
|
379
|
+
) => Promise<VehicleData[]>;
|
|
380
|
+
findByPlate: (
|
|
381
|
+
plate: string,
|
|
382
|
+
requestOptions?: RequestOptions,
|
|
383
|
+
) => Promise<VehicleData | null>;
|
|
384
|
+
findByOwner: (
|
|
385
|
+
owner: string,
|
|
386
|
+
requestOptions?: RequestOptions,
|
|
387
|
+
) => Promise<VehicleData[]>;
|
|
388
|
+
findOne: (
|
|
389
|
+
filters?: string | VehicleSearchFilters,
|
|
390
|
+
requestOptions?: RequestOptions,
|
|
391
|
+
) => Promise<VehicleData | null>;
|
|
261
392
|
};
|
|
262
393
|
queue: {
|
|
263
394
|
get: (requestOptions?: RequestOptions) => Promise<any[]>;
|
|
264
395
|
};
|
|
396
|
+
api: {
|
|
397
|
+
start: () => Promise<ApiServerInfo>;
|
|
398
|
+
stop: () => void;
|
|
399
|
+
info: () => ApiServerInfo;
|
|
400
|
+
};
|
|
265
401
|
onReady(listener: (...args: any[]) => void): this;
|
|
266
402
|
onJoin(listener: (...args: any[]) => void): this;
|
|
267
403
|
onLeave(listener: (...args: any[]) => void): this;
|
|
@@ -271,9 +407,14 @@ export class Client extends EventEmitter {
|
|
|
271
407
|
onQueueUpdate(listener: (...args: any[]) => void): this;
|
|
272
408
|
onStaffUpdate(listener: (...args: any[]) => void): this;
|
|
273
409
|
onModCall(listener: (...args: any[]) => void): this;
|
|
410
|
+
onEmergencyCall(listener: (...args: any[]) => void): this;
|
|
274
411
|
onCommandLog(listener: (...args: any[]) => void): this;
|
|
275
412
|
onLogCommand(listener: (...args: any[]) => void): this;
|
|
276
413
|
onServerUpdate(listener: (...args: any[]) => void): this;
|
|
414
|
+
onApiRequest(listener: (payload: ApiRequestPayload) => void): this;
|
|
415
|
+
onWebhook(listener: (payload: WebhookPayload) => void): this;
|
|
416
|
+
onWebhookCommand(listener: (payload: WebhookPayload) => void): this;
|
|
417
|
+
onWebhookEmergencyCall(listener: (payload: WebhookPayload) => void): this;
|
|
277
418
|
onError(listener: (...args: any[]) => void): this;
|
|
278
419
|
onDisconnect(listener: (...args: any[]) => void): this;
|
|
279
420
|
destroy(): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "erlc-v2",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Premium, lightweight JavaScript wrapper for the ER:LC API v2.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -23,9 +23,12 @@
|
|
|
23
23
|
"engines": {
|
|
24
24
|
"node": ">=18"
|
|
25
25
|
},
|
|
26
|
-
"scripts": {
|
|
27
|
-
"test:map": "node test-map-render.js"
|
|
28
|
-
|
|
26
|
+
"scripts": {
|
|
27
|
+
"test:map": "node test-map-render.js",
|
|
28
|
+
"dev:api": "node scripts/start-api.js",
|
|
29
|
+
"test:api": "node scripts/check-api.js",
|
|
30
|
+
"test:features": "node scripts/test-features.js"
|
|
31
|
+
},
|
|
29
32
|
"dependencies": {
|
|
30
33
|
"@napi-rs/canvas": "^0.1.74"
|
|
31
34
|
},
|
package/src/Client.js
CHANGED
|
@@ -2,11 +2,13 @@ const { EventEmitter } = require("events");
|
|
|
2
2
|
const Cache = require("./cache/Cache");
|
|
3
3
|
const RequestManager = require("./rest/RequestManager");
|
|
4
4
|
const Poller = require("./events/Poller");
|
|
5
|
+
const LocalApiServer = require("./api/LocalApiServer");
|
|
5
6
|
const { DEFAULT_OPTIONS, QUERY_FLAG_MAP } = require("./util/constants");
|
|
6
7
|
const { mergeOptions } = require("./util/options");
|
|
7
8
|
const { createLogger } = require("./util/logger");
|
|
8
9
|
const { normalizeServerResponse } = require("./util/normalize");
|
|
9
10
|
const { renderPlayerMap } = require("./map/renderPlayerMap");
|
|
11
|
+
const { searchVehicles, findVehicleByPlate } = require("./util/vehicleSearch");
|
|
10
12
|
const { ERLCError } = require("./errors");
|
|
11
13
|
|
|
12
14
|
const BASE_URL = "https://api.policeroleplay.community";
|
|
@@ -37,9 +39,14 @@ const EVENT_ALIASES = {
|
|
|
37
39
|
onQueueUpdate: "queueUpdate",
|
|
38
40
|
onStaffUpdate: "staffUpdate",
|
|
39
41
|
onModCall: "modCall",
|
|
42
|
+
onEmergencyCall: "emergencyCall",
|
|
40
43
|
onCommandLog: "commandLog",
|
|
41
44
|
onLogCommand: "logCommand",
|
|
42
45
|
onServerUpdate: "serverUpdate",
|
|
46
|
+
onApiRequest: "apiRequest",
|
|
47
|
+
onWebhook: "webhook",
|
|
48
|
+
onWebhookCommand: "webhookCommand",
|
|
49
|
+
onWebhookEmergencyCall: "webhookEmergencyCall",
|
|
43
50
|
onError: "error",
|
|
44
51
|
onDisconnect: "disconnect",
|
|
45
52
|
};
|
|
@@ -134,6 +141,10 @@ class Client extends EventEmitter {
|
|
|
134
141
|
this.server
|
|
135
142
|
.fetch({ modCalls: true }, requestOptions)
|
|
136
143
|
.then((d) => d.modCalls),
|
|
144
|
+
emergencyCalls: (requestOptions = {}) =>
|
|
145
|
+
this.server
|
|
146
|
+
.fetch({ emergencyCalls: true }, requestOptions)
|
|
147
|
+
.then((d) => d.emergencyCalls),
|
|
137
148
|
};
|
|
138
149
|
|
|
139
150
|
this.commands = {
|
|
@@ -146,6 +157,29 @@ class Client extends EventEmitter {
|
|
|
146
157
|
this.server
|
|
147
158
|
.fetch({ vehicles: true }, requestOptions)
|
|
148
159
|
.then((d) => d.vehicles),
|
|
160
|
+
search: (filters = {}, requestOptions = {}) =>
|
|
161
|
+
this.server
|
|
162
|
+
.fetch({ vehicles: true }, requestOptions)
|
|
163
|
+
.then((d) => searchVehicles(d.vehicles, filters)),
|
|
164
|
+
findByPlate: (plate, requestOptions = {}) =>
|
|
165
|
+
this.server
|
|
166
|
+
.fetch({ vehicles: true }, requestOptions)
|
|
167
|
+
.then((d) => findVehicleByPlate(d.vehicles, plate)),
|
|
168
|
+
findByOwner: (owner, requestOptions = {}) =>
|
|
169
|
+
this.server
|
|
170
|
+
.fetch({ vehicles: true }, requestOptions)
|
|
171
|
+
.then((d) => searchVehicles(d.vehicles, { owner })),
|
|
172
|
+
findOne: (filters = {}, requestOptions = {}) =>
|
|
173
|
+
this.server
|
|
174
|
+
.fetch({ vehicles: true }, requestOptions)
|
|
175
|
+
.then((d) =>
|
|
176
|
+
searchVehicles(
|
|
177
|
+
d.vehicles,
|
|
178
|
+
typeof filters === "string"
|
|
179
|
+
? { query: filters, limit: 1 }
|
|
180
|
+
: { ...filters, limit: 1 },
|
|
181
|
+
)[0] ?? null,
|
|
182
|
+
),
|
|
149
183
|
};
|
|
150
184
|
|
|
151
185
|
this.queue = {
|
|
@@ -153,10 +187,23 @@ class Client extends EventEmitter {
|
|
|
153
187
|
this.server.fetch({ queue: true }, requestOptions).then((d) => d.queue),
|
|
154
188
|
};
|
|
155
189
|
|
|
190
|
+
this.api = new LocalApiServer(this, this.options.api);
|
|
191
|
+
|
|
156
192
|
this.poller = new Poller(this, this.options.polling);
|
|
157
193
|
if (this.options.polling?.enabled !== false) {
|
|
158
194
|
this.poller.start();
|
|
159
195
|
}
|
|
196
|
+
if (this.options.api?.enabled || this.options.api?.port) {
|
|
197
|
+
this.api.start().catch((error) => {
|
|
198
|
+
this.logger.error({
|
|
199
|
+
msg: "local_api_start_failed",
|
|
200
|
+
error: error?.message || String(error),
|
|
201
|
+
});
|
|
202
|
+
if (this.listenerCount("error") > 0) {
|
|
203
|
+
this.emit("error", error);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
160
207
|
}
|
|
161
208
|
|
|
162
209
|
on(eventName, listener) {
|
|
@@ -227,6 +274,10 @@ class Client extends EventEmitter {
|
|
|
227
274
|
return this.on("commandLog", listener);
|
|
228
275
|
}
|
|
229
276
|
|
|
277
|
+
onEmergencyCall(listener) {
|
|
278
|
+
return this.on("emergencyCall", listener);
|
|
279
|
+
}
|
|
280
|
+
|
|
230
281
|
onLogCommand(listener) {
|
|
231
282
|
return this.on("logCommand", listener);
|
|
232
283
|
}
|
|
@@ -235,6 +286,22 @@ class Client extends EventEmitter {
|
|
|
235
286
|
return this.on("serverUpdate", listener);
|
|
236
287
|
}
|
|
237
288
|
|
|
289
|
+
onApiRequest(listener) {
|
|
290
|
+
return this.on("apiRequest", listener);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
onWebhook(listener) {
|
|
294
|
+
return this.on("webhook", listener);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
onWebhookCommand(listener) {
|
|
298
|
+
return this.on("webhookCommand", listener);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
onWebhookEmergencyCall(listener) {
|
|
302
|
+
return this.on("webhookEmergencyCall", listener);
|
|
303
|
+
}
|
|
304
|
+
|
|
238
305
|
onError(listener) {
|
|
239
306
|
return this.on("error", listener);
|
|
240
307
|
}
|
|
@@ -333,7 +400,7 @@ class Client extends EventEmitter {
|
|
|
333
400
|
|
|
334
401
|
const response = await this.requestManager.request({
|
|
335
402
|
method: "POST",
|
|
336
|
-
path: "/
|
|
403
|
+
path: "/v2/server/command",
|
|
337
404
|
body: { command: normalizedCommand },
|
|
338
405
|
useCache: false,
|
|
339
406
|
dedupe: requestOptions.dedupe === true,
|
|
@@ -345,6 +412,11 @@ class Client extends EventEmitter {
|
|
|
345
412
|
endpoint: response.endpoint,
|
|
346
413
|
bucket: response.bucket,
|
|
347
414
|
rateLimit: response.rateLimit,
|
|
415
|
+
message: response.data?.message ?? null,
|
|
416
|
+
commandId:
|
|
417
|
+
response.data?.commandId ??
|
|
418
|
+
response.data?.CommandId ??
|
|
419
|
+
null,
|
|
348
420
|
};
|
|
349
421
|
});
|
|
350
422
|
}
|
|
@@ -370,6 +442,7 @@ class Client extends EventEmitter {
|
|
|
370
442
|
if (this.state.destroyed) return;
|
|
371
443
|
this.state.destroyed = true;
|
|
372
444
|
this.poller.destroy();
|
|
445
|
+
this.api.stop();
|
|
373
446
|
this.requestManager.destroy(
|
|
374
447
|
this.state.disconnectError || new ERLCError("Client destroyed"),
|
|
375
448
|
);
|