@sonoransoftware/sonoran.js 1.0.34 → 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.
Files changed (38) hide show
  1. package/.github/workflows/auto-pr-on-branch-push.yml +89 -0
  2. package/.github/workflows/codex_instructions.md +24 -0
  3. package/.github/workflows/push-pr-nudge-codex.yml +50 -0
  4. package/dist/constants.d.ts +200 -1
  5. package/dist/constants.js +1 -0
  6. package/dist/index.d.ts +1 -1
  7. package/dist/instance/Instance.d.ts +6 -0
  8. package/dist/instance/Instance.js +27 -0
  9. package/dist/instance/instance.types.d.ts +3 -0
  10. package/dist/libs/rest/src/lib/REST.d.ts +2 -1
  11. package/dist/libs/rest/src/lib/REST.js +108 -0
  12. package/dist/libs/rest/src/lib/RequestManager.d.ts +2 -0
  13. package/dist/libs/rest/src/lib/RequestManager.js +201 -0
  14. package/dist/libs/rest/src/lib/errors/RateLimitError.js +19 -1
  15. package/dist/libs/rest/src/lib/utils/constants.d.ts +102 -22
  16. package/dist/libs/rest/src/lib/utils/constants.js +106 -2
  17. package/dist/managers/CADManager.d.ts +28 -0
  18. package/dist/managers/CADManager.js +90 -0
  19. package/dist/managers/CMSManager.d.ts +54 -0
  20. package/dist/managers/CMSManager.js +134 -0
  21. package/dist/managers/CMSServerManager.d.ts +3 -0
  22. package/dist/managers/CMSServerManager.js +36 -2
  23. package/dist/managers/RadioManager.d.ts +55 -0
  24. package/dist/managers/RadioManager.js +224 -0
  25. package/package.json +1 -1
  26. package/readme.md +170 -0
  27. package/src/constants.ts +232 -1
  28. package/src/index.ts +35 -1
  29. package/src/instance/Instance.ts +30 -1
  30. package/src/instance/instance.types.ts +4 -1
  31. package/src/libs/rest/src/lib/REST.ts +107 -1
  32. package/src/libs/rest/src/lib/RequestManager.ts +221 -10
  33. package/src/libs/rest/src/lib/errors/RateLimitError.ts +20 -2
  34. package/src/libs/rest/src/lib/utils/constants.ts +205 -24
  35. package/src/managers/CADManager.ts +86 -1
  36. package/src/managers/CMSManager.ts +121 -0
  37. package/src/managers/CMSServerManager.ts +39 -6
  38. package/src/managers/RadioManager.ts +187 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonoransoftware/sonoran.js",
3
- "version": "1.0.34",
3
+ "version": "1.0.35",
4
4
  "description": "Sonoran.js is a library that allows you to interact with the Sonoran CAD and Sonoran CMS API. Based off of and utilizes several Discord.js library techniques for ease of use.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/readme.md CHANGED
