polyv-live-api-sdk 1.0.2 → 1.0.3

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/dist/index.js CHANGED
@@ -424,6 +424,117 @@ async function collectAll(fetcher, options = {}) {
424
424
  return allItems;
425
425
  }
426
426
 
427
+ // src/utils/date-validation.ts
428
+ var MAX_DATE_RANGE_DAYS = 60;
429
+ var MAX_TIME_RANGE_MONTHS = 3;
430
+ var MAX_AUDIENCE_TIME_RANGE_DAYS = 90;
431
+ var DATE_FORMAT_REGEX = /^\d{4}-\d{2}-\d{2}$/;
432
+ function isValidDateFormat(dateStr) {
433
+ if (!dateStr || typeof dateStr !== "string") {
434
+ return false;
435
+ }
436
+ if (!DATE_FORMAT_REGEX.test(dateStr)) {
437
+ return false;
438
+ }
439
+ const date = new Date(dateStr);
440
+ if (isNaN(date.getTime())) {
441
+ return false;
442
+ }
443
+ const [year, month, day] = dateStr.split("-").map(Number);
444
+ return date.getFullYear() === year && date.getMonth() + 1 === month && date.getDate() === day;
445
+ }
446
+ function isStartDateBeforeEndDate(startDay, endDay) {
447
+ const startDate = new Date(startDay);
448
+ const endDate = new Date(endDay);
449
+ return startDate <= endDate;
450
+ }
451
+ function isStartTimeBeforeEndTime(startTime, endTime) {
452
+ return startTime <= endTime;
453
+ }
454
+ function isValidTimestamp(value) {
455
+ if (typeof value !== "number" || !Number.isFinite(value)) {
456
+ return false;
457
+ }
458
+ return value > 9466848e5;
459
+ }
460
+ function validateDateRange(startDay, endDay, maxDays = MAX_DATE_RANGE_DAYS) {
461
+ if (!isStartDateBeforeEndDate(startDay, endDay)) {
462
+ return {
463
+ valid: false,
464
+ error: "startDay must be before or equal to endDay"
465
+ };
466
+ }
467
+ const startDate = new Date(startDay);
468
+ const endDate = new Date(endDay);
469
+ const diffTime = endDate.getTime() - startDate.getTime();
470
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
471
+ if (diffDays > maxDays) {
472
+ return {
473
+ valid: false,
474
+ error: `Date range cannot exceed ${maxDays} days`,
475
+ daysDiff: diffDays
476
+ };
477
+ }
478
+ return { valid: true, daysDiff: diffDays };
479
+ }
480
+ function validateTimestampRange(startTime, endTime, maxMonths = MAX_TIME_RANGE_MONTHS) {
481
+ if (!isStartTimeBeforeEndTime(startTime, endTime)) {
482
+ return {
483
+ valid: false,
484
+ error: "startTime must be before or equal to endTime"
485
+ };
486
+ }
487
+ const diffTime = endTime - startTime;
488
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
489
+ const maxDays = maxMonths * 31;
490
+ if (diffDays > maxDays) {
491
+ return {
492
+ valid: false,
493
+ error: `Time range cannot exceed ${maxMonths} months`,
494
+ daysDiff: diffDays
495
+ };
496
+ }
497
+ return { valid: true, daysDiff: diffDays };
498
+ }
499
+ function validate90DayTimestampRange(startTime, endTime) {
500
+ if (!isStartTimeBeforeEndTime(startTime, endTime)) {
501
+ return {
502
+ valid: false,
503
+ error: "startTime must be before or equal to endTime"
504
+ };
505
+ }
506
+ const diffTime = endTime - startTime;
507
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
508
+ if (diffDays > MAX_AUDIENCE_TIME_RANGE_DAYS) {
509
+ return {
510
+ valid: false,
511
+ error: `Time range cannot exceed ${MAX_AUDIENCE_TIME_RANGE_DAYS} days`,
512
+ daysDiff: diffDays
513
+ };
514
+ }
515
+ return { valid: true, daysDiff: diffDays };
516
+ }
517
+ function validateConcurrencyDateRange(startDate, endDate, maxDays = MAX_DATE_RANGE_DAYS) {
518
+ if (!isStartDateBeforeEndDate(startDate, endDate)) {
519
+ return {
520
+ valid: false,
521
+ error: "startDate must be before or equal to endDate"
522
+ };
523
+ }
524
+ const start = new Date(startDate);
525
+ const end = new Date(endDate);
526
+ const diffTime = end.getTime() - start.getTime();
527
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
528
+ if (diffDays > maxDays) {
529
+ return {
530
+ valid: false,
531
+ error: `Date range cannot exceed ${maxDays} days`,
532
+ daysDiff: diffDays
533
+ };
534
+ }
535
+ return { valid: true, daysDiff: diffDays };
536
+ }
537
+
427
538
  // src/services/channel.service.ts
