polyv-live-cli 1.0.2
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/LICENSE +21 -0
- package/README.md +417 -0
- package/dist/commands/channel.commands.d.ts +9 -0
- package/dist/commands/channel.commands.d.ts.map +1 -0
- package/dist/commands/channel.commands.js +439 -0
- package/dist/commands/channel.commands.js.map +1 -0
- package/dist/commands/index.d.ts +3 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +8 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/stream.commands.d.ts +3 -0
- package/dist/commands/stream.commands.d.ts.map +1 -0
- package/dist/commands/stream.commands.js +272 -0
- package/dist/commands/stream.commands.js.map +1 -0
- package/dist/config/auth.d.ts +11 -0
- package/dist/config/auth.d.ts.map +1 -0
- package/dist/config/auth.js +124 -0
- package/dist/config/auth.js.map +1 -0
- package/dist/config/loader.d.ts +22 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +127 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/manager.d.ts +20 -0
- package/dist/config/manager.d.ts.map +1 -0
- package/dist/config/manager.js +258 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/validator.d.ts +43 -0
- package/dist/config/validator.d.ts.map +1 -0
- package/dist/config/validator.js +222 -0
- package/dist/config/validator.js.map +1 -0
- package/dist/handlers/base.handler.d.ts +15 -0
- package/dist/handlers/base.handler.d.ts.map +1 -0
- package/dist/handlers/base.handler.js +122 -0
- package/dist/handlers/base.handler.js.map +1 -0
- package/dist/handlers/channel.handler.d.ts +31 -0
- package/dist/handlers/channel.handler.d.ts.map +1 -0
- package/dist/handlers/channel.handler.js +690 -0
- package/dist/handlers/channel.handler.js.map +1 -0
- package/dist/handlers/index.d.ts +4 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +10 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/stream.handler.d.ts +25 -0
- package/dist/handlers/stream.handler.d.ts.map +1 -0
- package/dist/handlers/stream.handler.js +241 -0
- package/dist/handlers/stream.handler.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +342 -0
- package/dist/index.js.map +1 -0
- package/dist/services/channel.service.d.ts +25 -0
- package/dist/services/channel.service.d.ts.map +1 -0
- package/dist/services/channel.service.js +672 -0
- package/dist/services/channel.service.js.map +1 -0
- package/dist/services/index.d.ts +3 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +8 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/stream.service.d.ts +29 -0
- package/dist/services/stream.service.d.ts.map +1 -0
- package/dist/services/stream.service.js +489 -0
- package/dist/services/stream.service.js.map +1 -0
- package/dist/types/auth.d.ts +31 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +14 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/channel.d.ts +262 -0
- package/dist/types/channel.d.ts.map +1 -0
- package/dist/types/channel.js +3 -0
- package/dist/types/channel.js.map +1 -0
- package/dist/types/config.d.ts +82 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +56 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +22 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/signature.d.ts +22 -0
- package/dist/types/signature.d.ts.map +1 -0
- package/dist/types/signature.js +3 -0
- package/dist/types/signature.js.map +1 -0
- package/dist/types/stream.d.ts +104 -0
- package/dist/types/stream.d.ts.map +1 -0
- package/dist/types/stream.js +3 -0
- package/dist/types/stream.js.map +1 -0
- package/dist/utils/confirmation.d.ts +12 -0
- package/dist/utils/confirmation.d.ts.map +1 -0
- package/dist/utils/confirmation.js +164 -0
- package/dist/utils/confirmation.js.map +1 -0
- package/dist/utils/errors.d.ts +40 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +113 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/formatter.d.ts +8 -0
- package/dist/utils/formatter.d.ts.map +1 -0
- package/dist/utils/formatter.js +93 -0
- package/dist/utils/formatter.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +20 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/signature.d.ts +9 -0
- package/dist/utils/signature.d.ts.map +1 -0
- package/dist/utils/signature.js +77 -0
- package/dist/utils/signature.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ChannelService = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const signature_1 = require("../utils/signature");
|
|
9
|
+
const errors_1 = require("../utils/errors");
|
|
10
|
+
class ChannelService {
|
|
11
|
+
constructor(authConfig, serviceConfig) {
|
|
12
|
+
this.authConfig = authConfig;
|
|
13
|
+
this.config = serviceConfig;
|
|
14
|
+
this.httpClient = this.createHttpClient();
|
|
15
|
+
}
|
|
16
|
+
async createChannel(request) {
|
|
17
|
+
try {
|
|
18
|
+
this.validateCreateRequest(request);
|
|
19
|
+
const timestamp = Date.now();
|
|
20
|
+
const signatureParams = {
|
|
21
|
+
appId: this.authConfig.appId,
|
|
22
|
+
timestamp,
|
|
23
|
+
...(this.authConfig.userId && { userId: this.authConfig.userId })
|
|
24
|
+
};
|
|
25
|
+
const signatureResult = (0, signature_1.generateSignature)(signatureParams, {
|
|
26
|
+
appSecret: this.authConfig.appSecret,
|
|
27
|
+
debug: this.config.debug
|
|
28
|
+
});
|
|
29
|
+
const url = '/live/v4/channel/create';
|
|
30
|
+
const params = {
|
|
31
|
+
appId: this.authConfig.appId,
|
|
32
|
+
timestamp: signatureResult.timestamp,
|
|
33
|
+
sign: signatureResult.signature,
|
|
34
|
+
...(this.authConfig.userId && { userId: this.authConfig.userId })
|
|
35
|
+
};
|
|
36
|
+
if (this.config.debug) {
|
|
37
|
+
console.log('[ChannelService] Creating channel with request:', request);
|
|
38
|
+
console.log('[ChannelService] API URL:', `${this.config.baseUrl}${url}`);
|
|
39
|
+
console.log('[ChannelService] Auth params:', params);
|
|
40
|
+
}
|
|
41
|
+
const response = await this.httpClient.post(url, request, {
|
|
42
|
+
params
|
|
43
|
+
});
|
|
44
|
+
return this.transformToChannelModel(response.data, request);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (error instanceof errors_1.PolyVError) {
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
51
|
+
const apiError = this.transformAxiosError(error);
|
|
52
|
+
throw apiError;
|
|
53
|
+
}
|
|
54
|
+
throw new errors_1.PolyVError('Failed to create channel due to unexpected error', 'CHANNEL_CREATE_UNEXPECTED_ERROR', 500, {
|
|
55
|
+
originalError: error instanceof Error ? error.message : String(error),
|
|
56
|
+
request: this.sanitizeRequest(request)
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async listChannels(request = {}) {
|
|
61
|
+
try {
|
|
62
|
+
this.validateListRequest(request);
|
|
63
|
+
const pageNumber = request.page ?? 1;
|
|
64
|
+
const pageSize = request.limit ?? 20;
|
|
65
|
+
const timestamp = Date.now();
|
|
66
|
+
const signatureParams = {
|
|
67
|
+
appId: this.authConfig.appId,
|
|
68
|
+
timestamp,
|
|
69
|
+
pageNumber,
|
|
70
|
+
pageSize,
|
|
71
|
+
...(this.authConfig.userId && { userId: this.authConfig.userId })
|
|
72
|
+
};
|
|
73
|
+
if (request.categoryId) {
|
|
74
|
+
signatureParams.categoryId = request.categoryId;
|
|
75
|
+
}
|
|
76
|
+
if (request.keyword) {
|
|
77
|
+
signatureParams.keyword = request.keyword;
|
|
78
|
+
}
|
|
79
|
+
const signatureResult = (0, signature_1.generateSignature)(signatureParams, {
|
|
80
|
+
appSecret: this.authConfig.appSecret,
|
|
81
|
+
debug: this.config.debug
|
|
82
|
+
});
|
|
83
|
+
const url = '/live/v4/channel/detail/list';
|
|
84
|
+
const params = {
|
|
85
|
+
appId: this.authConfig.appId,
|
|
86
|
+
timestamp: signatureResult.timestamp,
|
|
87
|
+
sign: signatureResult.signature,
|
|
88
|
+
pageNumber,
|
|
89
|
+
pageSize,
|
|
90
|
+
...(this.authConfig.userId && { userId: this.authConfig.userId })
|
|
91
|
+
};
|
|
92
|
+
if (request.categoryId) {
|
|
93
|
+
params.categoryId = request.categoryId;
|
|
94
|
+
}
|
|
95
|
+
if (request.keyword) {
|
|
96
|
+
params.keyword = request.keyword;
|
|
97
|
+
}
|
|
98
|
+
if (this.config.debug) {
|
|
99
|
+
console.log('[ChannelService] Listing channels with request:', request);
|
|
100
|
+
console.log('[ChannelService] API URL:', `${this.config.baseUrl}${url}`);
|
|
101
|
+
console.log('[ChannelService] Auth params:', params);
|
|
102
|
+
}
|
|
103
|
+
const response = await this.httpClient.get(url, {
|
|
104
|
+
params
|
|
105
|
+
});
|
|
106
|
+
if (!response.data || response.data.code !== 200) {
|
|
107
|
+
const errorMessage = response.data?.error?.desc || 'Unknown API error';
|
|
108
|
+
throw new errors_1.PolyVAPIError(`Failed to list channels: ${errorMessage}`, 'CHANNEL_LIST_API_ERROR', response.data?.code || 500, {
|
|
109
|
+
polyvCode: response.data?.error?.code,
|
|
110
|
+
polyvMessage: errorMessage
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (!response.data.data?.contents || response.data.data.contents.length === 0) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
const channelDetails = response.data.data.contents.map((channel) => ({
|
|
117
|
+
channelId: String(channel.channelId),
|
|
118
|
+
name: channel.name,
|
|
119
|
+
status: channel.watchStatus,
|
|
120
|
+
createdAt: new Date(channel.startTime || Date.now()),
|
|
121
|
+
scene: channel.newScene || channel.scene,
|
|
122
|
+
template: channel.template,
|
|
123
|
+
description: channel.content || '',
|
|
124
|
+
...(channel.maxViewer && channel.maxViewer > 0 && { maxViewers: channel.maxViewer })
|
|
125
|
+
}));
|
|
126
|
+
return channelDetails;
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (error instanceof errors_1.PolyVError) {
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
133
|
+
const apiError = this.transformAxiosError(error);
|
|
134
|
+
throw apiError;
|
|
135
|
+
}
|
|
136
|
+
throw new errors_1.PolyVError('Failed to list channels due to unexpected error', 'CHANNEL_LIST_UNEXPECTED_ERROR', 500, {
|
|
137
|
+
originalError: error instanceof Error ? error.message : String(error),
|
|
138
|
+
request: this.sanitizeRequest(request)
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async getChannelDetail(request) {
|
|
143
|
+
try {
|
|
144
|
+
this.validateChannelDetailRequest(request);
|
|
145
|
+
const timestamp = Date.now();
|
|
146
|
+
const signatureParams = {
|
|
147
|
+
appId: this.authConfig.appId,
|
|
148
|
+
timestamp,
|
|
149
|
+
channelId: request.channelId,
|
|
150
|
+
...(this.authConfig.userId && { userId: this.authConfig.userId })
|
|
151
|
+
};
|
|
152
|
+
const signatureResult = (0, signature_1.generateSignature)(signatureParams, {
|
|
153
|
+
appSecret: this.authConfig.appSecret,
|
|
154
|
+
debug: this.config.debug
|
|
155
|
+
});
|
|
156
|
+
const url = '/live/v4/channel/basic/get';
|
|
157
|
+
const params = {
|
|
158
|
+
appId: this.authConfig.appId,
|
|
159
|
+
timestamp: signatureResult.timestamp,
|
|
160
|
+
sign: signatureResult.signature,
|
|
161
|
+
channelId: request.channelId,
|
|
162
|
+
...(this.authConfig.userId && { userId: this.authConfig.userId })
|
|
163
|
+
};
|
|
164
|
+
if (this.config.debug) {
|
|
165
|
+
console.log('[ChannelService] Getting channel detail with request:', request);
|
|
166
|
+
console.log('[ChannelService] API URL:', `${this.config.baseUrl}${url}`);
|
|
167
|
+
console.log('[ChannelService] Auth params:', params);
|
|
168
|
+
}
|
|
169
|
+
const response = await this.httpClient.get(url, {
|
|
170
|
+
params
|
|
171
|
+
});
|
|
172
|
+
if (!response.data || response.data.code !== 200) {
|
|
173
|
+
const errorMessage = response.data?.error?.desc || 'Unknown API error';
|
|
174
|
+
throw new errors_1.PolyVAPIError(`Failed to get channel detail: ${errorMessage}`, 'CHANNEL_DETAIL_API_ERROR', response.data?.code || 500, {
|
|
175
|
+
polyvCode: response.data?.error?.code,
|
|
176
|
+
polyvMessage: errorMessage,
|
|
177
|
+
channelId: request.channelId
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (!response.data.data) {
|
|
181
|
+
throw new errors_1.PolyVAPIError('Invalid API response: missing channel data', 'MISSING_CHANNEL_DATA', 500, { response: response.data, channelId: request.channelId });
|
|
182
|
+
}
|
|
183
|
+
return response.data.data;
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
if (error instanceof errors_1.PolyVError) {
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
190
|
+
const apiError = this.transformAxiosError(error);
|
|
191
|
+
throw apiError;
|
|
192
|
+
}
|
|
193
|
+
throw new errors_1.PolyVError('Failed to get channel detail due to unexpected error', 'CHANNEL_DETAIL_UNEXPECTED_ERROR', 500, {
|
|
194
|
+
originalError: error instanceof Error ? error.message : String(error),
|
|
195
|
+
request: this.sanitizeRequest(request)
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
async updateChannel(request) {
|
|
200
|
+
try {
|
|
201
|
+
this.validateChannelUpdateRequest(request);
|
|
202
|
+
const timestamp = Date.now();
|
|
203
|
+
const signatureParams = {
|
|
204
|
+
appId: this.authConfig.appId,
|
|
205
|
+
timestamp,
|
|
206
|
+
channelId: request.channelId,
|
|
207
|
+
...(this.authConfig.userId && { userId: this.authConfig.userId })
|
|
208
|
+
};
|
|
209
|
+
const signatureResult = (0, signature_1.generateSignature)(signatureParams, {
|
|
210
|
+
appSecret: this.authConfig.appSecret,
|
|
211
|
+
debug: this.config.debug
|
|
212
|
+
});
|
|
213
|
+
const url = '/live/v3/channel/basic/update';
|
|
214
|
+
const params = {
|
|
215
|
+
appId: this.authConfig.appId,
|
|
216
|
+
timestamp: signatureResult.timestamp,
|
|
217
|
+
sign: signatureResult.signature,
|
|
218
|
+
channelId: request.channelId,
|
|
219
|
+
...(this.authConfig.userId && { userId: this.authConfig.userId })
|
|
220
|
+
};
|
|
221
|
+
const requestBody = {};
|
|
222
|
+
if (request.basicSetting) {
|
|
223
|
+
requestBody.basicSetting = request.basicSetting;
|
|
224
|
+
}
|
|
225
|
+
if (request.authSettings) {
|
|
226
|
+
requestBody.authSettings = request.authSettings;
|
|
227
|
+
}
|
|
228
|
+
if (this.config.debug) {
|
|
229
|
+
console.log('[ChannelService] Updating channel with request:', request);
|
|
230
|
+
console.log('[ChannelService] API URL:', `${this.config.baseUrl}${url}`);
|
|
231
|
+
console.log('[ChannelService] Auth params:', params);
|
|
232
|
+
console.log('[ChannelService] Request body:', this.sanitizeRequest(requestBody));
|
|
233
|
+
}
|
|
234
|
+
const response = await this.httpClient.post(url, requestBody, {
|
|
235
|
+
params
|
|
236
|
+
});
|
|
237
|
+
if (!response.data || response.data.code !== 200) {
|
|
238
|
+
const errorMessage = response.data?.error?.desc || 'Unknown API error';
|
|
239
|
+
throw new errors_1.PolyVAPIError(`Failed to update channel: ${errorMessage}`, 'CHANNEL_UPDATE_API_ERROR', response.data?.code || 500, {
|
|
240
|
+
polyvCode: response.data?.error?.code,
|
|
241
|
+
polyvMessage: errorMessage,
|
|
242
|
+
channelId: request.channelId
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return response.data;
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
if (error instanceof errors_1.PolyVError) {
|
|
249
|
+
throw error;
|
|
250
|
+
}
|
|
251
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
252
|
+
const apiError = this.transformAxiosError(error);
|
|
253
|
+
throw apiError;
|
|
254
|
+
}
|
|
255
|
+
throw new errors_1.PolyVError('Failed to update channel due to unexpected error', 'CHANNEL_UPDATE_UNEXPECTED_ERROR', 500, {
|
|
256
|
+
originalError: error instanceof Error ? error.message : String(error),
|
|
257
|
+
request: this.sanitizeRequest(request)
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async deleteChannel(channelId) {
|
|
262
|
+
try {
|
|
263
|
+
this.validateChannelId(channelId);
|
|
264
|
+
const deleteRequest = {
|
|
265
|
+
channelIds: [channelId]
|
|
266
|
+
};
|
|
267
|
+
const response = await this.batchDeleteChannels(deleteRequest);
|
|
268
|
+
if (this.config.debug) {
|
|
269
|
+
console.log('[ChannelService] Single channel delete completed:', {
|
|
270
|
+
channelId,
|
|
271
|
+
success: response.data === true
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
return response;
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
if (error instanceof errors_1.PolyVError) {
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
throw new errors_1.PolyVError('Failed to delete channel due to unexpected error', 'CHANNEL_DELETE_UNEXPECTED_ERROR', 500, {
|
|
281
|
+
originalError: error instanceof Error ? error.message : String(error),
|
|
282
|
+
channelId
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async batchDeleteChannels(request) {
|
|
287
|
+
try {
|
|
288
|
+
this.validateBatchDeleteRequest(request);
|
|
289
|
+
const timestamp = Date.now();
|
|
290
|
+
const signatureParams = {
|
|
291
|
+
appId: this.authConfig.appId,
|
|
292
|
+
timestamp,
|
|
293
|
+
...(this.authConfig.userId && { userId: this.authConfig.userId })
|
|
294
|
+
};
|
|
295
|
+
const signatureResult = (0, signature_1.generateSignature)(signatureParams, {
|
|
296
|
+
appSecret: this.authConfig.appSecret,
|
|
297
|
+
debug: this.config.debug
|
|
298
|
+
});
|
|
299
|
+
const url = '/live/v3/channel/basic/batch-delete';
|
|
300
|
+
const params = {
|
|
301
|
+
appId: this.authConfig.appId,
|
|
302
|
+
timestamp: signatureResult.timestamp,
|
|
303
|
+
sign: signatureResult.signature,
|
|
304
|
+
...(this.authConfig.userId && { userId: this.authConfig.userId })
|
|
305
|
+
};
|
|
306
|
+
const requestBody = {
|
|
307
|
+
channelIds: request.channelIds
|
|
308
|
+
};
|
|
309
|
+
if (this.config.debug) {
|
|
310
|
+
console.log('[ChannelService] Batch deleting channels with request:', request);
|
|
311
|
+
console.log('[ChannelService] API URL:', `${this.config.baseUrl}${url}`);
|
|
312
|
+
console.log('[ChannelService] Auth params:', params);
|
|
313
|
+
console.log('[ChannelService] Request body:', requestBody);
|
|
314
|
+
}
|
|
315
|
+
const response = await this.httpClient.post(url, requestBody, {
|
|
316
|
+
params,
|
|
317
|
+
headers: {
|
|
318
|
+
'Content-Type': 'application/json'
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
if (!response.data || response.data.code !== 200) {
|
|
322
|
+
const errorMessage = response.data?.message || 'Unknown API error';
|
|
323
|
+
throw new errors_1.PolyVAPIError(`Failed to delete channels: ${errorMessage}`, 'CHANNEL_DELETE_API_ERROR', response.data?.code || 500, {
|
|
324
|
+
polyvMessage: errorMessage,
|
|
325
|
+
channelIds: request.channelIds
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
return response.data;
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
if (error instanceof errors_1.PolyVError) {
|
|
332
|
+
throw error;
|
|
333
|
+
}
|
|
334
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
335
|
+
const apiError = this.transformAxiosError(error);
|
|
336
|
+
throw apiError;
|
|
337
|
+
}
|
|
338
|
+
throw new errors_1.PolyVError('Failed to delete channels due to unexpected error', 'CHANNEL_DELETE_UNEXPECTED_ERROR', 500, {
|
|
339
|
+
originalError: error instanceof Error ? error.message : String(error),
|
|
340
|
+
request: this.sanitizeRequest(request)
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
validateListRequest(request) {
|
|
345
|
+
const errors = [];
|
|
346
|
+
if (request.page !== undefined) {
|
|
347
|
+
if (typeof request.page !== 'number' || !Number.isInteger(request.page) || request.page < 1) {
|
|
348
|
+
errors.push('page must be a positive integer (minimum 1)');
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (request.limit !== undefined) {
|
|
352
|
+
if (typeof request.limit !== 'number' || !Number.isInteger(request.limit) || request.limit < 1 || request.limit > 100) {
|
|
353
|
+
errors.push('limit must be an integer between 1 and 100');
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (request.categoryId !== undefined && (typeof request.categoryId !== 'string' || request.categoryId.trim().length === 0)) {
|
|
357
|
+
errors.push('categoryId must be a non-empty string');
|
|
358
|
+
}
|
|
359
|
+
if (request.keyword !== undefined && (typeof request.keyword !== 'string' || request.keyword.trim().length === 0)) {
|
|
360
|
+
errors.push('keyword must be a non-empty string');
|
|
361
|
+
}
|
|
362
|
+
if (request.labelId !== undefined && (typeof request.labelId !== 'string' || request.labelId.trim().length === 0)) {
|
|
363
|
+
errors.push('labelId must be a non-empty string');
|
|
364
|
+
}
|
|
365
|
+
if (errors.length > 0) {
|
|
366
|
+
throw new errors_1.PolyVValidationError(`Channel list request validation failed: ${errors.join(', ')}`, 'request', request, 'validation_failed');
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
validateChannelDetailRequest(request) {
|
|
370
|
+
const errors = [];
|
|
371
|
+
if (!request.channelId) {
|
|
372
|
+
errors.push('channelId is required');
|
|
373
|
+
}
|
|
374
|
+
else if (typeof request.channelId !== 'string') {
|
|
375
|
+
errors.push('channelId must be a string');
|
|
376
|
+
}
|
|
377
|
+
else if (request.channelId.trim().length === 0) {
|
|
378
|
+
errors.push('channelId cannot be empty');
|
|
379
|
+
}
|
|
380
|
+
if (errors.length > 0) {
|
|
381
|
+
throw new errors_1.PolyVValidationError(`Channel detail request validation failed: ${errors.join(', ')}`, 'request', request, 'validation_failed');
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
validateChannelUpdateRequest(request) {
|
|
385
|
+
const errors = [];
|
|
386
|
+
if (!request.channelId) {
|
|
387
|
+
errors.push('channelId is required');
|
|
388
|
+
}
|
|
389
|
+
else if (typeof request.channelId !== 'string') {
|
|
390
|
+
errors.push('channelId must be a string');
|
|
391
|
+
}
|
|
392
|
+
else if (request.channelId.trim().length === 0) {
|
|
393
|
+
errors.push('channelId cannot be empty');
|
|
394
|
+
}
|
|
395
|
+
if (!request.basicSetting && !request.authSettings) {
|
|
396
|
+
errors.push('at least one update field (basicSetting or authSettings) must be provided');
|
|
397
|
+
}
|
|
398
|
+
if (request.basicSetting) {
|
|
399
|
+
const basicSetting = request.basicSetting;
|
|
400
|
+
if (basicSetting.name !== undefined) {
|
|
401
|
+
if (typeof basicSetting.name !== 'string') {
|
|
402
|
+
errors.push('basicSetting.name must be a string');
|
|
403
|
+
}
|
|
404
|
+
else if (basicSetting.name.length > 100) {
|
|
405
|
+
errors.push('basicSetting.name cannot exceed 100 characters');
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (basicSetting.channelPasswd !== undefined) {
|
|
409
|
+
if (typeof basicSetting.channelPasswd !== 'string') {
|
|
410
|
+
errors.push('basicSetting.channelPasswd must be a string');
|
|
411
|
+
}
|
|
412
|
+
else if (basicSetting.channelPasswd.length < 6 || basicSetting.channelPasswd.length > 16) {
|
|
413
|
+
errors.push('basicSetting.channelPasswd must be 6-16 characters long');
|
|
414
|
+
}
|
|
415
|
+
else if (!/^[a-zA-Z0-9]+$/.test(basicSetting.channelPasswd)) {
|
|
416
|
+
errors.push('basicSetting.channelPasswd must contain only alphanumeric characters');
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (basicSetting.publisher !== undefined && typeof basicSetting.publisher !== 'string') {
|
|
420
|
+
errors.push('basicSetting.publisher must be a string');
|
|
421
|
+
}
|
|
422
|
+
if (basicSetting.desc !== undefined) {
|
|
423
|
+
if (typeof basicSetting.desc !== 'string') {
|
|
424
|
+
errors.push('basicSetting.desc must be a string');
|
|
425
|
+
}
|
|
426
|
+
else if (basicSetting.desc.length > 500) {
|
|
427
|
+
errors.push('basicSetting.desc cannot exceed 500 characters');
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (basicSetting.startTime !== undefined) {
|
|
431
|
+
if (typeof basicSetting.startTime !== 'number' || basicSetting.startTime < 0) {
|
|
432
|
+
errors.push('basicSetting.startTime must be a non-negative timestamp');
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
if (basicSetting.endTime !== undefined) {
|
|
436
|
+
if (typeof basicSetting.endTime !== 'number' || basicSetting.endTime < 0) {
|
|
437
|
+
errors.push('basicSetting.endTime must be a non-negative timestamp');
|
|
438
|
+
}
|
|
439
|
+
if (basicSetting.startTime !== undefined && basicSetting.endTime <= basicSetting.startTime) {
|
|
440
|
+
errors.push('basicSetting.endTime must be greater than startTime');
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
if (basicSetting.pageView !== undefined) {
|
|
444
|
+
if (typeof basicSetting.pageView !== 'number' || basicSetting.pageView < 0) {
|
|
445
|
+
errors.push('basicSetting.pageView must be a non-negative number');
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (basicSetting.likes !== undefined) {
|
|
449
|
+
if (typeof basicSetting.likes !== 'number' || basicSetting.likes < 0) {
|
|
450
|
+
errors.push('basicSetting.likes must be a non-negative number');
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (basicSetting.maxViewer !== undefined) {
|
|
454
|
+
if (typeof basicSetting.maxViewer !== 'number' || basicSetting.maxViewer <= 0) {
|
|
455
|
+
errors.push('basicSetting.maxViewer must be a positive number');
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (basicSetting.maxViewerRestrict !== undefined && !['Y', 'N'].includes(basicSetting.maxViewerRestrict)) {
|
|
459
|
+
errors.push('basicSetting.maxViewerRestrict must be "Y" or "N"');
|
|
460
|
+
}
|
|
461
|
+
if (basicSetting.closeDanmu !== undefined && !['Y', 'N'].includes(basicSetting.closeDanmu)) {
|
|
462
|
+
errors.push('basicSetting.closeDanmu must be "Y" or "N"');
|
|
463
|
+
}
|
|
464
|
+
if (basicSetting.coverImg !== undefined && typeof basicSetting.coverImg !== 'string') {
|
|
465
|
+
errors.push('basicSetting.coverImg must be a string');
|
|
466
|
+
}
|
|
467
|
+
if (basicSetting.splashImg !== undefined && typeof basicSetting.splashImg !== 'string') {
|
|
468
|
+
errors.push('basicSetting.splashImg must be a string');
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
if (request.authSettings) {
|
|
472
|
+
if (!Array.isArray(request.authSettings)) {
|
|
473
|
+
errors.push('authSettings must be an array');
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (errors.length > 0) {
|
|
477
|
+
throw new errors_1.PolyVValidationError(`Channel update request validation failed: ${errors.join(', ')}`, 'request', request, 'validation_failed');
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
validateChannelId(channelId) {
|
|
481
|
+
const errors = [];
|
|
482
|
+
if (!channelId) {
|
|
483
|
+
errors.push('channelId is required');
|
|
484
|
+
}
|
|
485
|
+
else if (typeof channelId !== 'string') {
|
|
486
|
+
errors.push('channelId must be a string');
|
|
487
|
+
}
|
|
488
|
+
else if (channelId.trim().length === 0) {
|
|
489
|
+
errors.push('channelId cannot be empty');
|
|
490
|
+
}
|
|
491
|
+
if (errors.length > 0) {
|
|
492
|
+
throw new errors_1.PolyVValidationError(`Channel ID validation failed: ${errors.join(', ')}`, 'channelId', channelId, 'validation_failed');
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
validateBatchDeleteRequest(request) {
|
|
496
|
+
const errors = [];
|
|
497
|
+
if (!request.channelIds) {
|
|
498
|
+
errors.push('channelIds is required');
|
|
499
|
+
}
|
|
500
|
+
else if (!Array.isArray(request.channelIds)) {
|
|
501
|
+
errors.push('channelIds must be an array');
|
|
502
|
+
}
|
|
503
|
+
else if (request.channelIds.length === 0) {
|
|
504
|
+
errors.push('channelIds cannot be empty');
|
|
505
|
+
}
|
|
506
|
+
else if (request.channelIds.length > 100) {
|
|
507
|
+
errors.push('channelIds cannot exceed 100 channels per batch');
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
for (let i = 0; i < request.channelIds.length; i++) {
|
|
511
|
+
const channelId = request.channelIds[i];
|
|
512
|
+
if (typeof channelId !== 'string') {
|
|
513
|
+
errors.push(`channelIds[${i}] must be a string`);
|
|
514
|
+
}
|
|
515
|
+
else if (channelId.trim().length === 0) {
|
|
516
|
+
errors.push(`channelIds[${i}] cannot be empty`);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (errors.length > 0) {
|
|
521
|
+
throw new errors_1.PolyVValidationError(`Channel batch delete request validation failed: ${errors.join(', ')}`, 'request', request, 'validation_failed');
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
createHttpClient() {
|
|
525
|
+
const client = axios_1.default.create({
|
|
526
|
+
baseURL: this.config.baseUrl,
|
|
527
|
+
timeout: this.config.timeout,
|
|
528
|
+
headers: {
|
|
529
|
+
'Content-Type': 'application/json',
|
|
530
|
+
'User-Agent': 'PolyV-CLI/2.1.0'
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
if (this.config.debug) {
|
|
534
|
+
client.interceptors.request.use((config) => {
|
|
535
|
+
console.log('[ChannelService] HTTP Request:', {
|
|
536
|
+
method: config.method?.toUpperCase(),
|
|
537
|
+
url: config.url,
|
|
538
|
+
params: config.params,
|
|
539
|
+
data: config.data ? this.sanitizeRequest(config.data) : undefined
|
|
540
|
+
});
|
|
541
|
+
return config;
|
|
542
|
+
}, (error) => {
|
|
543
|
+
console.error('[ChannelService] Request error:', error);
|
|
544
|
+
return Promise.reject(error);
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
client.interceptors.response.use((response) => {
|
|
548
|
+
if (this.config.debug) {
|
|
549
|
+
console.log('[ChannelService] HTTP Response:', {
|
|
550
|
+
status: response.status,
|
|
551
|
+
statusText: response.statusText,
|
|
552
|
+
data: response.data
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
return response;
|
|
556
|
+
}, (error) => {
|
|
557
|
+
if (this.config.debug) {
|
|
558
|
+
console.error('[ChannelService] Response error:', {
|
|
559
|
+
status: error.response?.status,
|
|
560
|
+
statusText: error.response?.statusText,
|
|
561
|
+
data: error.response?.data
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
return Promise.reject(error);
|
|
565
|
+
});
|
|
566
|
+
return client;
|
|
567
|
+
}
|
|
568
|
+
validateCreateRequest(request) {
|
|
569
|
+
const errors = [];
|
|
570
|
+
if (!request.name || typeof request.name !== 'string') {
|
|
571
|
+
errors.push('Channel name is required and must be a string');
|
|
572
|
+
}
|
|
573
|
+
else if (request.name.length === 0) {
|
|
574
|
+
errors.push('Channel name cannot be empty');
|
|
575
|
+
}
|
|
576
|
+
else if (request.name.length > 100) {
|
|
577
|
+
errors.push('Channel name cannot exceed 100 characters');
|
|
578
|
+
}
|
|
579
|
+
if (!request.newScene || typeof request.newScene !== 'string') {
|
|
580
|
+
errors.push('newScene is required and must be a string');
|
|
581
|
+
}
|
|
582
|
+
else if (!['topclass', 'cloudclass', 'telecast', 'akt'].includes(request.newScene)) {
|
|
583
|
+
errors.push('newScene must be one of: topclass, cloudclass, telecast, akt');
|
|
584
|
+
}
|
|
585
|
+
if (!request.template || typeof request.template !== 'string') {
|
|
586
|
+
errors.push('template is required and must be a string');
|
|
587
|
+
}
|
|
588
|
+
else if (!['ppt', 'video'].includes(request.template)) {
|
|
589
|
+
errors.push('template must be one of: ppt, video');
|
|
590
|
+
}
|
|
591
|
+
if (request.channelPasswd !== undefined) {
|
|
592
|
+
if (typeof request.channelPasswd !== 'string') {
|
|
593
|
+
errors.push('channelPasswd must be a string');
|
|
594
|
+
}
|
|
595
|
+
else if (request.channelPasswd.length < 6 || request.channelPasswd.length > 16) {
|
|
596
|
+
errors.push('channelPasswd must be 6-16 characters long');
|
|
597
|
+
}
|
|
598
|
+
else if (!/^[a-zA-Z0-9]+$/.test(request.channelPasswd)) {
|
|
599
|
+
errors.push('channelPasswd must contain only alphanumeric characters');
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (request.linkMicLimit !== undefined) {
|
|
603
|
+
if (typeof request.linkMicLimit !== 'number' || request.linkMicLimit < 0) {
|
|
604
|
+
errors.push('linkMicLimit must be a non-negative number');
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
if (request.startTime !== undefined) {
|
|
608
|
+
if (typeof request.startTime !== 'number' || request.startTime < 0) {
|
|
609
|
+
errors.push('startTime must be a non-negative timestamp');
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
if (request.endTime !== undefined) {
|
|
613
|
+
if (typeof request.endTime !== 'number' || request.endTime < 0) {
|
|
614
|
+
errors.push('endTime must be a non-negative timestamp');
|
|
615
|
+
}
|
|
616
|
+
if (request.startTime !== undefined && request.endTime <= request.startTime) {
|
|
617
|
+
errors.push('endTime must be greater than startTime');
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
if (errors.length > 0) {
|
|
621
|
+
throw new errors_1.PolyVValidationError(`Channel creation request validation failed: ${errors.join(', ')}`, 'request', request, 'validation_failed');
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
transformToChannelModel(response, originalRequest) {
|
|
625
|
+
if (!response.data || typeof response.data !== 'object') {
|
|
626
|
+
throw new errors_1.PolyVAPIError('Invalid API response: missing data field', 'INVALID_RESPONSE_FORMAT', 500, { response });
|
|
627
|
+
}
|
|
628
|
+
if (!response.data.channelId) {
|
|
629
|
+
throw new errors_1.PolyVAPIError('Invalid API response: missing channelId', 'MISSING_CHANNEL_ID', 500, { response });
|
|
630
|
+
}
|
|
631
|
+
return {
|
|
632
|
+
channelId: response.data.channelId,
|
|
633
|
+
name: originalRequest.name,
|
|
634
|
+
userId: response.data.userId || this.authConfig.userId || '',
|
|
635
|
+
channelPasswd: response.data.channelPasswd || '',
|
|
636
|
+
newScene: originalRequest.newScene,
|
|
637
|
+
template: originalRequest.template,
|
|
638
|
+
status: 'waiting',
|
|
639
|
+
createdAt: new Date()
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
transformAxiosError(error) {
|
|
643
|
+
if (error.response) {
|
|
644
|
+
const status = error.response.status;
|
|
645
|
+
const data = error.response.data;
|
|
646
|
+
if (data && typeof data === 'object' && data.code && data.message) {
|
|
647
|
+
return new errors_1.PolyVAPIError(`PolyV API error: ${data.message}`, 'POLYV_API_ERROR', status, {
|
|
648
|
+
polyvCode: data.code,
|
|
649
|
+
polyvMessage: data.message,
|
|
650
|
+
polyvData: data.data
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
return new errors_1.PolyVAPIError(`HTTP ${status} error: ${error.response.statusText}`, 'HTTP_ERROR', status, { responseData: data });
|
|
654
|
+
}
|
|
655
|
+
if (error.request) {
|
|
656
|
+
return new errors_1.PolyVAPIError('Network error: Unable to reach PolyV API', 'NETWORK_ERROR', 0, { request: error.config });
|
|
657
|
+
}
|
|
658
|
+
return new errors_1.PolyVAPIError(`Request setup error: ${error.message}`, 'REQUEST_ERROR', 0, { originalError: error.message });
|
|
659
|
+
}
|
|
660
|
+
sanitizeRequest(request) {
|
|
661
|
+
if (!request || typeof request !== 'object') {
|
|
662
|
+
return request;
|
|
663
|
+
}
|
|
664
|
+
const sanitized = { ...request };
|
|
665
|
+
if (sanitized.channelPasswd) {
|
|
666
|
+
sanitized.channelPasswd = '***masked***';
|
|
667
|
+
}
|
|
668
|
+
return sanitized;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
exports.ChannelService = ChannelService;
|
|
672
|
+
//# sourceMappingURL=channel.service.js.map
|