@@ -64,6 +64,36 @@ const params = {
64
64
  const account = await instance.cad.getAccount(params);
65
65
  ```
66
66
 
67
+ ### setClockTime
68
+ Synchronizes the CAD clock with your in-game time.
69
+ #### Argument `params`
70
+ ##### Type: `object` `{ serverId: number, currentUtc: string, currentGame: string, secondsPerHour: number }`
71
+ ```js
72
+ await instance.cad.setClockTime({
73
+ serverId: 1,
74
+ currentUtc: new Date().toISOString(),
75
+ currentGame: '2025-07-04T18:00:00Z',
76
+ secondsPerHour: 60
77
+ });
78
+ ```
79
+
80
+ ### joinCommunity
81
+ Adds one or more accounts to the community using an internal key.
82
+ ```js
83
+ await instance.cad.joinCommunity('internal-key', [
84
+ { account: '1234567890' },
85
+ '0987654321'
86
+ ]);
87
+ ```
88
+
89
+ ### leaveCommunity
90
+ Removes one or more accounts from the community using an internal key.
91
+ ```js
92
+ await instance.cad.leaveCommunity('internal-key', [
93
+ { account: '1234567890' }
94
+ ]);
95
+ ```
96
+
67
97
  ## CMS Functions
68
98
  ### verifyWhitelist(obj)
69
99
  Verifies that a user is whitelisted in the specified server.
@@ -176,5 +206,145 @@ const params = {
176
206
  const setRanks = await instance.cms.setAccountRanks(params, undefined, undefined, undefined, '12345678', undefined);
177
207
  ```
178
208
 
209
+ ### setAccountName(apiId, username, accId, discord, uniqueId, newName)
210
+ Sets the display name used in CMS for an account.
211
+ ```js
212
+ await instance.cms.setAccountName(undefined, undefined, 'account-uuid', undefined, undefined, 'New Display Name');
213
+ ```
214
+
215
+ ### cmsBanAccount(params)
216
+ Adds a ban flag to the targeted account.
217
+ ```js
218
+ await instance.cms.cmsBanAccount({ apiId: '1234' });
219
+ ```
220
+
221
+ ### cmsKickAccount(params)
222
+ Performs a CMS kick request for the targeted account.
223
+ ```js
224
+ await instance.cms.cmsKickAccount({ discord: '1234567890' });
225
+ ```
226
+
227
+ ### forceSync(params)
228
+ Manually triggers a CMS force-sync for the targeted identifiers.
229
+ ```js
230
+ await instance.cms.forceSync({ username: 'SomeUser' });
231
+ ```
232
+
233
+ ### getCurrentClockIn(params)
234
+ Fetches the current clock-in entry for the account if one exists.
235
+ ```js
236
+ const currentEntry = await instance.cms.getCurrentClockIn({ apiId: '1234' });
237
+ ```
238
+
239
+ ### getAccounts(options)
240
+ Retrieves CMS accounts with optional pagination and status filters.
241
+ ```js
242
+ const accounts = await instance.cms.getAccounts({ take: 50, banned: false });
243
+ ```
244
+
245
+ ### getProfileFields()
246
+ Returns profile field definitions configured for the community.
247
+ ```js
248
+ const profileFields = await instance.cms.getProfileFields();
249
+ ```
250
+
251
+ ### rsvp(eventId, params)
252
+ Toggles RSVP for an event for the provided account identifiers.
253
+ ```js
254
+ await instance.cms.rsvp('event-id', { accId: 'account-uuid' });
255
+ ```
256
+
257
+ ### getFormSubmissions(templateId, options)
258
+ Retrieves form submissions with optional pagination.
259
+ ```js
260
+ const submissions = await instance.cms.getFormSubmissions(42, { skip: 0, take: 25 });
261
+ ```
262
+
263
+ ### editAccountProfileFields(params)
264
+ Updates profile fields for an account.
265
+ ```js
266
+ await instance.cms.editAccountProfileFields({
267
+ accId: 'account-uuid',
268
+ profileFields: [
269
+ { fieldId: 10, value: 'Value' }
270
+ ]
271
+ });
272
+ ```
273
+
274
+ ### erlcGetOnlinePlayers(robloxJoinCode)
275
+ Returns the current ERLC player list for the join code.
276
+ ```js
277
+ const players = await instance.cms.erlcGetOnlinePlayers('join-code');
278
+ ```
279
+
280
+ ### erlcGetPlayerQueue(robloxJoinCode)
281
+ Returns the current ERLC player queue count for the join code.
282
+ ```js
283
+ const queue = await instance.cms.erlcGetPlayerQueue('join-code');
284
+ ```
285
+
286
+ ### erlcAddNewRecord(data)
287
+ Adds a moderation record for a player in ERLC.
288
+ ```js
289
+ await instance.cms.erlcAddNewRecord({
290
+ robloxJoinCode: 'join-code',
291
+ executerDiscordId: '1234567890',
292
+ type: 'Warning',
293
+ reason: 'Reckless driving'
294
+ });
295
+ ```
296
+
297
+ ## Radio Functions
298
+ ### getCommunityChannels()
299
+ Retrieves configured community channel groups and channels.
300
+ ```js
301
+ const channels = await instance.radio.getCommunityChannels();
302
+ ```
303
+
304
+ ### getConnectedUsers()
305
+ Lists all connected radio users in the community.
306
+ ```js
307
+ const users = await instance.radio.getConnectedUsers();
308
+ ```
309
+
310
+ ### getConnectedUser(roomId, identity)
311
+ Fetches a specific connected radio user by room and identity.
312
+ ```js
313
+ const user = await instance.radio.getConnectedUser(1, 'account-uuid');
314
+ ```
315
+
316
+ ### setUserChannels(identity, options)
317
+ Updates a user's transmit or scan channels.
318
+ ```js
319
+ await instance.radio.setUserChannels('account-uuid', { transmit: 12, scan: [10, 11, 12] });
320
+ ```
321
+
322
+ ### setUserDisplayName(accId, displayName)
323
+ Sets the user's radio display name.
324
+ ```js
325
+ await instance.radio.setUserDisplayName('account-uuid', 'Dispatch 101');
326
+ ```
327
+
328
+ ### getServerSubscriptionFromIp()
329
+ Resolves the community's subscription level for the calling server IP.
330
+ ```js
331
+ const subscription = await instance.radio.getServerSubscriptionFromIp();
332
+ ```
333
+
334
+ ### setServerIp(pushUrl)
335
+ Registers the push event URL for radio webhooks.
336
+ ```js
337
+ await instance.radio.setServerIp('https://example.com/sonoran-radio');
338
+ ```
339
+
340
+ ### setInGameSpeakerLocations(locations, token?)
341
+ Publishes available in-game speaker locations for tone routing.
342
+ ```js
343
+ await instance.radio.setInGameSpeakerLocations(
344
+ [{ name: 'Station 1', x: 123.4, y: 567.8, z: 90.1 }],
345
+ 'optional-bearer-token'
346
+ );
347
+ ```
348
+
179
349
  ## Further Documentation
180
350
  More documentation for Sonoran CAD specific methods and usage can be found [here](/docs/CAD-Methods-and-Usage.md), Sonoran CMS specific methods and usage can be found [here](/docs/CMS-Methods-and-Usage.md), and usage information for the REST class [here](/docs/REST-Methods-and-Usage.md).
package/src/constants.ts CHANGED
@@ -6,7 +6,8 @@ import { CADActiveUnit } from './structures/CADActiveUnit';
6
6
 
7
7
  export enum productEnums {
8
8
  CAD,
9
- CMS
9
+ CMS,
10
+ RADIO
10
11
  }
11
12
 
12
13
  export interface CADNewDispatchBuilderOptions {
@@ -252,6 +253,31 @@ export interface CMSSetAccountNamePromiseResult {
252
253
  reason?: string;
253
254
  }
254
255
 
256
+ export interface CADSetClockTimePromiseResult {
257
+ success: boolean;
258
+ reason?: string;
259
+ data?: unknown;
260
+ }
261
+
262
+ export interface CADJoinCommunityPromiseResult {
263
+ success: boolean;
264
+ reason?: string;
265
+ data?: unknown;
266
+ }
267
+
268
+ export interface CADLeaveCommunityPromiseResult {
269
+ success: boolean;
270
+ reason?: string;
271
+ data?: unknown;
272
+ }
273
+
274
+ export interface CMSProfileField {
275
+ id: string;
276
+ type: string;
277
+ label: string;
278
+ options: unknown;
279
+ }
280
+
255
281
  export interface CMSKickAccountPromiseResult {
256
282
  success: boolean;
257
283
  reason?: string;
@@ -267,6 +293,84 @@ export interface CMSForceSyncPromiseResult {
267
293
  reason?: string;
268
294
  }
269
295
 
296
+ export interface CMSGetCurrentClockInPromiseResult {
297
+ success: boolean;
298
+ reason?: string;
299
+ data?: clockInOutRequest | null;
300
+ }
301
+
302
+ export interface CMSAccountSummary {
303
+ accId: string;
304
+ accName: string;
305
+ activeApiIds: string[];
306
+ discordId?: string;
307
+ sysStatus: boolean;
308
+ comStatus: boolean;
309
+ archived: boolean;
310
+ banned: boolean;
311
+ [key: string]: unknown;
312
+ }
313
+
314
+ export interface CMSAccountsPage {
315
+ total: number;
316
+ skip: number;
317
+ take: number;
318
+ accounts: CMSAccountSummary[];
319
+ }
320
+
321
+ export interface CMSGetAccountsPromiseResult {
322
+ success: boolean;
323
+ reason?: string;
324
+ data?: CMSAccountsPage;
325
+ }
326
+
327
+ export interface CMSGetProfileFieldsPromiseResult {
328
+ success: boolean;
329
+ reason?: string;
330
+ data?: CMSProfileField[];
331
+ }
332
+
333
+ export interface CMSProfileFieldUpdate {
334
+ id: string;
335
+ value: unknown;
336
+ }
337
+
338
+ export interface CMSEditAccountProfileFieldsPromiseResult {
339
+ success: boolean;
340
+ reason?: string;
341
+ data?: CMSProfileFieldUpdate[];
342
+ }
343
+
344
+ export interface CMSRsvpPromiseResult {
345
+ success: boolean;
346
+ reason?: string;
347
+ status?: string;
348
+ data?: unknown;
349
+ }
350
+
351
+ export interface CMSSetGameServerStruct {
352
+ id?: number;
353
+ name: string;
354
+ description?: string;
355
+ ip?: string;
356
+ port?: string;
357
+ allowedRanks?: string[];
358
+ blockedRanks?: string[];
359
+ [key: string]: unknown;
360
+ }
361
+
362
+ export interface CMSSetGameServersPromiseResult {
363
+ success: boolean;
364
+ reason?: string;
365
+ data?: CMSSetGameServerStruct[];
366
+ }
367
+
368
+ export interface CMSGetFormSubmissionsPromiseResult<T = unknown> {
369
+ success: boolean;
370
+ reason?: string;
371
+ data?: T[];
372
+ }
373
+
270
374
  export interface CMSERLCGetOnlinePlayersPromiseResult {
271
375
  success: boolean;
272
376
  reason?: string;
@@ -289,3 +393,130 @@ export interface CMSERLCAddNewRecordPromiseResult {
289
393
  reason?: string;
290
394
  logId?: string;
291
395
  }
396
+
397
+ export interface RadioChannelGroup {
398
+ id: number;
399
+ name: string;
400
+ orderIndex: number;
401
+ }
402
+
403
+ export interface RadioChannel {
404
+ id: number;
405
+ groupId: number;
406
+ displayName: string;
407
+ recvFreqMajor: number;
408
+ recvFreqMinor: number;
409
+ xmitFreqMajor: number;
410
+ xmitFreqMinor: number;
411
+ repeatsXmit: boolean;
412
+ status: boolean;
413
+ orderIndex: number;
414
+ talkoverProtection: boolean;
415
+ [key: string]: unknown;
416
+ }
417
+
418
+ export interface RadioConnectedUserMetadataScanList {
419
+ id: number;
420
+ name: string;
421
+ channelIds: number[];
422
+ [key: string]: unknown;
423
+ }
424
+
425
+ export interface RadioConnectedUserMetadataState {
426
+ primaryChId?: number;
427
+ scannedChIds?: number[];
428
+ scanLists?: RadioConnectedUserMetadataScanList[];
429
+ spec?: number;
430
+ [key: string]: unknown;
431
+ }
432
+
433
+ export interface RadioConnectedUserMetadata {
434
+ sonrad?: boolean;
435
+ state?: RadioConnectedUserMetadataState;
436
+ [key: string]: unknown;
437
+ }
438
+
439
+ export interface RadioConnectedUser {
440
+ identity: string;
441
+ name: string;
442
+ roomId?: number;
443
+ metadata: RadioConnectedUserMetadata;
444
+ [key: string]: unknown;
445
+ }
446
+
447
+ export interface RadioSpeakerLocation {
448
+ label: string;
449
+ id: string;
450
+ }
451
+
452
+ export interface RadioSetUserChannelsOptions {
453
+ transmit?: number;
454
+ scan?: number[];
455
+ }
456
+
457
+ export type RadioSubscriptionLevel = 0 | 1 | 2;
458
+
459
+ export interface RadioGetCommunityChannelsPromiseResult {
460
+ success: boolean;
461
+ reason?: string;
462
+ data?: {
463
+ result: string;
464
+ groups: RadioChannelGroup[];
465
+ channels: RadioChannel[];
466
+ [key: string]: unknown;
467
+ };
468
+ }
469
+
470
+ export interface RadioGetConnectedUsersPromiseResult {
471
+ success: boolean;
472
+ reason?: string;
473
+ data?: {
474
+ result: string;
475
+ connectedUsers: RadioConnectedUser[];
476
+ [key: string]: unknown;
477
+ };
478
+ }
479
+
480
+ export interface RadioGetConnectedUserPromiseResult {
481
+ success: boolean;
482
+ reason?: string;
483
+ data?: {
484
+ result: string;
485
+ data: RadioConnectedUser;
486
+ [key: string]: unknown;
487
+ };
488
+ }
489
+
490
+ export interface RadioSetUserChannelsPromiseResult {
491
+ success: boolean;
492
+ reason?: string;
493
+ result?: string;
494
+ }
495
+
496
+ export interface RadioSetUserDisplayNamePromiseResult {
497
+ success: boolean;
498
+ reason?: string;
499
+ result?: string;
500
+ }
501
+
502
+ export interface RadioGetServerSubscriptionFromIpPromiseResult {
503
+ success: boolean;
504
+ reason?: string;
505
+ data?: {
506
+ result: string;
507
+ subscription: RadioSubscriptionLevel;
508
+ [key: string]: unknown;
509
+ };
510
+ }
511
+
512
+ export interface RadioSetServerIpPromiseResult {
513
+ success: boolean;
514
+ reason?: string;
515
+ result?: string;
516
+ }
517
+
518
+ export interface RadioSetInGameSpeakerLocationsPromiseResult {
519
+ success: boolean;
520
+ reason?: string;
521
+ result?: string;
522
+ }
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 { productEnums, CADNewDispatchBuilderOptions, CADSubscriptionVersionEnum, CMSSubscriptionVersionEnum } from './constants';
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';
@@ -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
+ }
@@ -13,6 +13,9 @@ export type InstanceOptions = {
13
13
  cmsApiKey?: string;
14
14
  cmsApiUrl?: string;
15
15
  cmsDefaultServerId?: number;
16
+ radioCommunityId?: string;
17
+ radioApiKey?: string;
18
+ radioApiUrl?: string;
16
19
  debug?: boolean;
17
20
  apiHeaders?: HeadersInit ;
18
- };
21
+ };