428
539
  var ChannelService = class {
429
540
  client;
@@ -1839,17 +1950,21 @@ var ChannelService = class {
1839
1950
  * await channelService.setRecordDefault('ch123456', 'file123');
1840
1951
  * ```
1841
1952
  */
1842
- async setRecordDefault(channelId, fileId) {
1953
+ async setRecordDefault(channelId, fileId, listType) {
1843
1954
  if (!channelId || channelId.trim() === "") {
1844
1955
  throw PolyVValidationError.required("channelId");
1845
1956
  }
1846
1957
  if (!fileId || fileId.trim() === "") {
1847
1958
  throw PolyVValidationError.required("fileId");
1848
1959
  }
1960
+ const params = { channelId, fileId };
1961
+ if (listType) {
1962
+ params.listType = listType;
1963
+ }
1849
1964
  await this.client.httpClient.post(
1850
1965
  "/live/v3/channel/record/set-default",
1851
1966
  null,
1852
- { params: { channelId, fileId } }
1967
+ { params }
1853
1968
  );
1854
1969
  return true;
1855
1970
  }
@@ -1963,6 +2078,38 @@ var ChannelService = class {
1963
2078
  );
1964
2079
  return response;
1965
2080
  }
2081
+ /**
2082
+ * Set playback setting (Story 9.7)
2083
+ *
2084
+ * Sets the playback settings for a channel.
2085
+ * API: POST /live/v3/channel/playback/set-setting
2086
+ *
2087
+ * @param channelId - The channel ID
2088
+ * @param options - Playback setting options
2089
+ * @returns true if operation was successful
2090
+ * @throws PolyVValidationError if channelId is empty
2091
+ *
2092
+ * @example
2093
+ * ```typescript
2094
+ * await channelService.setPlaybackSetting('ch123456', {
2095
+ * playbackEnabled: 'Y',
2096
+ * type: 'single',
2097
+ * origin: 'playback',
2098
+ * });
2099
+ * ```
2100
+ */
2101
+ async setPlaybackSetting(channelId, options) {
2102
+ if (!channelId || channelId.trim() === "") {
2103
+ throw PolyVValidationError.required("channelId");
2104
+ }
2105
+ const params = { channelId, ...options };
2106
+ await this.client.httpClient.post(
2107
+ "/live/v3/channel/playback/set-setting",
2108
+ null,
2109
+ { params }
2110
+ );
2111
+ return true;
2112
+ }
1966
2113
  /**
1967
2114
  * Set playback sort
1968
2115
  *
@@ -2292,6 +2439,15 @@ var ChannelService = class {
2292
2439
  if (options.callbackUrl !== void 0) {
2293
2440
  params.callbackUrl = options.callbackUrl;
2294
2441
  }
2442
+ if (options.autoConvert !== void 0) {
2443
+ params.autoConvert = options.autoConvert;
2444
+ }
2445
+ if (options.mergeMp4 !== void 0) {
2446
+ params.mergeMp4 = options.mergeMp4;
2447
+ }
2448
+ if (options.orderByCustom !== void 0) {
2449
+ params.orderByCustom = options.orderByCustom;
2450
+ }
2295
2451
  await this.client.httpClient.post(
2296
2452
  "/live/v3/channel/record/merge-async",
2297
2453
  null,
@@ -4028,6 +4184,44 @@ var ChannelService = class {
4028
4184
  // ============================================
4029
4185
  // Product APIs (Story 8-2)
4030
4186
  // ============================================
4187
+ /**
4188
+ * List channel products
4189
+ *
4190
+ * Lists products in a channel with pagination support.
4191
+ *
4192
+ * @param params - Query parameters including channelId (required)
4193
+ * @returns Paginated product list
4194
+ * @throws PolyVValidationError if channelId is missing
4195
+ *
4196
+ * @example
4197
+ * ```typescript
4198
+ * const result = await channelService.listChannelProducts({
4199
+ * channelId: 'ch123456',
4200
+ * pageNumber: 1,
4201
+ * pageSize: 20,
4202
+ * });
4203
+ * console.log(result.contents);
4204
+ * ```
4205
+ */
4206
+ async listChannelProducts(params) {
4207
+ if (!params.channelId || params.channelId.trim() === "") {
4208
+ throw PolyVValidationError.required("channelId");
4209
+ }
4210
+ const queryParams = {
4211
+ channelId: params.channelId
4212
+ };
4213
+ if (params.pageNumber !== void 0) {
4214
+ queryParams.pageNumber = params.pageNumber;
4215
+ }
4216
+ if (params.pageSize !== void 0) {
4217
+ queryParams.pageSize = params.pageSize;
4218
+ }
4219
+ const response = await this.client.httpClient.get(
4220
+ "/live/v3/channel/product/list",
4221
+ { params: queryParams }
4222
+ );
4223
+ return response;
4224
+ }
4031
4225
  /**
4032
4226
  * Add channel product
4033
4227
  *
@@ -9392,6 +9586,112 @@ var PlayerService = class {
9392
9586
  }
9393
9587
  }
9394
9588
  }
9589
+ // ============================================
9590
+ // Channel Decorate APIs (Story 10.5)
9591
+ // ============================================
9592
+ /**
9593
+ * Get channel decorate settings
9594
+ * Query channel player decoration settings (watermark, warmup image, etc.)
9595
+ *
9596
+ * @param channelId - Channel ID
9597
+ * @returns Channel decorate settings
9598
+ *
9599
+ * @example
9600
+ * ```typescript
9601
+ * const decorate = await client.player.getChannelDecorate(123456);
9602
+ * console.log(decorate.player.watermarkEnabled);
9603
+ * ```
9604
+ */
9605
+ async getChannelDecorate(channelId) {
9606
+ this.validateChannelId(channelId);
9607
+ const response = await this.client.httpClient.get(
9608
+ "/live/v4/channel/decorate/get",
9609
+ { params: { channelId } }
9610
+ );
9611
+ return response;
9612
+ }
9613
+ /**
9614
+ * Update channel decorate settings
9615
+ * Update channel player decoration settings (watermark, warmup image, etc.)
9616
+ *
9617
+ * @param channelId - Channel ID
9618
+ * @param params - Channel decorate update parameters
9619
+ * @returns true on success
9620
+ *
9621
+ * @example
9622
+ * ```typescript
9623
+ * await client.player.updateChannelDecorate(123456, {
9624
+ * watermarkEnabled: 'Y',
9625
+ * iconUrl: 'http://example.com/logo.png',
9626
+ * iconPosition: 'br',
9627
+ * logoOpacity: 0.8,
9628
+ * });
9629
+ * ```
9630
+ */
9631
+ async updateChannelDecorate(channelId, params) {
9632
+ this.validateChannelId(channelId);
9633
+ if (params.iconPosition !== void 0) {
9634
+ this.validateLogoPosition(params.iconPosition);
9635
+ }
9636
+ if (params.logoOpacity !== void 0) {
9637
+ this.validateDecorateOpacity(params.logoOpacity);
9638
+ }
9639
+ if (params.watermarkEnabled !== void 0) {
9640
+ this.validateYNValue(params.watermarkEnabled, "watermarkEnabled");
9641
+ }
9642
+ if (params.warmUpEnabled !== void 0) {
9643
+ this.validateYNValue(params.warmUpEnabled, "warmUpEnabled");
9644
+ }
9645
+ const playerBody = {};
9646
+ if (params.watermarkEnabled !== void 0) {
9647
+ playerBody.watermarkEnabled = params.watermarkEnabled;
9648
+ }
9649
+ if (params.iconUrl !== void 0) {
9650
+ playerBody.iconUrl = params.iconUrl;
9651
+ }
9652
+ if (params.iconPosition !== void 0) {
9653
+ playerBody.iconPosition = params.iconPosition;
9654
+ }
9655
+ if (params.logoOpacity !== void 0) {
9656
+ playerBody.logoOpacity = params.logoOpacity;
9657
+ }
9658
+ if (params.iconLink !== void 0) {
9659
+ playerBody.iconLink = params.iconLink;
9660
+ }
9661
+ if (params.warmUpEnabled !== void 0) {
9662
+ playerBody.warmUpEnabled = params.warmUpEnabled;
9663
+ }
9664
+ if (params.warmUpImageUrl !== void 0) {
9665
+ playerBody.warmUpImageUrl = params.warmUpImageUrl;
9666
+ }
9667
+ if (params.coverJumpUrl !== void 0) {
9668
+ playerBody.coverJumpUrl = params.coverJumpUrl;
9669
+ }
9670
+ if (params.backgroundUrl !== void 0) {
9671
+ playerBody.backgroundUrl = params.backgroundUrl;
9672
+ }
9673
+ if (params.basePV !== void 0) {
9674
+ playerBody.basePV = params.basePV;
9675
+ }
9676
+ if (params.actualPV !== void 0) {
9677
+ playerBody.actualPV = params.actualPV;
9678
+ }
9679
+ const body = { player: playerBody };
9680
+ const response = await this.client.httpClient.post(
9681
+ "/live/v4/channel/decorate/update",
9682
+ body,
9683
+ { params: { channelId } }
9684
+ );
9685
+ return response;
9686
+ }
9687
+ /**
9688
+ * Validate decorate opacity (0-1)
9689
+ */
9690
+ validateDecorateOpacity(opacity) {
9691
+ if (typeof opacity !== "number" || opacity < 0 || opacity > 1) {
9692
+ throw new PolyVValidationError("logoOpacity must be a number between 0 and 1");
9693
+ }
9694
+ }
9395
9695
  };
9396
9696
 
9397
9697
  // src/services/other.service.ts
@@ -10853,7 +11153,9 @@ var V4ChannelService = class {
10853
11153
  * @returns Sessions list
10854
11154
  */
10855
11155
  async sessionList(params) {
10856
- this.validateChannelId(params.channelId);
11156
+ if (params.channelId) {
11157
+ this.validateChannelId(params.channelId);
11158
+ }
10857
11159
  this.validatePaginationParams(params);
10858
11160
  const response = await this.client.httpClient.get(
10859
11161
  "/live/v4/channel/session/new/list",
@@ -12024,8 +12326,16 @@ var V4ChannelService = class {
12024
12326
  * Validate channel ID
12025
12327
  */
12026
12328
  validateChannelId(channelId) {
12027
- if (!channelId || channelId.trim() === "") {
12028
- throw new PolyVValidationError("channelId is required and cannot be empty", "channelId");
12329
+ if (typeof channelId === "string") {
12330
+ if (!channelId || channelId.trim() === "") {
12331
+ throw new PolyVValidationError("channelId is required and cannot be empty", "channelId");
12332
+ }
12333
+ } else if (typeof channelId === "number") {
12334
+ if (!channelId || channelId <= 0) {
12335
+ throw new PolyVValidationError("channelId is required and must be a positive number", "channelId");
12336
+ }
12337
+ } else {
12338
+ throw new PolyVValidationError("channelId must be a string or number", "channelId");
12029
12339
  }
12030
12340
  }
12031
12341
  /**
@@ -14832,6 +15142,540 @@ var V4WebAppService = class {
14832
15142
  }
14833
15143
  };
14834
15144
 
15145
+ // src/services/statistics.service.ts
15146
+ var StatisticsService = class {
15147
+ client;
15148
+ /**
15149
+ * Create a new StatisticsService instance
15150
+ *
15151
+ * @param client - The PolyVClient instance to use for API calls
15152
+ */
15153
+ constructor(client) {
15154
+ this.client = client;
15155
+ }
15156
+ // ============================================
15157
+ // Daily View Statistics API
15158
+ // ============================================
15159
+ /**
15160
+ * Get daily view statistics
15161
+ *
15162
+ * Query daily view statistics for a channel within a date range.
15163
+ * The date range cannot exceed 60 days.
15164
+ *
15165
+ * @param params - Query parameters
15166
+ * @returns Daily view statistics response
15167
+ * @throws {PolyVValidationError} When parameters are invalid
15168
+ *
15169
+ * @example
15170
+ * ```typescript
15171
+ * const result = await client.statistics.getDailyViewStatistics({
15172
+ * channelId: '123456',
15173
+ * startDay: '2024-01-01',
15174
+ * endDay: '2024-01-31',
15175
+ * });
15176
+ * console.log(result.contents);
15177
+ * ```
15178
+ */
15179
+ async getDailyViewStatistics(params) {
15180
+ this.validateGetDailyViewStatisticsParams(params);
15181
+ const response = await this.client.httpClient.get(
15182
+ "/live/v3/channel/statistics/daily/summary",
15183
+ { params }
15184
+ );
15185
+ return {
15186
+ contents: response
15187
+ };
15188
+ }
15189
+ // ============================================
15190
+ // Private Validation Helpers
15191
+ // ============================================
15192
+ /**
15193
+ * Validate parameters for getDailyViewStatistics
15194
+ */
15195
+ validateGetDailyViewStatisticsParams(params) {
15196
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15197
+ throw new PolyVValidationError(
15198
+ "channelId is required and must be a non-empty string",
15199
+ "channelId",
15200
+ params.channelId
15201
+ );
15202
+ }
15203
+ if (!params.startDay || !isValidDateFormat(params.startDay)) {
15204
+ throw new PolyVValidationError(
15205
+ "startDay is required and must be in yyyy-MM-dd format",
15206
+ "startDay",
15207
+ params.startDay
15208
+ );
15209
+ }
15210
+ if (!params.endDay || !isValidDateFormat(params.endDay)) {
15211
+ throw new PolyVValidationError(
15212
+ "endDay is required and must be in yyyy-MM-dd format",
15213
+ "endDay",
15214
+ params.endDay
15215
+ );
15216
+ }
15217
+ const rangeValidation = validateDateRange(params.startDay, params.endDay, MAX_DATE_RANGE_DAYS);
15218
+ if (!rangeValidation.valid) {
15219
+ throw new PolyVValidationError(
15220
+ rangeValidation.error || "Invalid date range",
15221
+ "dateRange",
15222
+ { startDay: params.startDay, endDay: params.endDay, daysDiff: rangeValidation.daysDiff }
15223
+ );
15224
+ }
15225
+ }
15226
+ // ============================================
15227
+ // Concurrency Data API (Story 10.2)
15228
+ // ============================================
15229
+ /**
15230
+ * Get historical concurrency data
15231
+ *
15232
+ * Query historical concurrency data for a channel within a date range.
15233
+ * The date range cannot exceed 60 days.
15234
+ *
15235
+ * @param params - Query parameters
15236
+ * @returns Concurrency data response
15237
+ * @throws {PolyVValidationError} When parameters are invalid
15238
+ *
15239
+ * @example
15240
+ * ```typescript
15241
+ * const result = await client.statistics.getConcurrencyData({
15242
+ * channelId: '123456',
15243
+ * startDate: '2024-01-01',
15244
+ * endDate: '2024-01-31',
15245
+ * });
15246
+ * console.log(result.contents);
15247
+ * ```
15248
+ */
15249
+ async getConcurrencyData(params) {
15250
+ this.validateGetConcurrencyDataParams(params);
15251
+ const response = await this.client.httpClient.get(
15252
+ "/live/v3/channel/statistics/concurrence",
15253
+ { params }
15254
+ );
15255
+ return {
15256
+ contents: response
15257
+ };
15258
+ }
15259
+ /**
15260
+ * Validate parameters for getConcurrencyData
15261
+ */
15262
+ validateGetConcurrencyDataParams(params) {
15263
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15264
+ throw new PolyVValidationError(
15265
+ "channelId is required and must be a non-empty string",
15266
+ "channelId",
15267
+ params.channelId
15268
+ );
15269
+ }
15270
+ if (!params.startDate || !isValidDateFormat(params.startDate)) {
15271
+ throw new PolyVValidationError(
15272
+ "startDate is required and must be in yyyy-MM-dd format",
15273
+ "startDate",
15274
+ params.startDate
15275
+ );
15276
+ }
15277
+ if (!params.endDate || !isValidDateFormat(params.endDate)) {
15278
+ throw new PolyVValidationError(
15279
+ "endDate is required and must be in yyyy-MM-dd format",
15280
+ "endDate",
15281
+ params.endDate
15282
+ );
15283
+ }
15284
+ const rangeValidation = validateConcurrencyDateRange(params.startDate, params.endDate, MAX_DATE_RANGE_DAYS);
15285
+ if (!rangeValidation.valid) {
15286
+ throw new PolyVValidationError(
15287
+ rangeValidation.error || "Invalid date range",
15288
+ "dateRange",
15289
+ { startDate: params.startDate, endDate: params.endDate, daysDiff: rangeValidation.daysDiff }
15290
+ );
15291
+ }
15292
+ }
15293
+ // ============================================
15294
+ // Max Concurrent API (Story 10.2)
15295
+ // ============================================
15296
+ /**
15297
+ * Get maximum historical concurrent viewers
15298
+ *
15299
+ * Query the maximum concurrent viewers for a channel within a time range.
15300
+ * The time range cannot exceed 3 months.
15301
+ *
15302
+ * @param params - Query parameters
15303
+ * @returns Max concurrent response
15304
+ * @throws {PolyVValidationError} When parameters are invalid
15305
+ *
15306
+ * @example
15307
+ * ```typescript
15308
+ * const result = await client.statistics.getMaxConcurrent({
15309
+ * channelId: '123456',
15310
+ * startTime: 1704067200000,
15311
+ * endTime: 1735689600000,
15312
+ * });
15313
+ * console.log(result.contents);
15314
+ * ```
15315
+ */
15316
+ async getMaxConcurrent(params) {
15317
+ this.validateGetMaxConcurrentParams(params);
15318
+ const response = await this.client.httpClient.get(
15319
+ "/live/v3/channel/statistics/get-max-history-concurrent",
15320
+ { params }
15321
+ );
15322
+ return {
15323
+ contents: response
15324
+ };
15325
+ }
15326
+ /**
15327
+ * Validate parameters for getMaxConcurrent
15328
+ */
15329
+ validateGetMaxConcurrentParams(params) {
15330
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15331
+ throw new PolyVValidationError(
15332
+ "channelId is required and must be a non-empty string",
15333
+ "channelId",
15334
+ params.channelId
15335
+ );
15336
+ }
15337
+ if (!isValidTimestamp(params.startTime)) {
15338
+ throw new PolyVValidationError(
15339
+ "startTime is required and must be a valid timestamp",
15340
+ "startTime",
15341
+ params.startTime
15342
+ );
15343
+ }
15344
+ if (!isValidTimestamp(params.endTime)) {
15345
+ throw new PolyVValidationError(
15346
+ "endTime is required and must be a valid timestamp",
15347
+ "endTime",
15348
+ params.endTime
15349
+ );
15350
+ }
15351
+ const rangeValidation = validateTimestampRange(params.startTime, params.endTime);
15352
+ if (!rangeValidation.valid) {
15353
+ throw new PolyVValidationError(
15354
+ rangeValidation.error || "Invalid time range",
15355
+ "timeRange",
15356
+ { startTime: params.startTime, endTime: params.endTime, daysDiff: rangeValidation.daysDiff }
15357
+ );
15358
+ }
15359
+ }
15360
+ // ============================================
15361
+ // Region Distribution API (Story 10.3)
15362
+ // ============================================
15363
+ /**
15364
+ * Get region distribution
15365
+ *
15366
+ * Query the geographic distribution of viewers for a channel.
15367
+ * The time range cannot exceed 90 days.
15368
+ *
15369
+ * @param params - Query parameters
15370
+ * @returns Region distribution response
15371
+ * @throws {PolyVValidationError} When parameters are invalid
15372
+ *
15373
+ * @example
15374
+ * ```typescript
15375
+ * const result = await client.statistics.getRegionDistribution({
15376
+ * channelId: '123456',
15377
+ * startTime: 1648742400000,
15378
+ * endTime: 1651334399000,
15379
+ * type: 'province',
15380
+ * });
15381
+ * console.log(result.data);
15382
+ * ```
15383
+ */
15384
+ async getRegionDistribution(params) {
15385
+ this.validateGetRegionDistributionParams(params);
15386
+ const requestParams = {
15387
+ channelId: params.channelId,
15388
+ startTime: params.startTime,
15389
+ endTime: params.endTime
15390
+ };
15391
+ if (params.type) {
15392
+ requestParams.type = params.type;
15393
+ }
15394
+ const response = await this.client.httpClient.get(
15395
+ "/live/v4/channel/statistics/geo-summary-mc",
15396
+ { params: requestParams }
15397
+ );
15398
+ return response;
15399
+ }
15400
+ /**
15401
+ * Validate parameters for getRegionDistribution
15402
+ */
15403
+ validateGetRegionDistributionParams(params) {
15404
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15405
+ throw new PolyVValidationError(
15406
+ "channelId is required and must be a non-empty string",
15407
+ "channelId",
15408
+ params.channelId
15409
+ );
15410
+ }
15411
+ if (!isValidTimestamp(params.startTime)) {
15412
+ throw new PolyVValidationError(
15413
+ "startTime is required and must be a valid timestamp",
15414
+ "startTime",
15415
+ params.startTime
15416
+ );
15417
+ }
15418
+ if (!isValidTimestamp(params.endTime)) {
15419
+ throw new PolyVValidationError(
15420
+ "endTime is required and must be a valid timestamp",
15421
+ "endTime",
15422
+ params.endTime
15423
+ );
15424
+ }
15425
+ const rangeValidation = validate90DayTimestampRange(params.startTime, params.endTime);
15426
+ if (!rangeValidation.valid) {
15427
+ throw new PolyVValidationError(
15428
+ rangeValidation.error || "Invalid time range",
15429
+ "timeRange",
15430
+ { startTime: params.startTime, endTime: params.endTime, daysDiff: rangeValidation.daysDiff }
15431
+ );
15432
+ }
15433
+ if (params.type !== void 0) {
15434
+ const validTypes = ["country", "province", "city"];
15435
+ if (!validTypes.includes(params.type)) {
15436
+ throw new PolyVValidationError(
15437
+ "Type must be one of: country, province, city",
15438
+ "type",
15439
+ params.type
15440
+ );
15441
+ }
15442
+ }
15443
+ }
15444
+ // ============================================
15445
+ // Device Distribution API (Story 10.3)
15446
+ // ============================================
15447
+ /**
15448
+ * Get device distribution
15449
+ *
15450
+ * Query the browser/device distribution of viewers for a channel.
15451
+ * The time range cannot exceed 90 days.
15452
+ *
15453
+ * @param params - Query parameters
15454
+ * @returns Device distribution response
15455
+ * @throws {PolyVValidationError} When parameters are invalid
15456
+ *
15457
+ * @example
15458
+ * ```typescript
15459
+ * const result = await client.statistics.getDeviceDistribution({
15460
+ * channelId: '123456',
15461
+ * startTime: 1651386101000,
15462
+ * endTime: 1652336501462,
15463
+ * });
15464
+ * console.log(result.data);
15465
+ * ```
15466
+ */
15467
+ async getDeviceDistribution(params) {
15468
+ this.validateGetDeviceDistributionParams(params);
15469
+ const response = await this.client.httpClient.get(
15470
+ "/live/v4/channel/statistics/browser-summary",
15471
+ { params }
15472
+ );
15473
+ return response;
15474
+ }
15475
+ /**
15476
+ * Validate parameters for getDeviceDistribution
15477
+ */
15478
+ validateGetDeviceDistributionParams(params) {
15479
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15480
+ throw new PolyVValidationError(
15481
+ "channelId is required and must be a non-empty string",
15482
+ "channelId",
15483
+ params.channelId
15484
+ );
15485
+ }
15486
+ if (!isValidTimestamp(params.startTime)) {
15487
+ throw new PolyVValidationError(
15488
+ "startTime is required and must be a valid timestamp",
15489
+ "startTime",
15490
+ params.startTime
15491
+ );
15492
+ }
15493
+ if (!isValidTimestamp(params.endTime)) {
15494
+ throw new PolyVValidationError(
15495
+ "endTime is required and must be a valid timestamp",
15496
+ "endTime",
15497
+ params.endTime
15498
+ );
15499
+ }
15500
+ const rangeValidation = validate90DayTimestampRange(params.startTime, params.endTime);
15501
+ if (!rangeValidation.valid) {
15502
+ throw new PolyVValidationError(
15503
+ rangeValidation.error || "Invalid time range",
15504
+ "timeRange",
15505
+ { startTime: params.startTime, endTime: params.endTime, daysDiff: rangeValidation.daysDiff }
15506
+ );
15507
+ }
15508
+ }
15509
+ // ============================================
15510
+ // Viewlog Export API (Story 10.4)
15511
+ // ============================================
15512
+ /**
15513
+ * Get viewlog (viewing log) data
15514
+ *
15515
+ * Query viewing log data for a channel within a date range.
15516
+ * The date range must be within the same month.
15517
+ *
15518
+ * @param params - Query parameters
15519
+ * @returns Viewlog response with pagination
15520
+ * @throws {PolyVValidationError} When parameters are invalid
15521
+ *
15522
+ * @example
15523
+ * ```typescript
15524
+ * const result = await client.statistics.getViewlog({
15525
+ * channelId: '3151318',
15526
+ * startDate: '2024-01-01 00:00:00',
15527
+ * endDate: '2024-01-31 23:59:59',
15528
+ * });
15529
+ * console.log(result.contents);
15530
+ * ```
15531
+ */
15532
+ async getViewlog(params) {
15533
+ this.validateGetViewlogParams(params);
15534
+ const requestParams = {
15535
+ channelId: params.channelId,
15536
+ startDate: params.startDate,
15537
+ endDate: params.endDate,
15538
+ pageSize: params.pageSize ?? 1e3
15539
+ };
15540
+ if (params.page !== void 0) {
15541
+ requestParams.page = params.page;
15542
+ }
15543
+ if (params.watchType !== void 0) {
15544
+ requestParams.watchType = params.watchType;
15545
+ }
15546
+ const response = await this.client.httpClient.get(
15547
+ "/live/v3/user/statistics/viewlog",
15548
+ { params: requestParams }
15549
+ );
15550
+ if (response && typeof response === "object" && "data" in response) {
15551
+ const responseData = response;
15552
+ if (responseData.data && typeof responseData.data === "object") {
15553
+ return responseData.data;
15554
+ }
15555
+ }
15556
+ return response;
15557
+ }
15558
+ /**
15559
+ * Validate parameters for getViewlog
15560
+ */
15561
+ validateGetViewlogParams(params) {
15562
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15563
+ throw new PolyVValidationError(
15564
+ "channelId is required and must be a non-empty string",
15565
+ "channelId",
15566
+ params.channelId
15567
+ );
15568
+ }
15569
+ const dateTimeRegex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
15570
+ if (!params.startDate || !dateTimeRegex.test(params.startDate)) {
15571
+ throw new PolyVValidationError(
15572
+ "startDate is required and must be in yyyy-MM-dd HH:mm:ss format",
15573
+ "startDate",
15574
+ params.startDate
15575
+ );
15576
+ }
15577
+ if (!params.endDate || !dateTimeRegex.test(params.endDate)) {
15578
+ throw new PolyVValidationError(
15579
+ "endDate is required and must be in yyyy-MM-dd HH:mm:ss format",
15580
+ "endDate",
15581
+ params.endDate
15582
+ );
15583
+ }
15584
+ const startMonth = params.startDate.substring(0, 7);
15585
+ const endMonth = params.endDate.substring(0, 7);
15586
+ if (startMonth !== endMonth) {
15587
+ throw new PolyVValidationError(
15588
+ "startDate and endDate must be in the same month",
15589
+ "dateRange",
15590
+ { startDate: params.startDate, endDate: params.endDate }
15591
+ );
15592
+ }
15593
+ if (params.watchType !== void 0) {
15594
+ const validWatchTypes = ["live", "vod"];
15595
+ if (!validWatchTypes.includes(params.watchType)) {
15596
+ throw new PolyVValidationError(
15597
+ 'watchType must be either "live" or "vod"',
15598
+ "watchType",
15599
+ params.watchType
15600
+ );
15601
+ }
15602
+ }
15603
+ }
15604
+ // ============================================
15605
+ // Session Stats Export API (Story 10.4)
15606
+ // ============================================
15607
+ /**
15608
+ * Export session statistics report
15609
+ *
15610
+ * Export the session statistics report for a specific session.
15611
+ * Returns a download URL for the report file.
15612
+ *
15613
+ * @param params - Query parameters
15614
+ * @returns Export response with download URL
15615
+ * @throws {PolyVValidationError} When parameters are invalid
15616
+ *
15617
+ * @example
15618
+ * ```typescript
15619
+ * const result = await client.statistics.exportSessionStats({
15620
+ * channelId: '3151318',
15621
+ * sessionId: 'fv3ma84e63',
15622
+ * });
15623
+ * console.log(result.downloadUrl);
15624
+ * ```
15625
+ */
15626
+ async exportSessionStats(params) {
15627
+ this.validateExportSessionStatsParams(params);
15628
+ const response = await this.client.httpClient.get(
15629
+ "/live/v3/channel/session/stats/export",
15630
+ { params }
15631
+ );
15632
+ if (response && typeof response === "object" && "data" in response) {
15633
+ const responseData = response;
15634
+ if (responseData.data && typeof responseData.data === "object") {
15635
+ const innerData = responseData.data;
15636
+ if (innerData.code && innerData.code !== 200) {
15637
+ throw new Error(innerData.message || "API Error");
15638
+ }
15639
+ if ("downloadUrl" in innerData) {
15640
+ return innerData;
15641
+ }
15642
+ if (typeof innerData.data === "string" && innerData.data) {
15643
+ return { downloadUrl: innerData.data };
15644
+ }
15645
+ }
15646
+ }
15647
+ if (response && typeof response === "object" && "code" in response) {
15648
+ const apiResponse = response;
15649
+ if (apiResponse.code && apiResponse.code !== 200) {
15650
+ throw new Error(String(apiResponse.message || "API Error"));
15651
+ }
15652
+ if (typeof apiResponse.data === "string" && apiResponse.data) {
15653
+ return { downloadUrl: apiResponse.data };
15654
+ }
15655
+ }
15656
+ return response;
15657
+ }
15658
+ /**
15659
+ * Validate parameters for exportSessionStats
15660
+ */
15661
+ validateExportSessionStatsParams(params) {
15662
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15663
+ throw new PolyVValidationError(
15664
+ "channelId is required and must be a non-empty string",
15665
+ "channelId",
15666
+ params.channelId
15667
+ );
15668
+ }
15669
+ if (!params.sessionId || typeof params.sessionId !== "string" || params.sessionId.trim() === "") {
15670
+ throw new PolyVValidationError(
15671
+ "sessionId is required and must be a non-empty string",
15672
+ "sessionId",
15673
+ params.sessionId
15674
+ );
15675
+ }
15676
+ }
15677
+ };
15678
+
14835
15679
  // src/client.ts
14836
15680
  var DEFAULT_CONFIG = {
14837
15681
  baseUrl: "https://api.polyv.net",
@@ -14855,6 +15699,10 @@ var PolyVClient = class {
14855
15699
  * Channel service for managing live channels
14856
15700
  */
14857
15701
  channel;
15702
+ /**
15703
+ * Statistics service for managing statistics operations
15704
+ */
15705
+ statistics;
14858
15706
  /**
14859
15707
  * Chat service for managing chat messages
14860
15708
  */
@@ -14954,6 +15802,7 @@ var PolyVClient = class {
14954
15802
  };
14955
15803
  this.httpClient = this.createHttpClient();
14956
15804
  this.channel = new ChannelService(this);
15805
+ this.statistics = new StatisticsService(this);
14957
15806
  this.chat = new ChatService(this);
14958
15807
  this.liveInteraction = new LiveInteractionService(this);
14959
15808
  this.account = new AccountService(this);
@@ -15253,6 +16102,6 @@ function getErrorCodeCategory(code) {
15253
16102
  // src/index.ts
15254
16103
  var VERSION = "1.0.0";
15255
16104
 
15256
- export { ChannelService, ERROR_CATEGORIES, ERROR_MESSAGES, HttpMethod, PolyVAPIError, PolyVClient, PolyVError, PolyVErrorCode, PolyVValidationError, PptStatus, SignatureMethod, TtsVoiceTag, VERSION, VideoProduceStatus, collectAll, createSignature, generateSignature, generateTimestamp, getEnvironmentInfo, getErrorCodeCategory, getErrorMessage, getErrorMessageByCode, isBrowser, isNode, isPolyVAPIError, isPolyVError, isPolyVErrorCode, isPolyVValidationError, isWebWorker, paginate, sortParams };
16105
+ export { ChannelService, ERROR_CATEGORIES, ERROR_MESSAGES, HttpMethod, MAX_DATE_RANGE_DAYS, PolyVAPIError, PolyVClient, PolyVError, PolyVErrorCode, PolyVValidationError, PptStatus, SignatureMethod, TtsVoiceTag, VERSION, VideoProduceStatus, collectAll, createSignature, generateSignature, generateTimestamp, getEnvironmentInfo, getErrorCodeCategory, getErrorMessage, getErrorMessageByCode, isBrowser, isNode, isPolyVAPIError, isPolyVError, isPolyVErrorCode, isPolyVValidationError, isStartDateBeforeEndDate, isValidDateFormat, isWebWorker, paginate, sortParams, validateDateRange };
15257
16106
  //# sourceMappingURL=index.js.map
15258
16107
  //# sourceMappingURL=index.js.map