polyv-live-api-sdk 1.0.0 → 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.cjs CHANGED
@@ -431,6 +431,117 @@ async function collectAll(fetcher, options = {}) {
431
431
  return allItems;
432
432
  }
433
433
 
434
+ // src/utils/date-validation.ts
435
+ var MAX_DATE_RANGE_DAYS = 60;
436
+ var MAX_TIME_RANGE_MONTHS = 3;
437
+ var MAX_AUDIENCE_TIME_RANGE_DAYS = 90;
438
+ var DATE_FORMAT_REGEX = /^\d{4}-\d{2}-\d{2}$/;
439
+ function isValidDateFormat(dateStr) {
440
+ if (!dateStr || typeof dateStr !== "string") {
441
+ return false;
442
+ }
443
+ if (!DATE_FORMAT_REGEX.test(dateStr)) {
444
+ return false;
445
+ }
446
+ const date = new Date(dateStr);
447
+ if (isNaN(date.getTime())) {
448
+ return false;
449
+ }
450
+ const [year, month, day] = dateStr.split("-").map(Number);
451
+ return date.getFullYear() === year && date.getMonth() + 1 === month && date.getDate() === day;
452
+ }
453
+ function isStartDateBeforeEndDate(startDay, endDay) {
454
+ const startDate = new Date(startDay);
455
+ const endDate = new Date(endDay);
456
+ return startDate <= endDate;
457
+ }
458
+ function isStartTimeBeforeEndTime(startTime, endTime) {
459
+ return startTime <= endTime;
460
+ }
461
+ function isValidTimestamp(value) {
462
+ if (typeof value !== "number" || !Number.isFinite(value)) {
463
+ return false;
464
+ }
465
+ return value > 9466848e5;
466
+ }
467
+ function validateDateRange(startDay, endDay, maxDays = MAX_DATE_RANGE_DAYS) {
468
+ if (!isStartDateBeforeEndDate(startDay, endDay)) {
469
+ return {
470
+ valid: false,
471
+ error: "startDay must be before or equal to endDay"
472
+ };
473
+ }
474
+ const startDate = new Date(startDay);
475
+ const endDate = new Date(endDay);
476
+ const diffTime = endDate.getTime() - startDate.getTime();
477
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
478
+ if (diffDays > maxDays) {
479
+ return {
480
+ valid: false,
481
+ error: `Date range cannot exceed ${maxDays} days`,
482
+ daysDiff: diffDays
483
+ };
484
+ }
485
+ return { valid: true, daysDiff: diffDays };
486
+ }
487
+ function validateTimestampRange(startTime, endTime, maxMonths = MAX_TIME_RANGE_MONTHS) {
488
+ if (!isStartTimeBeforeEndTime(startTime, endTime)) {
489
+ return {
490
+ valid: false,
491
+ error: "startTime must be before or equal to endTime"
492
+ };
493
+ }
494
+ const diffTime = endTime - startTime;
495
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
496
+ const maxDays = maxMonths * 31;
497
+ if (diffDays > maxDays) {
498
+ return {
499
+ valid: false,
500
+ error: `Time range cannot exceed ${maxMonths} months`,
501
+ daysDiff: diffDays
502
+ };
503
+ }
504
+ return { valid: true, daysDiff: diffDays };
505
+ }
506
+ function validate90DayTimestampRange(startTime, endTime) {
507
+ if (!isStartTimeBeforeEndTime(startTime, endTime)) {
508
+ return {
509
+ valid: false,
510
+ error: "startTime must be before or equal to endTime"
511
+ };
512
+ }
513
+ const diffTime = endTime - startTime;
514
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
515
+ if (diffDays > MAX_AUDIENCE_TIME_RANGE_DAYS) {
516
+ return {
517
+ valid: false,
518
+ error: `Time range cannot exceed ${MAX_AUDIENCE_TIME_RANGE_DAYS} days`,
519
+ daysDiff: diffDays
520
+ };
521
+ }
522
+ return { valid: true, daysDiff: diffDays };
523
+ }
524
+ function validateConcurrencyDateRange(startDate, endDate, maxDays = MAX_DATE_RANGE_DAYS) {
525
+ if (!isStartDateBeforeEndDate(startDate, endDate)) {
526
+ return {
527
+ valid: false,
528
+ error: "startDate must be before or equal to endDate"
529
+ };
530
+ }
531
+ const start = new Date(startDate);
532
+ const end = new Date(endDate);
533
+ const diffTime = end.getTime() - start.getTime();
534
+ const diffDays = Math.ceil(diffTime / (1e3 * 60 * 60 * 24));
535
+ if (diffDays > maxDays) {
536
+ return {
537
+ valid: false,
538
+ error: `Date range cannot exceed ${maxDays} days`,
539
+ daysDiff: diffDays
540
+ };
541
+ }
542
+ return { valid: true, daysDiff: diffDays };
543
+ }
544
+
434
545
  // src/services/channel.service.ts
