@sonoransoftware/sonoran.js 1.0.33 → 1.0.35
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/.github/workflows/auto-pr-on-branch-push.yml +89 -0
- package/.github/workflows/codex_instructions.md +24 -0
- package/.github/workflows/push-pr-nudge-codex.yml +50 -0
- package/dist/constants.d.ts +205 -1
- package/dist/constants.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/instance/Instance.d.ts +6 -0
- package/dist/instance/Instance.js +27 -0
- package/dist/instance/instance.types.d.ts +3 -0
- package/dist/libs/rest/src/lib/REST.d.ts +2 -1
- package/dist/libs/rest/src/lib/REST.js +113 -0
- package/dist/libs/rest/src/lib/RequestManager.d.ts +2 -0
- package/dist/libs/rest/src/lib/RequestManager.js +201 -0
- package/dist/libs/rest/src/lib/errors/RateLimitError.js +19 -1
- package/dist/libs/rest/src/lib/utils/constants.d.ts +105 -22
- package/dist/libs/rest/src/lib/utils/constants.js +112 -2
- package/dist/managers/CADManager.d.ts +28 -0
- package/dist/managers/CADManager.js +90 -0
- package/dist/managers/CMSManager.d.ts +60 -0
- package/dist/managers/CMSManager.js +156 -0
- package/dist/managers/CMSServerManager.d.ts +3 -0
- package/dist/managers/CMSServerManager.js +36 -2
- package/dist/managers/RadioManager.d.ts +55 -0
- package/dist/managers/RadioManager.js +224 -0
- package/package.json +1 -1
- package/readme.md +170 -0
- package/src/constants.ts +239 -2
- package/src/index.ts +35 -1
- package/src/instance/Instance.ts +30 -1
- package/src/instance/instance.types.ts +4 -1
- package/src/libs/rest/src/lib/REST.ts +112 -1
- package/src/libs/rest/src/lib/RequestManager.ts +221 -10
- package/src/libs/rest/src/lib/errors/RateLimitError.ts +20 -2
- package/src/libs/rest/src/lib/utils/constants.ts +215 -25
- package/src/managers/CADManager.ts +86 -1
- package/src/managers/CMSManager.ts +142 -1
- package/src/managers/CMSServerManager.ts +39 -6
- package/src/managers/RadioManager.ts +187 -0
package/src/index.ts
CHANGED
|
@@ -1,4 +1,38 @@
|
|
|
1
1
|
export * from './instance/Instance';
|
|
2
2
|
export * from './builders';
|
|
3
3
|
export * from './libs/rest/src';
|
|
4
|
-
export {
|
|
4
|
+
export {
|
|
5
|
+
productEnums,
|
|
6
|
+
CADNewDispatchBuilderOptions,
|
|
7
|
+
CADSubscriptionVersionEnum,
|
|
8
|
+
CMSSubscriptionVersionEnum,
|
|
9
|
+
RadioSubscriptionLevel,
|
|
10
|
+
RadioSetUserChannelsOptions,
|
|
11
|
+
RadioChannel,
|
|
12
|
+
RadioChannelGroup,
|
|
13
|
+
RadioConnectedUser,
|
|
14
|
+
RadioSpeakerLocation,
|
|
15
|
+
RadioGetCommunityChannelsPromiseResult,
|
|
16
|
+
RadioGetConnectedUsersPromiseResult,
|
|
17
|
+
RadioGetConnectedUserPromiseResult,
|
|
18
|
+
RadioSetUserChannelsPromiseResult,
|
|
19
|
+
RadioSetUserDisplayNamePromiseResult,
|
|
20
|
+
RadioGetServerSubscriptionFromIpPromiseResult,
|
|
21
|
+
RadioSetServerIpPromiseResult,
|
|
22
|
+
RadioSetInGameSpeakerLocationsPromiseResult,
|
|
23
|
+
CADSetClockTimePromiseResult,
|
|
24
|
+
CADJoinCommunityPromiseResult,
|
|
25
|
+
CADLeaveCommunityPromiseResult,
|
|
26
|
+
CMSProfileField,
|
|
27
|
+
CMSGetCurrentClockInPromiseResult,
|
|
28
|
+
CMSAccountsPage,
|
|
29
|
+
CMSAccountSummary,
|
|
30
|
+
CMSGetAccountsPromiseResult,
|
|
31
|
+
CMSGetProfileFieldsPromiseResult,
|
|
32
|
+
CMSProfileFieldUpdate,
|
|
33
|
+
CMSEditAccountProfileFieldsPromiseResult,
|
|
34
|
+
CMSRsvpPromiseResult,
|
|
35
|
+
CMSSetGameServerStruct,
|
|
36
|
+
CMSSetGameServersPromiseResult,
|
|
37
|
+
CMSGetFormSubmissionsPromiseResult
|
|
38
|
+
} from './constants';
|
package/src/instance/Instance.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as globalTypes from '../constants';
|
|
|
4
4
|
import * as InstanceTypes from './instance.types';
|
|
5
5
|
import { CADManager } from '../managers/CADManager';
|
|
6
6
|
import { CMSManager } from '../managers/CMSManager';
|
|
7
|
+
import { RadioManager } from '../managers/RadioManager';
|
|
7
8
|
import { debugLog } from '../utils';
|
|
8
9
|
|
|
9
10
|
export class Instance extends EventEmitter {
|
|
@@ -17,9 +18,14 @@ export class Instance extends EventEmitter {
|
|
|
17
18
|
public cmsApiUrl: string = 'https://api.sonorancms.com';
|
|
18
19
|
public cmsDefaultServerId: number = 1;
|
|
19
20
|
public isCMSSuccessful: boolean = false;
|
|
21
|
+
public radioCommunityId: string | undefined;
|
|
22
|
+
public radioApiKey: string | undefined;
|
|
23
|
+
public radioApiUrl: string = 'https://api.sonoranradio.com';
|
|
24
|
+
public isRadioSuccessful: boolean = false;
|
|
20
25
|
|
|
21
26
|
public cad: CADManager | undefined;
|
|
22
27
|
public cms: CMSManager | undefined;
|
|
28
|
+
public radio: RadioManager | undefined;
|
|
23
29
|
|
|
24
30
|
public debug: boolean = false;
|
|
25
31
|
public apiHeaders: HeadersInit = {};
|
|
@@ -64,6 +70,17 @@ export class Instance extends EventEmitter {
|
|
|
64
70
|
this.initialize();
|
|
65
71
|
break;
|
|
66
72
|
}
|
|
73
|
+
case globalTypes.productEnums.RADIO: {
|
|
74
|
+
this.radioCommunityId = options.communityId;
|
|
75
|
+
this.radioApiKey = options.apiKey;
|
|
76
|
+
if (Object.prototype.hasOwnProperty.call(options, 'radioApiUrl') && typeof options.radioApiUrl === 'string') {
|
|
77
|
+
this._debugLog(`Overriding Radio API URL... ${options.radioApiUrl}`);
|
|
78
|
+
this.radioApiUrl = options.radioApiUrl;
|
|
79
|
+
}
|
|
80
|
+
this._debugLog('About to initialize instance.');
|
|
81
|
+
this.initialize();
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
67
84
|
default: {
|
|
68
85
|
throw new Error('Invalid product enum given for constructor.');
|
|
69
86
|
}
|
|
@@ -76,6 +93,8 @@ export class Instance extends EventEmitter {
|
|
|
76
93
|
this.cadApiKey = options.cadApiKey;
|
|
77
94
|
this.cmsCommunityId = options.cmsCommunityId;
|
|
78
95
|
this.cmsApiKey = options.cmsApiKey;
|
|
96
|
+
this.radioCommunityId = options.radioCommunityId;
|
|
97
|
+
this.radioApiKey = options.radioApiKey;
|
|
79
98
|
|
|
80
99
|
if (options.cadDefaultServerId !== undefined) {
|
|
81
100
|
this._debugLog(`Overriding default CAD server id... ${options.serverId}`);
|
|
@@ -93,6 +112,10 @@ export class Instance extends EventEmitter {
|
|
|
93
112
|
this._debugLog(`Overriding CMS API URL... ${options.cmsApiUrl}`);
|
|
94
113
|
this.cmsApiUrl = options.cmsApiUrl;
|
|
95
114
|
}
|
|
115
|
+
if (Object.prototype.hasOwnProperty.call(options, 'radioApiUrl') && typeof options.radioApiUrl === 'string') {
|
|
116
|
+
this._debugLog(`Overriding Radio API URL... ${options.radioApiUrl}`);
|
|
117
|
+
this.radioApiUrl = options.radioApiUrl;
|
|
118
|
+
}
|
|
96
119
|
this.initialize();
|
|
97
120
|
}
|
|
98
121
|
}
|
|
@@ -112,6 +135,12 @@ export class Instance extends EventEmitter {
|
|
|
112
135
|
} else {
|
|
113
136
|
this._debugLog('Not initializing CMS Manager due to a missing community id, api key, or api url.');
|
|
114
137
|
}
|
|
138
|
+
if (this.radioCommunityId && this.radioApiKey && this.radioApiUrl) {
|
|
139
|
+
this._debugLog('About to initialize Radio Manager');
|
|
140
|
+
this.radio = new RadioManager(this);
|
|
141
|
+
} else {
|
|
142
|
+
this._debugLog('Not initializing Radio Manager due to a missing community id, api key, or api url.');
|
|
143
|
+
}
|
|
115
144
|
}
|
|
116
145
|
|
|
117
146
|
public _debugLog(message: string): void {
|
|
@@ -119,4 +148,4 @@ export class Instance extends EventEmitter {
|
|
|
119
148
|
debugLog(message);
|
|
120
149
|
}
|
|
121
150
|
}
|
|
122
|
-
}
|
|
151
|
+
}
|
|
@@ -14,6 +14,7 @@ import type { RequestInit, Response } from 'node-fetch';
|
|
|
14
14
|
import { Instance } from '../../../../instance/Instance';
|
|
15
15
|
import { CADManager } from '../../../../managers/CADManager';
|
|
16
16
|
import { CMSManager } from '../../../../managers/CMSManager';
|
|
17
|
+
import { RadioManager } from '../../../../managers/RadioManager';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Options to be passed when creating the REST instance
|
|
@@ -106,7 +107,7 @@ export interface REST {
|
|
|
106
107
|
(<S extends string | symbol>(event?: Exclude<S, keyof RestEvents>) => this);
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
export type RestManagerTypes = CADManager | CMSManager;
|
|
110
|
+
export type RestManagerTypes = CADManager | CMSManager | RadioManager;
|
|
110
111
|
|
|
111
112
|
export class REST extends EventEmitter {
|
|
112
113
|
public readonly requestManager: RequestManager;
|
|
@@ -150,6 +151,11 @@ export class REST extends EventEmitter {
|
|
|
150
151
|
apiKey = this.instance.cmsApiKey;
|
|
151
152
|
break;
|
|
152
153
|
}
|
|
154
|
+
case productEnums.RADIO: {
|
|
155
|
+
communityId = this.instance.radioCommunityId;
|
|
156
|
+
apiKey = this.instance.radioApiKey;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
153
159
|
}
|
|
154
160
|
if (!communityId || !apiKey) throw new Error(`Community ID or API Key could not be found for request. P${apiType.product}`);
|
|
155
161
|
// if (apiType.minVersion > this.manager.version) throw new Error(`[${type}] Subscription version too low for this API type request. Current Version: ${convertSubNumToName(this.manager.version)} Needed Version: ${convertSubNumToName(apiType.minVersion)}`); // Verifies API Subscription Level Requirement which is deprecated currently
|
|
@@ -179,6 +185,9 @@ export class REST extends EventEmitter {
|
|
|
179
185
|
serverId: args[0]
|
|
180
186
|
}
|
|
181
187
|
}
|
|
188
|
+
case 'SET_GAME_SERVERS': {
|
|
189
|
+
return args[0] ?? [];
|
|
190
|
+
}
|
|
182
191
|
case 'RSVP': {
|
|
183
192
|
return {
|
|
184
193
|
eventId: args[0],
|
|
@@ -206,6 +215,62 @@ export class REST extends EventEmitter {
|
|
|
206
215
|
uniqueId: args[4]
|
|
207
216
|
};
|
|
208
217
|
}
|
|
218
|
+
case 'GET_CURRENT_CLOCK_IN': {
|
|
219
|
+
return {
|
|
220
|
+
apiId: args[0],
|
|
221
|
+
username: args[1],
|
|
222
|
+
accId: args[2],
|
|
223
|
+
discord: args[3],
|
|
224
|
+
uniqueId: args[4]
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
case 'GET_ACCOUNTS': {
|
|
228
|
+
return args[0] ?? {};
|
|
229
|
+
}
|
|
230
|
+
case 'GET_PROFILE_FIELDS': {
|
|
231
|
+
return {};
|
|
232
|
+
}
|
|
233
|
+
case 'SET_CLOCK': {
|
|
234
|
+
if (args[0] && typeof args[0] === 'object' && !Array.isArray(args[0])) {
|
|
235
|
+
return args[0];
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
serverId: args[0],
|
|
239
|
+
currentUtc: args[1],
|
|
240
|
+
currentGame: args[2],
|
|
241
|
+
secondsPerHour: args[3]
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
case 'JOIN_COMMUNITY':
|
|
245
|
+
case 'LEAVE_COMMUNITY': {
|
|
246
|
+
const payload = args[0] && typeof args[0] === 'object' && !Array.isArray(args[0]) && 'internalKey' in args[0]
|
|
247
|
+
? args[0]
|
|
248
|
+
: null;
|
|
249
|
+
const internalKey = payload ? payload.internalKey : args[0];
|
|
250
|
+
const accountsInput = payload ? payload.accounts : args[1];
|
|
251
|
+
let accounts: Array<{ account: string }> = [];
|
|
252
|
+
if (Array.isArray(accountsInput)) {
|
|
253
|
+
accounts = accountsInput.map((entry) => {
|
|
254
|
+
if (typeof entry === 'string') {
|
|
255
|
+
return { account: entry };
|
|
256
|
+
}
|
|
257
|
+
if (entry && typeof entry === 'object' && 'account' in entry) {
|
|
258
|
+
return entry as { account: string };
|
|
259
|
+
}
|
|
260
|
+
return { account: String(entry) };
|
|
261
|
+
});
|
|
262
|
+
} else if (accountsInput) {
|
|
263
|
+
if (typeof accountsInput === 'string') {
|
|
264
|
+
accounts = [{ account: accountsInput }];
|
|
265
|
+
} else if (typeof accountsInput === 'object' && 'account' in accountsInput) {
|
|
266
|
+
accounts = [accountsInput as { account: string }];
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
internalKey,
|
|
271
|
+
accounts
|
|
272
|
+
};
|
|
273
|
+
}
|
|
209
274
|
case 'CLOCK_IN_OUT': {
|
|
210
275
|
return {
|
|
211
276
|
apiId: args[0],
|
|
@@ -237,6 +302,13 @@ export class REST extends EventEmitter {
|
|
|
237
302
|
secret: args[0],
|
|
238
303
|
};
|
|
239
304
|
}
|
|
305
|
+
case 'GET_FORM_TEMPLATE_SUBMISSIONS': {
|
|
306
|
+
return {
|
|
307
|
+
templateId: args[0],
|
|
308
|
+
skip: args[1],
|
|
309
|
+
take: args[2],
|
|
310
|
+
};
|
|
311
|
+
}
|
|
240
312
|
case 'CHANGE_FORM_STAGE': {
|
|
241
313
|
return {
|
|
242
314
|
accId: args[0],
|
|
@@ -306,6 +378,11 @@ export class REST extends EventEmitter {
|
|
|
306
378
|
robloxJoinCode: args[0]
|
|
307
379
|
}
|
|
308
380
|
}
|
|
381
|
+
case 'ERLC_GET_PLAYER_QUEUE': {
|
|
382
|
+
return {
|
|
383
|
+
robloxJoinCode: args[0]
|
|
384
|
+
}
|
|
385
|
+
}
|
|
309
386
|
case 'ERLC_ADD_NEW_RECORD': {
|
|
310
387
|
return {
|
|
311
388
|
robloxJoinCode: args[0],
|
|
@@ -317,6 +394,40 @@ export class REST extends EventEmitter {
|
|
|
317
394
|
points: args[6],
|
|
318
395
|
}
|
|
319
396
|
}
|
|
397
|
+
case 'RADIO_GET_COMMUNITY_CHANNELS':
|
|
398
|
+
case 'RADIO_GET_CONNECTED_USERS':
|
|
399
|
+
case 'RADIO_GET_SERVER_SUBSCRIPTION_FROM_IP': {
|
|
400
|
+
return undefined;
|
|
401
|
+
}
|
|
402
|
+
case 'RADIO_GET_CONNECTED_USER': {
|
|
403
|
+
return {
|
|
404
|
+
roomId: args[0],
|
|
405
|
+
identity: args[1]
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
case 'RADIO_SET_USER_CHANNELS': {
|
|
409
|
+
return {
|
|
410
|
+
identity: args[0],
|
|
411
|
+
options: args[1] ?? {}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
case 'RADIO_SET_USER_DISPLAY_NAME': {
|
|
415
|
+
return {
|
|
416
|
+
accId: args[0],
|
|
417
|
+
displayName: args[1]
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
case 'RADIO_SET_SERVER_IP': {
|
|
421
|
+
return {
|
|
422
|
+
pushUrl: args[0]
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
case 'RADIO_SET_IN_GAME_SPEAKER_LOCATIONS': {
|
|
426
|
+
return {
|
|
427
|
+
locations: args[0],
|
|
428
|
+
token: args[1]
|
|
429
|
+
}
|
|
430
|
+
}
|
|
320
431
|
default: {
|
|
321
432
|
return args;
|
|
322
433
|
}
|
|
@@ -5,7 +5,8 @@ import { EventEmitter } from 'events';
|
|
|
5
5
|
|
|
6
6
|
import type { Instance } from '../../../../instance/Instance';
|
|
7
7
|
import { RESTOptions, RateLimitData, RestEvents } from './REST';
|
|
8
|
-
import { DefaultCADRestOptions, DefaultCMSRestOptions, AllAPITypes/**, RESTTypedAPIDataStructs, PossibleRequestData*/ } from './utils/constants';
|
|
8
|
+
import { DefaultCADRestOptions, DefaultCMSRestOptions, DefaultRadioRestOptions, AllAPITypes/**, RESTTypedAPIDataStructs, PossibleRequestData*/ } from './utils/constants';
|
|
9
|
+
import type { AllAPITypeData } from './utils/constants';
|
|
9
10
|
import { productEnums } from '../../../../constants';
|
|
10
11
|
// import { APIError, HTTPError } from './errors';
|
|
11
12
|
import { IHandler } from './handlers/IHandler';
|
|
@@ -29,6 +30,7 @@ export interface RequestData {
|
|
|
29
30
|
key: string;
|
|
30
31
|
type: string;
|
|
31
32
|
data: any;
|
|
33
|
+
internalKey?: string;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
export interface InternalRequestData extends RequestData {
|
|
@@ -87,6 +89,10 @@ export class RequestManager extends EventEmitter {
|
|
|
87
89
|
this.options = { ...DefaultCMSRestOptions, ...options };
|
|
88
90
|
break;
|
|
89
91
|
}
|
|
92
|
+
case productEnums.RADIO: {
|
|
93
|
+
this.options = { ...DefaultRadioRestOptions, ...options };
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
90
96
|
default: {
|
|
91
97
|
throw new Error('No Product provided for RequestManager initialization');
|
|
92
98
|
}
|
|
@@ -134,10 +140,16 @@ export class RequestManager extends EventEmitter {
|
|
|
134
140
|
case productEnums.CMS:
|
|
135
141
|
apiURL = instance.cmsApiUrl;
|
|
136
142
|
break;
|
|
143
|
+
case productEnums.RADIO:
|
|
144
|
+
apiURL = instance.radioApiUrl;
|
|
145
|
+
break;
|
|
137
146
|
}
|
|
138
147
|
|
|
139
148
|
const findType = AllAPITypes.find((_type) => _type.type === type);
|
|
140
149
|
if (findType) {
|
|
150
|
+
if (product === productEnums.RADIO) {
|
|
151
|
+
return RequestManager.resolveRadioRequest(instance, apiURL, findType, data, apiData);
|
|
152
|
+
}
|
|
141
153
|
apiData.fullUrl = `${apiURL}/${findType.path}`;
|
|
142
154
|
apiData.method = findType.method;
|
|
143
155
|
apiData.fetchOptions.method = findType.method;
|
|
@@ -150,6 +162,10 @@ export class RequestManager extends EventEmitter {
|
|
|
150
162
|
apiData.data.data = clonedData;
|
|
151
163
|
break;
|
|
152
164
|
}
|
|
165
|
+
case 'SET_GAME_SERVERS': {
|
|
166
|
+
apiData.data.data = clonedData;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
153
169
|
case 'SET_PENAL_CODES': {
|
|
154
170
|
apiData.data.data = [clonedData[0]];
|
|
155
171
|
break;
|
|
@@ -186,14 +202,37 @@ export class RequestManager extends EventEmitter {
|
|
|
186
202
|
apiData.data.data = clonedData;
|
|
187
203
|
break;
|
|
188
204
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
205
|
+
case 'SET_POSTALS': {
|
|
206
|
+
apiData.data.data = [clonedData[0]];
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
case 'SET_CLOCK': {
|
|
210
|
+
apiData.data.data = Array.isArray(clonedData) ? clonedData : [clonedData];
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
case 'JOIN_COMMUNITY':
|
|
214
|
+
case 'LEAVE_COMMUNITY': {
|
|
215
|
+
const internalKey = clonedData?.internalKey;
|
|
216
|
+
if (internalKey !== undefined) {
|
|
217
|
+
apiData.data.internalKey = internalKey;
|
|
218
|
+
}
|
|
219
|
+
const accountsSource = clonedData?.accounts;
|
|
220
|
+
const accountsArray = Array.isArray(accountsSource) ? accountsSource : accountsSource ? [accountsSource] : [];
|
|
221
|
+
apiData.data.data = accountsArray.map((entry: any) => {
|
|
222
|
+
if (typeof entry === 'string') {
|
|
223
|
+
return { account: entry };
|
|
224
|
+
}
|
|
225
|
+
if (entry && typeof entry === 'object' && 'account' in entry) {
|
|
226
|
+
return entry;
|
|
227
|
+
}
|
|
228
|
+
return { account: String(entry) };
|
|
229
|
+
});
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
case 'NEW_CHARACTER': {
|
|
233
|
+
apiData.data.data = [clonedData[0]];
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
197
236
|
case 'EDIT_CHARACTER': {
|
|
198
237
|
apiData.data.data = [clonedData[0]];
|
|
199
238
|
break;
|
|
@@ -255,7 +294,179 @@ export class RequestManager extends EventEmitter {
|
|
|
255
294
|
return apiData;
|
|
256
295
|
}
|
|
257
296
|
|
|
297
|
+
private static resolveRadioRequest(instance: Instance, apiURL: string | boolean, apiType: AllAPITypeData, request: RequestData, apiData: APIData): APIData {
|
|
298
|
+
if (!apiURL || typeof apiURL !== 'string') {
|
|
299
|
+
throw new Error('Radio API URL could not be resolved for request.');
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const rawData = request.data;
|
|
303
|
+
const payload: any =
|
|
304
|
+
rawData == null ? {} : (typeof rawData === 'object' ? cloneObject(rawData) : rawData);
|
|
305
|
+
const headers: Record<string, string> = {
|
|
306
|
+
Accept: 'application/json'
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
const applyHeaders = (source: unknown) => {
|
|
310
|
+
if (!source) return;
|
|
311
|
+
if (Array.isArray(source)) {
|
|
312
|
+
for (const [key, value] of source) {
|
|
313
|
+
headers[key] = value;
|
|
314
|
+
}
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (typeof source === 'object' && source !== null && 'forEach' in source && typeof (source as any).forEach === 'function') {
|
|
318
|
+
(source as any).forEach((value: string, key: string) => {
|
|
319
|
+
headers[key] = value;
|
|
320
|
+
});
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
Object.assign(headers, source as Record<string, string>);
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
applyHeaders(instance.apiHeaders);
|
|
327
|
+
|
|
328
|
+
let method = apiType.method;
|
|
329
|
+
let path = apiType.path;
|
|
330
|
+
let body: unknown;
|
|
331
|
+
|
|
332
|
+
const ensureAuth = () => {
|
|
333
|
+
if (!request.id || !request.key) {
|
|
334
|
+
throw new Error('Community ID or API Key could not be found for request.');
|
|
335
|
+
}
|
|
336
|
+
return {
|
|
337
|
+
id: request.id,
|
|
338
|
+
key: request.key,
|
|
339
|
+
encodedId: encodeURIComponent(request.id),
|
|
340
|
+
encodedKey: encodeURIComponent(request.key)
|
|
341
|
+
};
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const encodeSegment = (value: string | number) => encodeURIComponent(String(value));
|
|
345
|
+
|
|
346
|
+
switch (apiType.type) {
|
|
347
|
+
case 'RADIO_GET_COMMUNITY_CHANNELS': {
|
|
348
|
+
const auth = ensureAuth();
|
|
349
|
+
path = `${apiType.path}/${auth.encodedId}/${auth.encodedKey}`;
|
|
350
|
+
method = 'GET';
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
case 'RADIO_GET_CONNECTED_USERS': {
|
|
354
|
+
const auth = ensureAuth();
|
|
355
|
+
path = `${apiType.path}/${auth.encodedId}/${auth.encodedKey}`;
|
|
356
|
+
method = 'GET';
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
case 'RADIO_GET_CONNECTED_USER': {
|
|
360
|
+
const auth = ensureAuth();
|
|
361
|
+
const roomIdRaw = payload?.roomId ?? payload?.roomID;
|
|
362
|
+
if (roomIdRaw === undefined) {
|
|
363
|
+
throw new Error('roomId is required for RADIO_GET_CONNECTED_USER requests.');
|
|
364
|
+
}
|
|
365
|
+
const roomIdNumeric = typeof roomIdRaw === 'number' ? roomIdRaw : Number(roomIdRaw);
|
|
366
|
+
if (Number.isNaN(roomIdNumeric)) {
|
|
367
|
+
throw new Error('roomId must be a number for RADIO_GET_CONNECTED_USER requests.');
|
|
368
|
+
}
|
|
369
|
+
const identity = payload?.identity;
|
|
370
|
+
if (!identity) {
|
|
371
|
+
throw new Error('identity is required for RADIO_GET_CONNECTED_USER requests.');
|
|
372
|
+
}
|
|
373
|
+
path = `${apiType.path}/${auth.encodedId}/${auth.encodedKey}/${encodeSegment(roomIdNumeric)}/${encodeSegment(identity)}`;
|
|
374
|
+
method = 'GET';
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
case 'RADIO_SET_USER_CHANNELS': {
|
|
378
|
+
const auth = ensureAuth();
|
|
379
|
+
const identity = payload?.identity;
|
|
380
|
+
if (!identity) {
|
|
381
|
+
throw new Error('identity is required for RADIO_SET_USER_CHANNELS requests.');
|
|
382
|
+
}
|
|
383
|
+
const options = payload?.options ?? {};
|
|
384
|
+
path = `${apiType.path}/${auth.encodedId}/${auth.encodedKey}/${encodeSegment(identity)}`;
|
|
385
|
+
method = 'POST';
|
|
386
|
+
const requestBody: Record<string, unknown> = {};
|
|
387
|
+
if (options?.transmit !== undefined) {
|
|
388
|
+
requestBody.transmit = options.transmit;
|
|
389
|
+
}
|
|
390
|
+
if (options?.scan !== undefined) {
|
|
391
|
+
requestBody.scan = options.scan;
|
|
392
|
+
}
|
|
393
|
+
body = requestBody;
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
case 'RADIO_SET_USER_DISPLAY_NAME': {
|
|
397
|
+
const auth = ensureAuth();
|
|
398
|
+
const accId = payload?.accId;
|
|
399
|
+
const displayName = payload?.displayName;
|
|
400
|
+
if (!accId || !displayName) {
|
|
401
|
+
throw new Error('accId and displayName are required for RADIO_SET_USER_DISPLAY_NAME requests.');
|
|
402
|
+
}
|
|
403
|
+
method = 'POST';
|
|
404
|
+
body = {
|
|
405
|
+
id: auth.id,
|
|
406
|
+
key: auth.key,
|
|
407
|
+
accId,
|
|
408
|
+
displayName
|
|
409
|
+
};
|
|
410
|
+
path = apiType.path;
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
case 'RADIO_GET_SERVER_SUBSCRIPTION_FROM_IP': {
|
|
414
|
+
method = 'GET';
|
|
415
|
+
path = apiType.path;
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
case 'RADIO_SET_SERVER_IP': {
|
|
419
|
+
const auth = ensureAuth();
|
|
420
|
+
const pushUrl = payload?.pushUrl;
|
|
421
|
+
if (!pushUrl) {
|
|
422
|
+
throw new Error('pushUrl is required for RADIO_SET_SERVER_IP requests.');
|
|
423
|
+
}
|
|
424
|
+
method = 'POST';
|
|
425
|
+
body = {
|
|
426
|
+
id: auth.id,
|
|
427
|
+
key: auth.key,
|
|
428
|
+
pushUrl
|
|
429
|
+
};
|
|
430
|
+
path = apiType.path;
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
case 'RADIO_SET_IN_GAME_SPEAKER_LOCATIONS': {
|
|
434
|
+
const auth = ensureAuth();
|
|
435
|
+
const locations = payload?.locations;
|
|
436
|
+
if (!Array.isArray(locations)) {
|
|
437
|
+
throw new Error('locations array is required for RADIO_SET_IN_GAME_SPEAKER_LOCATIONS requests.');
|
|
438
|
+
}
|
|
439
|
+
method = 'POST';
|
|
440
|
+
body = {
|
|
441
|
+
id: auth.id,
|
|
442
|
+
key: auth.key,
|
|
443
|
+
locations
|
|
444
|
+
};
|
|
445
|
+
const token = payload?.token ?? auth.key;
|
|
446
|
+
if (token) {
|
|
447
|
+
headers.Authorization = `Bearer ${token}`;
|
|
448
|
+
}
|
|
449
|
+
path = apiType.path;
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
default: {
|
|
453
|
+
throw new Error(`Unsupported radio API type received: ${apiType.type}`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
apiData.typePath = path;
|
|
458
|
+
apiData.fullUrl = `${apiURL}/${path}`;
|
|
459
|
+
apiData.method = method;
|
|
460
|
+
apiData.fetchOptions.method = method;
|
|
461
|
+
if (body !== undefined) {
|
|
462
|
+
headers['Content-Type'] = 'application/json';
|
|
463
|
+
apiData.fetchOptions.body = JSON.stringify(body);
|
|
464
|
+
}
|
|
465
|
+
apiData.fetchOptions.headers = headers;
|
|
466
|
+
return apiData;
|
|
467
|
+
}
|
|
468
|
+
|
|
258
469
|
debug(log: string) {
|
|
259
470
|
return this.instance._debugLog(log);
|
|
260
471
|
}
|
|
261
|
-
}
|
|
472
|
+
}
|
|
@@ -16,6 +16,24 @@ export class RateLimitError extends Error implements RateLimitData {
|
|
|
16
16
|
* The name of the error
|
|
17
17
|
*/
|
|
18
18
|
public override get name(): string {
|
|
19
|
-
|
|
19
|
+
let productName: string;
|
|
20
|
+
switch (this.product) {
|
|
21
|
+
case productEnums.CAD: {
|
|
22
|
+
productName = 'Sonoran CAD';
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
case productEnums.CMS: {
|
|
26
|
+
productName = 'Sonoran CMS';
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
case productEnums.RADIO: {
|
|
30
|
+
productName = 'Sonoran Radio';
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
default: {
|
|
34
|
+
productName = 'Invalid Product';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return `Ratelimit Hit - [${productName} '${this.type}']`;
|
|
20
38
|
}
|
|
21
|
-
}
|
|
39
|
+
}
|