@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
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { Instance } from '../instance/Instance';
|
|
2
|
-
import { CMSServerAPIStruct } from '../libs/rest/src';
|
|
2
|
+
import { APIError, CMSServerAPIStruct } from '../libs/rest/src';
|
|
3
|
+
import * as globalTypes from '../constants';
|
|
3
4
|
import { CMSServer } from '../structures/CMSServer';
|
|
4
5
|
import { CacheManager } from './CacheManager';
|
|
5
6
|
import { CMSManager } from './CMSManager';
|
|
6
7
|
|
|
7
8
|
export class CMSServerManager extends CacheManager<number, CMSServer, CMSServerAPIStruct> {
|
|
8
|
-
constructor(instance: Instance, manager: CMSManager) {
|
|
9
|
+
constructor(instance: Instance, private readonly manager: CMSManager) {
|
|
9
10
|
super(instance, CMSServer, []);
|
|
10
|
-
|
|
11
11
|
(async () => {
|
|
12
|
-
|
|
12
|
+
const managerRef = this.manager;
|
|
13
|
+
while(!managerRef.ready) {
|
|
13
14
|
await new Promise((resolve) => {
|
|
14
15
|
setTimeout(resolve, 100);
|
|
15
16
|
});
|
|
16
17
|
}
|
|
17
18
|
try {
|
|
18
|
-
const serversRes: any = await
|
|
19
|
+
const serversRes: any = await managerRef.rest?.request('GET_GAME_SERVERS');
|
|
19
20
|
const servers = serversRes.servers;
|
|
20
21
|
servers.forEach((server: CMSServerAPIStruct) => {
|
|
21
22
|
const serverStruct = {
|
|
@@ -30,4 +31,36 @@ export class CMSServerManager extends CacheManager<number, CMSServer, CMSServerA
|
|
|
30
31
|
}
|
|
31
32
|
})();
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
+
|
|
35
|
+
public async setGameServers(servers: globalTypes.CMSSetGameServerStruct[]): Promise<globalTypes.CMSSetGameServersPromiseResult> {
|
|
36
|
+
if (!Array.isArray(servers) || servers.length === 0) {
|
|
37
|
+
throw new Error('servers array must include at least one server configuration.');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return new Promise(async (resolve, reject) => {
|
|
41
|
+
try {
|
|
42
|
+
const response: any = await this.manager.rest?.request('SET_GAME_SERVERS', servers);
|
|
43
|
+
const updatedServers = (Array.isArray(response?.data) ? response.data : []) as CMSServerAPIStruct[];
|
|
44
|
+
|
|
45
|
+
if (updatedServers.length > 0) {
|
|
46
|
+
this.cache.clear();
|
|
47
|
+
updatedServers.forEach((server) => {
|
|
48
|
+
const serverStruct = {
|
|
49
|
+
id: server.id,
|
|
50
|
+
config: server
|
|
51
|
+
};
|
|
52
|
+
this._add(serverStruct, true, server.id);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
resolve({ success: true, data: updatedServers as globalTypes.CMSSetGameServerStruct[] });
|
|
57
|
+
} catch (err) {
|
|
58
|
+
if (err instanceof APIError) {
|
|
59
|
+
resolve({ success: false, reason: err.response });
|
|
60
|
+
} else {
|
|
61
|
+
reject(err);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { Instance } from '../instance/Instance';
|
|
2
|
+
import { APIError, DefaultRadioRestOptions, REST } from '../libs/rest/src';
|
|
3
|
+
import { BaseManager } from './BaseManager';
|
|
4
|
+
import * as globalTypes from '../constants';
|
|
5
|
+
import type { Mutable } from '../constants';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Manages all Sonoran Radio API interactions.
|
|
9
|
+
*/
|
|
10
|
+
export class RadioManager extends BaseManager {
|
|
11
|
+
public readonly ready: boolean = false;
|
|
12
|
+
public readonly failReason: unknown = null;
|
|
13
|
+
public rest: REST | undefined;
|
|
14
|
+
|
|
15
|
+
constructor(instance: Instance) {
|
|
16
|
+
super(instance);
|
|
17
|
+
|
|
18
|
+
this.rest = new REST(instance, this, globalTypes.productEnums.RADIO, DefaultRadioRestOptions);
|
|
19
|
+
void this.buildManager(instance);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
protected async buildManager(instance: Instance) {
|
|
23
|
+
const mutableThis = this as Mutable<RadioManager>;
|
|
24
|
+
try {
|
|
25
|
+
mutableThis.ready = true;
|
|
26
|
+
instance.isRadioSuccessful = true;
|
|
27
|
+
instance.emit('RADIO_SETUP_SUCCESSFUL');
|
|
28
|
+
} catch (err) {
|
|
29
|
+
mutableThis.failReason = err;
|
|
30
|
+
instance.emit('RADIO_SETUP_UNSUCCESSFUL', err);
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Retrieves the configured community channel groups and channels.
|
|
37
|
+
*/
|
|
38
|
+
public async getCommunityChannels(): Promise<globalTypes.RadioGetCommunityChannelsPromiseResult> {
|
|
39
|
+
return new Promise(async (resolve, reject) => {
|
|
40
|
+
try {
|
|
41
|
+
const response: any = await this.rest?.request('RADIO_GET_COMMUNITY_CHANNELS');
|
|
42
|
+
resolve({ success: true, data: response });
|
|
43
|
+
} catch (err) {
|
|
44
|
+
if (err instanceof APIError) {
|
|
45
|
+
resolve({ success: false, reason: err.response });
|
|
46
|
+
} else {
|
|
47
|
+
reject(err);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Retrieves all connected users for the community.
|
|
55
|
+
*/
|
|
56
|
+
public async getConnectedUsers(): Promise<globalTypes.RadioGetConnectedUsersPromiseResult> {
|
|
57
|
+
return new Promise(async (resolve, reject) => {
|
|
58
|
+
try {
|
|
59
|
+
const response: any = await this.rest?.request('RADIO_GET_CONNECTED_USERS');
|
|
60
|
+
resolve({ success: true, data: response });
|
|
61
|
+
} catch (err) {
|
|
62
|
+
if (err instanceof APIError) {
|
|
63
|
+
resolve({ success: false, reason: err.response });
|
|
64
|
+
} else {
|
|
65
|
+
reject(err);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Retrieves a specific connected user by room id and identity.
|
|
73
|
+
* @param {number} roomId Multi-server room id.
|
|
74
|
+
* @param {string} identity User account UUID.
|
|
75
|
+
*/
|
|
76
|
+
public async getConnectedUser(roomId: number, identity: string): Promise<globalTypes.RadioGetConnectedUserPromiseResult> {
|
|
77
|
+
return new Promise(async (resolve, reject) => {
|
|
78
|
+
try {
|
|
79
|
+
const response: any = await this.rest?.request('RADIO_GET_CONNECTED_USER', roomId, identity);
|
|
80
|
+
resolve({ success: true, data: response });
|
|
81
|
+
} catch (err) {
|
|
82
|
+
if (err instanceof APIError) {
|
|
83
|
+
resolve({ success: false, reason: err.response });
|
|
84
|
+
} else {
|
|
85
|
+
reject(err);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Updates a user's transmit and scanned channel configuration.
|
|
93
|
+
* @param {string} identity The user's UUID.
|
|
94
|
+
* @param {RadioSetUserChannelsOptions} options Transmit and scan channel configuration.
|
|
95
|
+
*/
|
|
96
|
+
public async setUserChannels(identity: string, options: globalTypes.RadioSetUserChannelsOptions = {}): Promise<globalTypes.RadioSetUserChannelsPromiseResult> {
|
|
97
|
+
return new Promise(async (resolve, reject) => {
|
|
98
|
+
try {
|
|
99
|
+
const response: any = await this.rest?.request('RADIO_SET_USER_CHANNELS', identity, options);
|
|
100
|
+
resolve({ success: true, result: response?.result ?? response });
|
|
101
|
+
} catch (err) {
|
|
102
|
+
if (err instanceof APIError) {
|
|
103
|
+
resolve({ success: false, reason: err.response });
|
|
104
|
+
} else {
|
|
105
|
+
reject(err);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Updates a user's display name.
|
|
113
|
+
* @param {string} accId The user's account UUID.
|
|
114
|
+
* @param {string} displayName The new display name.
|
|
115
|
+
*/
|
|
116
|
+
public async setUserDisplayName(accId: string, displayName: string): Promise<globalTypes.RadioSetUserDisplayNamePromiseResult> {
|
|
117
|
+
return new Promise(async (resolve, reject) => {
|
|
118
|
+
try {
|
|
119
|
+
const response: any = await this.rest?.request('RADIO_SET_USER_DISPLAY_NAME', accId, displayName);
|
|
120
|
+
resolve({ success: true, result: response?.result ?? response });
|
|
121
|
+
} catch (err) {
|
|
122
|
+
if (err instanceof APIError) {
|
|
123
|
+
resolve({ success: false, reason: err.response });
|
|
124
|
+
} else {
|
|
125
|
+
reject(err);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Retrieves the community subscription level determined by the calling server's IP.
|
|
133
|
+
*/
|
|
134
|
+
public async getServerSubscriptionFromIp(): Promise<globalTypes.RadioGetServerSubscriptionFromIpPromiseResult> {
|
|
135
|
+
return new Promise(async (resolve, reject) => {
|
|
136
|
+
try {
|
|
137
|
+
const response: any = await this.rest?.request('RADIO_GET_SERVER_SUBSCRIPTION_FROM_IP');
|
|
138
|
+
resolve({ success: true, data: response });
|
|
139
|
+
} catch (err) {
|
|
140
|
+
if (err instanceof APIError) {
|
|
141
|
+
resolve({ success: false, reason: err.response });
|
|
142
|
+
} else {
|
|
143
|
+
reject(err);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Sets the push event URL for the community.
|
|
151
|
+
* @param {string} pushUrl The server push URL.
|
|
152
|
+
*/
|
|
153
|
+
public async setServerIp(pushUrl: string): Promise<globalTypes.RadioSetServerIpPromiseResult> {
|
|
154
|
+
return new Promise(async (resolve, reject) => {
|
|
155
|
+
try {
|
|
156
|
+
const response: any = await this.rest?.request('RADIO_SET_SERVER_IP', pushUrl);
|
|
157
|
+
resolve({ success: true, result: response?.result ?? response });
|
|
158
|
+
} catch (err) {
|
|
159
|
+
if (err instanceof APIError) {
|
|
160
|
+
resolve({ success: false, reason: err.response });
|
|
161
|
+
} else {
|
|
162
|
+
reject(err);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Sets the available in-game speaker locations for tone dispatching.
|
|
170
|
+
* @param {RadioSpeakerLocation[]} locations Collection of speaker locations.
|
|
171
|
+
* @param {string} [token] Optional bearer token for authorization. Defaults to the community API key.
|
|
172
|
+
*/
|
|
173
|
+
public async setInGameSpeakerLocations(locations: globalTypes.RadioSpeakerLocation[], token?: string): Promise<globalTypes.RadioSetInGameSpeakerLocationsPromiseResult> {
|
|
174
|
+
return new Promise(async (resolve, reject) => {
|
|
175
|
+
try {
|
|
176
|
+
const response: any = await this.rest?.request('RADIO_SET_IN_GAME_SPEAKER_LOCATIONS', locations, token);
|
|
177
|
+
resolve({ success: true, result: response?.result ?? response });
|
|
178
|
+
} catch (err) {
|
|
179
|
+
if (err instanceof APIError) {
|
|
180
|
+
resolve({ success: false, reason: err.response });
|
|
181
|
+
} else {
|
|
182
|
+
reject(err);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|