435
546
  var ChannelService = class {
436
547
  client;
@@ -1846,17 +1957,21 @@ var ChannelService = class {
1846
1957
  * await channelService.setRecordDefault('ch123456', 'file123');
1847
1958
  * ```
1848
1959
  */
1849
- async setRecordDefault(channelId, fileId) {
1960
+ async setRecordDefault(channelId, fileId, listType) {
1850
1961
  if (!channelId || channelId.trim() === "") {
1851
1962
  throw PolyVValidationError.required("channelId");
1852
1963
  }
1853
1964
  if (!fileId || fileId.trim() === "") {
1854
1965
  throw PolyVValidationError.required("fileId");
1855
1966
  }
1967
+ const params = { channelId, fileId };
1968
+ if (listType) {
1969
+ params.listType = listType;
1970
+ }
1856
1971
  await this.client.httpClient.post(
1857
1972
  "/live/v3/channel/record/set-default",
1858
1973
  null,
1859
- { params: { channelId, fileId } }
1974
+ { params }
1860
1975
  );
1861
1976
  return true;
1862
1977
  }
@@ -1970,6 +2085,38 @@ var ChannelService = class {
1970
2085
  );
1971
2086
  return response;
1972
2087
  }
2088
+ /**
2089
+ * Set playback setting (Story 9.7)
2090
+ *
2091
+ * Sets the playback settings for a channel.
2092
+ * API: POST /live/v3/channel/playback/set-setting
2093
+ *
2094
+ * @param channelId - The channel ID
2095
+ * @param options - Playback setting options
2096
+ * @returns true if operation was successful
2097
+ * @throws PolyVValidationError if channelId is empty
2098
+ *
2099
+ * @example
2100
+ * ```typescript
2101
+ * await channelService.setPlaybackSetting('ch123456', {
2102
+ * playbackEnabled: 'Y',
2103
+ * type: 'single',
2104
+ * origin: 'playback',
2105
+ * });
2106
+ * ```
2107
+ */
2108
+ async setPlaybackSetting(channelId, options) {
2109
+ if (!channelId || channelId.trim() === "") {
2110
+ throw PolyVValidationError.required("channelId");
2111
+ }
2112
+ const params = { channelId, ...options };
2113
+ await this.client.httpClient.post(
2114
+ "/live/v3/channel/playback/set-setting",
2115
+ null,
2116
+ { params }
2117
+ );
2118
+ return true;
2119
+ }
1973
2120
  /**
1974
2121
  * Set playback sort
1975
2122
  *
@@ -2299,6 +2446,15 @@ var ChannelService = class {
2299
2446
  if (options.callbackUrl !== void 0) {
2300
2447
  params.callbackUrl = options.callbackUrl;
2301
2448
  }
2449
+ if (options.autoConvert !== void 0) {
2450
+ params.autoConvert = options.autoConvert;
2451
+ }
2452
+ if (options.mergeMp4 !== void 0) {
2453
+ params.mergeMp4 = options.mergeMp4;
2454
+ }
2455
+ if (options.orderByCustom !== void 0) {
2456
+ params.orderByCustom = options.orderByCustom;
2457
+ }
2302
2458
  await this.client.httpClient.post(
2303
2459
  "/live/v3/channel/record/merge-async",
2304
2460
  null,
@@ -4035,6 +4191,44 @@ var ChannelService = class {
4035
4191
  // ============================================
4036
4192
  // Product APIs (Story 8-2)
4037
4193
  // ============================================
4194
+ /**
4195
+ * List channel products
4196
+ *
4197
+ * Lists products in a channel with pagination support.
4198
+ *
4199
+ * @param params - Query parameters including channelId (required)
4200
+ * @returns Paginated product list
4201
+ * @throws PolyVValidationError if channelId is missing
4202
+ *
4203
+ * @example
4204
+ * ```typescript
4205
+ * const result = await channelService.listChannelProducts({
4206
+ * channelId: 'ch123456',
4207
+ * pageNumber: 1,
4208
+ * pageSize: 20,
4209
+ * });
4210
+ * console.log(result.contents);
4211
+ * ```
4212
+ */
4213
+ async listChannelProducts(params) {
4214
+ if (!params.channelId || params.channelId.trim() === "") {
4215
+ throw PolyVValidationError.required("channelId");
4216
+ }
4217
+ const queryParams = {
4218
+ channelId: params.channelId
4219
+ };
4220
+ if (params.pageNumber !== void 0) {
4221
+ queryParams.pageNumber = params.pageNumber;
4222
+ }
4223
+ if (params.pageSize !== void 0) {
4224
+ queryParams.pageSize = params.pageSize;
4225
+ }
4226
+ const response = await this.client.httpClient.get(
4227
+ "/live/v3/channel/product/list",
4228
+ { params: queryParams }
4229
+ );
4230
+ return response;
4231
+ }
4038
4232
  /**
4039
4233
  * Add channel product
4040
4234
  *
@@ -9399,6 +9593,112 @@ var PlayerService = class {
9399
9593
  }
9400
9594
  }
9401
9595
  }
9596
+ // ============================================
9597
+ // Channel Decorate APIs (Story 10.5)
9598
+ // ============================================
9599
+ /**
9600
+ * Get channel decorate settings
9601
+ * Query channel player decoration settings (watermark, warmup image, etc.)
9602
+ *
9603
+ * @param channelId - Channel ID
9604
+ * @returns Channel decorate settings
9605
+ *
9606
+ * @example
9607
+ * ```typescript
9608
+ * const decorate = await client.player.getChannelDecorate(123456);
9609
+ * console.log(decorate.player.watermarkEnabled);
9610
+ * ```
9611
+ */
9612
+ async getChannelDecorate(channelId) {
9613
+ this.validateChannelId(channelId);
9614
+ const response = await this.client.httpClient.get(
9615
+ "/live/v4/channel/decorate/get",
9616
+ { params: { channelId } }
9617
+ );
9618
+ return response;
9619
+ }
9620
+ /**
9621
+ * Update channel decorate settings
9622
+ * Update channel player decoration settings (watermark, warmup image, etc.)
9623
+ *
9624
+ * @param channelId - Channel ID
9625
+ * @param params - Channel decorate update parameters
9626
+ * @returns true on success
9627
+ *
9628
+ * @example
9629
+ * ```typescript
9630
+ * await client.player.updateChannelDecorate(123456, {
9631
+ * watermarkEnabled: 'Y',
9632
+ * iconUrl: 'http://example.com/logo.png',
9633
+ * iconPosition: 'br',
9634
+ * logoOpacity: 0.8,
9635
+ * });
9636
+ * ```
9637
+ */
9638
+ async updateChannelDecorate(channelId, params) {
9639
+ this.validateChannelId(channelId);
9640
+ if (params.iconPosition !== void 0) {
9641
+ this.validateLogoPosition(params.iconPosition);
9642
+ }
9643
+ if (params.logoOpacity !== void 0) {
9644
+ this.validateDecorateOpacity(params.logoOpacity);
9645
+ }
9646
+ if (params.watermarkEnabled !== void 0) {
9647
+ this.validateYNValue(params.watermarkEnabled, "watermarkEnabled");
9648
+ }
9649
+ if (params.warmUpEnabled !== void 0) {
9650
+ this.validateYNValue(params.warmUpEnabled, "warmUpEnabled");
9651
+ }
9652
+ const playerBody = {};
9653
+ if (params.watermarkEnabled !== void 0) {
9654
+ playerBody.watermarkEnabled = params.watermarkEnabled;
9655
+ }
9656
+ if (params.iconUrl !== void 0) {
9657
+ playerBody.iconUrl = params.iconUrl;
9658
+ }
9659
+ if (params.iconPosition !== void 0) {
9660
+ playerBody.iconPosition = params.iconPosition;
9661
+ }
9662
+ if (params.logoOpacity !== void 0) {
9663
+ playerBody.logoOpacity = params.logoOpacity;
9664
+ }
9665
+ if (params.iconLink !== void 0) {
9666
+ playerBody.iconLink = params.iconLink;
9667
+ }
9668
+ if (params.warmUpEnabled !== void 0) {
9669
+ playerBody.warmUpEnabled = params.warmUpEnabled;
9670
+ }
9671
+ if (params.warmUpImageUrl !== void 0) {
9672
+ playerBody.warmUpImageUrl = params.warmUpImageUrl;
9673
+ }
9674
+ if (params.coverJumpUrl !== void 0) {
9675
+ playerBody.coverJumpUrl = params.coverJumpUrl;
9676
+ }
9677
+ if (params.backgroundUrl !== void 0) {
9678
+ playerBody.backgroundUrl = params.backgroundUrl;
9679
+ }
9680
+ if (params.basePV !== void 0) {
9681
+ playerBody.basePV = params.basePV;
9682
+ }
9683
+ if (params.actualPV !== void 0) {
9684
+ playerBody.actualPV = params.actualPV;
9685
+ }
9686
+ const body = { player: playerBody };
9687
+ const response = await this.client.httpClient.post(
9688
+ "/live/v4/channel/decorate/update",
9689
+ body,
9690
+ { params: { channelId } }
9691
+ );
9692
+ return response;
9693
+ }
9694
+ /**
9695
+ * Validate decorate opacity (0-1)
9696
+ */
9697
+ validateDecorateOpacity(opacity) {
9698
+ if (typeof opacity !== "number" || opacity < 0 || opacity > 1) {
9699
+ throw new PolyVValidationError("logoOpacity must be a number between 0 and 1");
9700
+ }
9701
+ }
9402
9702
  };
9403
9703
 
9404
9704
  // src/services/other.service.ts
@@ -10637,7 +10937,7 @@ var V4ChannelService = class {
10637
10937
  async channelDetailList(params) {
10638
10938
  this.validatePaginationParams(params);
10639
10939
  const response = await this.client.httpClient.get(
10640
- "/live/v4/channel/operate/channel-detail-list",
10940
+ "/live/v4/channel/detail/list",
10641
10941
  { params }
10642
10942
  );
10643
10943
  return response;
@@ -10860,7 +11160,9 @@ var V4ChannelService = class {
10860
11160
  * @returns Sessions list
10861
11161
  */
10862
11162
  async sessionList(params) {
10863
- this.validateChannelId(params.channelId);
11163
+ if (params.channelId) {
11164
+ this.validateChannelId(params.channelId);
11165
+ }
10864
11166
  this.validatePaginationParams(params);
10865
11167
  const response = await this.client.httpClient.get(
10866
11168
  "/live/v4/channel/session/new/list",
@@ -12031,8 +12333,16 @@ var V4ChannelService = class {
12031
12333
  * Validate channel ID
12032
12334
  */
12033
12335
  validateChannelId(channelId) {
12034
- if (!channelId || channelId.trim() === "") {
12035
- throw new PolyVValidationError("channelId is required and cannot be empty", "channelId");
12336
+ if (typeof channelId === "string") {
12337
+ if (!channelId || channelId.trim() === "") {
12338
+ throw new PolyVValidationError("channelId is required and cannot be empty", "channelId");
12339
+ }
12340
+ } else if (typeof channelId === "number") {
12341
+ if (!channelId || channelId <= 0) {
12342
+ throw new PolyVValidationError("channelId is required and must be a positive number", "channelId");
12343
+ }
12344
+ } else {
12345
+ throw new PolyVValidationError("channelId must be a string or number", "channelId");
12036
12346
  }
12037
12347
  }
12038
12348
  /**
@@ -14839,6 +15149,540 @@ var V4WebAppService = class {
14839
15149
  }
14840
15150
  };
14841
15151
 
15152
+ // src/services/statistics.service.ts
15153
+ var StatisticsService = class {
15154
+ client;
15155
+ /**
15156
+ * Create a new StatisticsService instance
15157
+ *
15158
+ * @param client - The PolyVClient instance to use for API calls
15159
+ */
15160
+ constructor(client) {
15161
+ this.client = client;
15162
+ }
15163
+ // ============================================
15164
+ // Daily View Statistics API
15165
+ // ============================================
15166
+ /**
15167
+ * Get daily view statistics
15168
+ *
15169
+ * Query daily view statistics for a channel within a date range.
15170
+ * The date range cannot exceed 60 days.
15171
+ *
15172
+ * @param params - Query parameters
15173
+ * @returns Daily view statistics response
15174
+ * @throws {PolyVValidationError} When parameters are invalid
15175
+ *
15176
+ * @example
15177
+ * ```typescript
15178
+ * const result = await client.statistics.getDailyViewStatistics({
15179
+ * channelId: '123456',
15180
+ * startDay: '2024-01-01',
15181
+ * endDay: '2024-01-31',
15182
+ * });
15183
+ * console.log(result.contents);
15184
+ * ```
15185
+ */
15186
+ async getDailyViewStatistics(params) {
15187
+ this.validateGetDailyViewStatisticsParams(params);
15188
+ const response = await this.client.httpClient.get(
15189
+ "/live/v3/channel/statistics/daily/summary",
15190
+ { params }
15191
+ );
15192
+ return {
15193
+ contents: response
15194
+ };
15195
+ }
15196
+ // ============================================
15197
+ // Private Validation Helpers
15198
+ // ============================================
15199
+ /**
15200
+ * Validate parameters for getDailyViewStatistics
15201
+ */
15202
+ validateGetDailyViewStatisticsParams(params) {
15203
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15204
+ throw new PolyVValidationError(
15205
+ "channelId is required and must be a non-empty string",
15206
+ "channelId",
15207
+ params.channelId
15208
+ );
15209
+ }
15210
+ if (!params.startDay || !isValidDateFormat(params.startDay)) {
15211
+ throw new PolyVValidationError(
15212
+ "startDay is required and must be in yyyy-MM-dd format",
15213
+ "startDay",
15214
+ params.startDay
15215
+ );
15216
+ }
15217
+ if (!params.endDay || !isValidDateFormat(params.endDay)) {
15218
+ throw new PolyVValidationError(
15219
+ "endDay is required and must be in yyyy-MM-dd format",
15220
+ "endDay",
15221
+ params.endDay
15222
+ );
15223
+ }
15224
+ const rangeValidation = validateDateRange(params.startDay, params.endDay, MAX_DATE_RANGE_DAYS);
15225
+ if (!rangeValidation.valid) {
15226
+ throw new PolyVValidationError(
15227
+ rangeValidation.error || "Invalid date range",
15228
+ "dateRange",
15229
+ { startDay: params.startDay, endDay: params.endDay, daysDiff: rangeValidation.daysDiff }
15230
+ );
15231
+ }
15232
+ }
15233
+ // ============================================
15234
+ // Concurrency Data API (Story 10.2)
15235
+ // ============================================
15236
+ /**
15237
+ * Get historical concurrency data
15238
+ *
15239
+ * Query historical concurrency data for a channel within a date range.
15240
+ * The date range cannot exceed 60 days.
15241
+ *
15242
+ * @param params - Query parameters
15243
+ * @returns Concurrency data response
15244
+ * @throws {PolyVValidationError} When parameters are invalid
15245
+ *
15246
+ * @example
15247
+ * ```typescript
15248
+ * const result = await client.statistics.getConcurrencyData({
15249
+ * channelId: '123456',
15250
+ * startDate: '2024-01-01',
15251
+ * endDate: '2024-01-31',
15252
+ * });
15253
+ * console.log(result.contents);
15254
+ * ```
15255
+ */
15256
+ async getConcurrencyData(params) {
15257
+ this.validateGetConcurrencyDataParams(params);
15258
+ const response = await this.client.httpClient.get(
15259
+ "/live/v3/channel/statistics/concurrence",
15260
+ { params }
15261
+ );
15262
+ return {
15263
+ contents: response
15264
+ };
15265
+ }
15266
+ /**
15267
+ * Validate parameters for getConcurrencyData
15268
+ */
15269
+ validateGetConcurrencyDataParams(params) {
15270
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15271
+ throw new PolyVValidationError(
15272
+ "channelId is required and must be a non-empty string",
15273
+ "channelId",
15274
+ params.channelId
15275
+ );
15276
+ }
15277
+ if (!params.startDate || !isValidDateFormat(params.startDate)) {
15278
+ throw new PolyVValidationError(
15279
+ "startDate is required and must be in yyyy-MM-dd format",
15280
+ "startDate",
15281
+ params.startDate
15282
+ );
15283
+ }
15284
+ if (!params.endDate || !isValidDateFormat(params.endDate)) {
15285
+ throw new PolyVValidationError(
15286
+ "endDate is required and must be in yyyy-MM-dd format",
15287
+ "endDate",
15288
+ params.endDate
15289
+ );
15290
+ }
15291
+ const rangeValidation = validateConcurrencyDateRange(params.startDate, params.endDate, MAX_DATE_RANGE_DAYS);
15292
+ if (!rangeValidation.valid) {
15293
+ throw new PolyVValidationError(
15294
+ rangeValidation.error || "Invalid date range",
15295
+ "dateRange",
15296
+ { startDate: params.startDate, endDate: params.endDate, daysDiff: rangeValidation.daysDiff }
15297
+ );
15298
+ }
15299
+ }
15300
+ // ============================================
15301
+ // Max Concurrent API (Story 10.2)
15302
+ // ============================================
15303
+ /**
15304
+ * Get maximum historical concurrent viewers
15305
+ *
15306
+ * Query the maximum concurrent viewers for a channel within a time range.
15307
+ * The time range cannot exceed 3 months.
15308
+ *
15309
+ * @param params - Query parameters
15310
+ * @returns Max concurrent response
15311
+ * @throws {PolyVValidationError} When parameters are invalid
15312
+ *
15313
+ * @example
15314
+ * ```typescript
15315
+ * const result = await client.statistics.getMaxConcurrent({
15316
+ * channelId: '123456',
15317
+ * startTime: 1704067200000,
15318
+ * endTime: 1735689600000,
15319
+ * });
15320
+ * console.log(result.contents);
15321
+ * ```
15322
+ */
15323
+ async getMaxConcurrent(params) {
15324
+ this.validateGetMaxConcurrentParams(params);
15325
+ const response = await this.client.httpClient.get(
15326
+ "/live/v3/channel/statistics/get-max-history-concurrent",
15327
+ { params }
15328
+ );
15329
+ return {
15330
+ contents: response
15331
+ };
15332
+ }
15333
+ /**
15334
+ * Validate parameters for getMaxConcurrent
15335
+ */
15336
+ validateGetMaxConcurrentParams(params) {
15337
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15338
+ throw new PolyVValidationError(
15339
+ "channelId is required and must be a non-empty string",
15340
+ "channelId",
15341
+ params.channelId
15342
+ );
15343
+ }
15344
+ if (!isValidTimestamp(params.startTime)) {
15345
+ throw new PolyVValidationError(
15346
+ "startTime is required and must be a valid timestamp",
15347
+ "startTime",
15348
+ params.startTime
15349
+ );
15350
+ }
15351
+ if (!isValidTimestamp(params.endTime)) {
15352
+ throw new PolyVValidationError(
15353
+ "endTime is required and must be a valid timestamp",
15354
+ "endTime",
15355
+ params.endTime
15356
+ );
15357
+ }
15358
+ const rangeValidation = validateTimestampRange(params.startTime, params.endTime);
15359
+ if (!rangeValidation.valid) {
15360
+ throw new PolyVValidationError(
15361
+ rangeValidation.error || "Invalid time range",
15362
+ "timeRange",
15363
+ { startTime: params.startTime, endTime: params.endTime, daysDiff: rangeValidation.daysDiff }
15364
+ );
15365
+ }
15366
+ }
15367
+ // ============================================
15368
+ // Region Distribution API (Story 10.3)
15369
+ // ============================================
15370
+ /**
15371
+ * Get region distribution
15372
+ *
15373
+ * Query the geographic distribution of viewers for a channel.
15374
+ * The time range cannot exceed 90 days.
15375
+ *
15376
+ * @param params - Query parameters
15377
+ * @returns Region distribution response
15378
+ * @throws {PolyVValidationError} When parameters are invalid
15379
+ *
15380
+ * @example
15381
+ * ```typescript
15382
+ * const result = await client.statistics.getRegionDistribution({
15383
+ * channelId: '123456',
15384
+ * startTime: 1648742400000,
15385
+ * endTime: 1651334399000,
15386
+ * type: 'province',
15387
+ * });
15388
+ * console.log(result.data);
15389
+ * ```
15390
+ */
15391
+ async getRegionDistribution(params) {
15392
+ this.validateGetRegionDistributionParams(params);
15393
+ const requestParams = {
15394
+ channelId: params.channelId,
15395
+ startTime: params.startTime,
15396
+ endTime: params.endTime
15397
+ };
15398
+ if (params.type) {
15399
+ requestParams.type = params.type;
15400
+ }
15401
+ const response = await this.client.httpClient.get(
15402
+ "/live/v4/channel/statistics/geo-summary-mc",
15403
+ { params: requestParams }
15404
+ );
15405
+ return response;
15406
+ }
15407
+ /**
15408
+ * Validate parameters for getRegionDistribution
15409
+ */
15410
+ validateGetRegionDistributionParams(params) {
15411
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15412
+ throw new PolyVValidationError(
15413
+ "channelId is required and must be a non-empty string",
15414
+ "channelId",
15415
+ params.channelId
15416
+ );
15417
+ }
15418
+ if (!isValidTimestamp(params.startTime)) {
15419
+ throw new PolyVValidationError(
15420
+ "startTime is required and must be a valid timestamp",
15421
+ "startTime",
15422
+ params.startTime
15423
+ );
15424
+ }
15425
+ if (!isValidTimestamp(params.endTime)) {
15426
+ throw new PolyVValidationError(
15427
+ "endTime is required and must be a valid timestamp",
15428
+ "endTime",
15429
+ params.endTime
15430
+ );
15431
+ }
15432
+ const rangeValidation = validate90DayTimestampRange(params.startTime, params.endTime);
15433
+ if (!rangeValidation.valid) {
15434
+ throw new PolyVValidationError(
15435
+ rangeValidation.error || "Invalid time range",
15436
+ "timeRange",
15437
+ { startTime: params.startTime, endTime: params.endTime, daysDiff: rangeValidation.daysDiff }
15438
+ );
15439
+ }
15440
+ if (params.type !== void 0) {
15441
+ const validTypes = ["country", "province", "city"];
15442
+ if (!validTypes.includes(params.type)) {
15443
+ throw new PolyVValidationError(
15444
+ "Type must be one of: country, province, city",
15445
+ "type",
15446
+ params.type
15447
+ );
15448
+ }
15449
+ }
15450
+ }
15451
+ // ============================================
15452
+ // Device Distribution API (Story 10.3)
15453
+ // ============================================
15454
+ /**
15455
+ * Get device distribution
15456
+ *
15457
+ * Query the browser/device distribution of viewers for a channel.
15458
+ * The time range cannot exceed 90 days.
15459
+ *
15460
+ * @param params - Query parameters
15461
+ * @returns Device distribution response
15462
+ * @throws {PolyVValidationError} When parameters are invalid
15463
+ *
15464
+ * @example
15465
+ * ```typescript
15466
+ * const result = await client.statistics.getDeviceDistribution({
15467
+ * channelId: '123456',
15468
+ * startTime: 1651386101000,
15469
+ * endTime: 1652336501462,
15470
+ * });
15471
+ * console.log(result.data);
15472
+ * ```
15473
+ */
15474
+ async getDeviceDistribution(params) {
15475
+ this.validateGetDeviceDistributionParams(params);
15476
+ const response = await this.client.httpClient.get(
15477
+ "/live/v4/channel/statistics/browser-summary",
15478
+ { params }
15479
+ );
15480
+ return response;
15481
+ }
15482
+ /**
15483
+ * Validate parameters for getDeviceDistribution
15484
+ */
15485
+ validateGetDeviceDistributionParams(params) {
15486
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15487
+ throw new PolyVValidationError(
15488
+ "channelId is required and must be a non-empty string",
15489
+ "channelId",
15490
+ params.channelId
15491
+ );
15492
+ }
15493
+ if (!isValidTimestamp(params.startTime)) {
15494
+ throw new PolyVValidationError(
15495
+ "startTime is required and must be a valid timestamp",
15496
+ "startTime",
15497
+ params.startTime
15498
+ );
15499
+ }
15500
+ if (!isValidTimestamp(params.endTime)) {
15501
+ throw new PolyVValidationError(
15502
+ "endTime is required and must be a valid timestamp",
15503
+ "endTime",
15504
+ params.endTime
15505
+ );
15506
+ }
15507
+ const rangeValidation = validate90DayTimestampRange(params.startTime, params.endTime);
15508
+ if (!rangeValidation.valid) {
15509
+ throw new PolyVValidationError(
15510
+ rangeValidation.error || "Invalid time range",
15511
+ "timeRange",
15512
+ { startTime: params.startTime, endTime: params.endTime, daysDiff: rangeValidation.daysDiff }
15513
+ );
15514
+ }
15515
+ }
15516
+ // ============================================
15517
+ // Viewlog Export API (Story 10.4)
15518
+ // ============================================
15519
+ /**
15520
+ * Get viewlog (viewing log) data
15521
+ *
15522
+ * Query viewing log data for a channel within a date range.
15523
+ * The date range must be within the same month.
15524
+ *
15525
+ * @param params - Query parameters
15526
+ * @returns Viewlog response with pagination
15527
+ * @throws {PolyVValidationError} When parameters are invalid
15528
+ *
15529
+ * @example
15530
+ * ```typescript
15531
+ * const result = await client.statistics.getViewlog({
15532
+ * channelId: '3151318',
15533
+ * startDate: '2024-01-01 00:00:00',
15534
+ * endDate: '2024-01-31 23:59:59',
15535
+ * });
15536
+ * console.log(result.contents);
15537
+ * ```
15538
+ */
15539
+ async getViewlog(params) {
15540
+ this.validateGetViewlogParams(params);
15541
+ const requestParams = {
15542
+ channelId: params.channelId,
15543
+ startDate: params.startDate,
15544
+ endDate: params.endDate,
15545
+ pageSize: params.pageSize ?? 1e3
15546
+ };
15547
+ if (params.page !== void 0) {
15548
+ requestParams.page = params.page;
15549
+ }
15550
+ if (params.watchType !== void 0) {
15551
+ requestParams.watchType = params.watchType;
15552
+ }
15553
+ const response = await this.client.httpClient.get(
15554
+ "/live/v3/user/statistics/viewlog",
15555
+ { params: requestParams }
15556
+ );
15557
+ if (response && typeof response === "object" && "data" in response) {
15558
+ const responseData = response;
15559
+ if (responseData.data && typeof responseData.data === "object") {
15560
+ return responseData.data;
15561
+ }
15562
+ }
15563
+ return response;
15564
+ }
15565
+ /**
15566
+ * Validate parameters for getViewlog
15567
+ */
15568
+ validateGetViewlogParams(params) {
15569
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15570
+ throw new PolyVValidationError(
15571
+ "channelId is required and must be a non-empty string",
15572
+ "channelId",
15573
+ params.channelId
15574
+ );
15575
+ }
15576
+ const dateTimeRegex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
15577
+ if (!params.startDate || !dateTimeRegex.test(params.startDate)) {
15578
+ throw new PolyVValidationError(
15579
+ "startDate is required and must be in yyyy-MM-dd HH:mm:ss format",
15580
+ "startDate",
15581
+ params.startDate
15582
+ );
15583
+ }
15584
+ if (!params.endDate || !dateTimeRegex.test(params.endDate)) {
15585
+ throw new PolyVValidationError(
15586
+ "endDate is required and must be in yyyy-MM-dd HH:mm:ss format",
15587
+ "endDate",
15588
+ params.endDate
15589
+ );
15590
+ }
15591
+ const startMonth = params.startDate.substring(0, 7);
15592
+ const endMonth = params.endDate.substring(0, 7);
15593
+ if (startMonth !== endMonth) {
15594
+ throw new PolyVValidationError(
15595
+ "startDate and endDate must be in the same month",
15596
+ "dateRange",
15597
+ { startDate: params.startDate, endDate: params.endDate }
15598
+ );
15599
+ }
15600
+ if (params.watchType !== void 0) {
15601
+ const validWatchTypes = ["live", "vod"];
15602
+ if (!validWatchTypes.includes(params.watchType)) {
15603
+ throw new PolyVValidationError(
15604
+ 'watchType must be either "live" or "vod"',
15605
+ "watchType",
15606
+ params.watchType
15607
+ );
15608
+ }
15609
+ }
15610
+ }
15611
+ // ============================================
15612
+ // Session Stats Export API (Story 10.4)
15613
+ // ============================================
15614
+ /**
15615
+ * Export session statistics report
15616
+ *
15617
+ * Export the session statistics report for a specific session.
15618
+ * Returns a download URL for the report file.
15619
+ *
15620
+ * @param params - Query parameters
15621
+ * @returns Export response with download URL
15622
+ * @throws {PolyVValidationError} When parameters are invalid
15623
+ *
15624
+ * @example
15625
+ * ```typescript
15626
+ * const result = await client.statistics.exportSessionStats({
15627
+ * channelId: '3151318',
15628
+ * sessionId: 'fv3ma84e63',
15629
+ * });
15630
+ * console.log(result.downloadUrl);
15631
+ * ```
15632
+ */
15633
+ async exportSessionStats(params) {
15634
+ this.validateExportSessionStatsParams(params);
15635
+ const response = await this.client.httpClient.get(
15636
+ "/live/v3/channel/session/stats/export",
15637
+ { params }
15638
+ );
15639
+ if (response && typeof response === "object" && "data" in response) {
15640
+ const responseData = response;
15641
+ if (responseData.data && typeof responseData.data === "object") {
15642
+ const innerData = responseData.data;
15643
+ if (innerData.code && innerData.code !== 200) {
15644
+ throw new Error(innerData.message || "API Error");
15645
+ }
15646
+ if ("downloadUrl" in innerData) {
15647
+ return innerData;
15648
+ }
15649
+ if (typeof innerData.data === "string" && innerData.data) {
15650
+ return { downloadUrl: innerData.data };
15651
+ }
15652
+ }
15653
+ }
15654
+ if (response && typeof response === "object" && "code" in response) {
15655
+ const apiResponse = response;
15656
+ if (apiResponse.code && apiResponse.code !== 200) {
15657
+ throw new Error(String(apiResponse.message || "API Error"));
15658
+ }
15659
+ if (typeof apiResponse.data === "string" && apiResponse.data) {
15660
+ return { downloadUrl: apiResponse.data };
15661
+ }
15662
+ }
15663
+ return response;
15664
+ }
15665
+ /**
15666
+ * Validate parameters for exportSessionStats
15667
+ */
15668
+ validateExportSessionStatsParams(params) {
15669
+ if (!params.channelId || typeof params.channelId !== "string" || params.channelId.trim() === "") {
15670
+ throw new PolyVValidationError(
15671
+ "channelId is required and must be a non-empty string",
15672
+ "channelId",
15673
+ params.channelId
15674
+ );
15675
+ }
15676
+ if (!params.sessionId || typeof params.sessionId !== "string" || params.sessionId.trim() === "") {
15677
+ throw new PolyVValidationError(
15678
+ "sessionId is required and must be a non-empty string",
15679
+ "sessionId",
15680
+ params.sessionId
15681
+ );
15682
+ }
15683
+ }
15684
+ };
15685
+
14842
15686
  // src/client.ts
14843
15687
  var DEFAULT_CONFIG = {
14844
15688
  baseUrl: "https://api.polyv.net",
@@ -14862,6 +15706,10 @@ var PolyVClient = class {
14862
15706
  * Channel service for managing live channels
14863
15707
  */
14864
15708
  channel;
15709
+ /**
15710
+ * Statistics service for managing statistics operations
15711
+ */
15712
+ statistics;
14865
15713
  /**
14866
15714
  * Chat service for managing chat messages
14867
15715
  */
@@ -14961,6 +15809,7 @@ var PolyVClient = class {
14961
15809
  };
14962
15810
  this.httpClient = this.createHttpClient();
14963
15811
  this.channel = new ChannelService(this);
15812
+ this.statistics = new StatisticsService(this);
14964
15813
  this.chat = new ChatService(this);
14965
15814
  this.liveInteraction = new LiveInteractionService(this);
14966
15815
  this.account = new AccountService(this);
@@ -15264,6 +16113,7 @@ exports.ChannelService = ChannelService;
15264
16113
  exports.ERROR_CATEGORIES = ERROR_CATEGORIES;
15265
16114
  exports.ERROR_MESSAGES = ERROR_MESSAGES;
15266
16115
  exports.HttpMethod = HttpMethod;
16116
+ exports.MAX_DATE_RANGE_DAYS = MAX_DATE_RANGE_DAYS;
15267
16117
  exports.PolyVAPIError = PolyVAPIError;
15268
16118
  exports.PolyVClient = PolyVClient;
15269
16119
  exports.PolyVError = PolyVError;
@@ -15288,8 +16138,11 @@ exports.isPolyVAPIError = isPolyVAPIError;
15288
16138
  exports.isPolyVError = isPolyVError;
15289
16139
  exports.isPolyVErrorCode = isPolyVErrorCode;
15290
16140
  exports.isPolyVValidationError = isPolyVValidationError;
16141
+ exports.isStartDateBeforeEndDate = isStartDateBeforeEndDate;
16142
+ exports.isValidDateFormat = isValidDateFormat;
15291
16143
  exports.isWebWorker = isWebWorker;
15292
16144
  exports.paginate = paginate;
15293
16145
  exports.sortParams = sortParams;
16146
+ exports.validateDateRange = validateDateRange;
15294
16147
  //# sourceMappingURL=index.cjs.map
15295
16148
  //# sourceMappingURL=index.cjs.map