@xhub-short/adapters 0.1.0-beta.9 → 1.0.0-beta.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +540 -19
  2. package/dist/index.js +673 -48
  3. package/package.json +4 -4
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { IDataSource, VideoItem, FeedResponse, ILogger, LogLevel, LogEntry, IStorage, ISessionStorage, SessionSnapshot, IInteraction, Comment, ICommentAdapter, MockCommentAdapterConfig, CommentListResponse, ReplyListResponse, PostCommentPayload, CommentItem, PostReplyPayload, ReplyItem, EditCommentPayload, DeleteCommentPayload, ReportCommentPayload, IAnalytics, AnalyticsEvent, INetworkAdapter, NetworkType, NetworkQuality, IVideoLoader, VideoSource, PreloadConfig, PreloadResult, PreloadStatus, IPosterLoader, CommentTransformers } from '@xhub-short/contracts';
1
+ import { IDataSource, ContentItem, FeedResponse, VideoItem, IPlaylistDataSource, PlaylistData, PlaylistCollectionResponse, ILogger, LogLevel, LogEntry, IStorage, ISessionStorage, SessionSnapshot, IInteraction, Comment, ICommentAdapter, MockCommentAdapterConfig, CommentListResponse, ReplyListResponse, PostCommentPayload, CommentItem, PostReplyPayload, ReplyItem, EditCommentPayload, DeleteCommentPayload, ReportCommentPayload, IAnalytics, AnalyticsEvent, INetworkAdapter, NetworkType, NetworkQuality, IPosterLoader, IVideoLoader, VideoSource, PreloadConfig, PreloadResult, PreloadStatus, ReportReason, CommentTransformers } from '@xhub-short/contracts';
2
2
 
3
3
  /**
4
4
  * MockDataAdapter - Development/Testing Data Source
@@ -13,16 +13,20 @@ import { IDataSource, VideoItem, FeedResponse, ILogger, LogLevel, LogEntry, ISto
13
13
  * ```
14
14
  */
15
15
  declare class MockDataAdapter implements IDataSource {
16
- private readonly videos;
16
+ private readonly items;
17
17
  private readonly pageSize;
18
18
  private readonly delay;
19
19
  constructor(options?: MockDataAdapterOptions);
20
20
  /**
21
- * Fetch a page of mock videos
21
+ * Fetch a page of mock items
22
22
  */
23
- fetchFeed(cursor?: string): Promise<FeedResponse>;
23
+ fetchFeed(cursor?: string): Promise<FeedResponse<ContentItem>>;
24
+ /**
25
+ * Get a single content item by ID
26
+ */
27
+ getContentDetail(id: string): Promise<ContentItem>;
24
28
  /**
25
- * Get a single video by ID
29
+ * @deprecated Use getContentDetail instead
26
30
  */
27
31
  getVideoDetail(id: string): Promise<VideoItem>;
28
32
  /**
@@ -38,14 +42,29 @@ declare class MockDataAdapter implements IDataSource {
38
42
  * Configuration options for MockDataAdapter
39
43
  */
40
44
  interface MockDataAdapterOptions {
41
- /** Custom mock video data */
42
- videos?: VideoItem[];
45
+ /** Custom mock content data */
46
+ items?: ContentItem[];
47
+ /** @deprecated Use items instead */
48
+ videos?: ContentItem[];
43
49
  /** Number of items per page (default: 3) */
44
50
  pageSize?: number;
45
51
  /** Simulated network delay in ms (default: 300) */
46
52
  delay?: number;
47
53
  }
48
54
 
55
+ /**
56
+ * MockPlaylistAdapter - Development/Testing Playlist Data Source
57
+ */
58
+ declare class MockPlaylistAdapter implements IPlaylistDataSource {
59
+ private readonly delay;
60
+ constructor(options?: {
61
+ delay?: number;
62
+ });
63
+ fetchPlaylist(id: string): Promise<PlaylistData>;
64
+ fetchPlaylistCollection(cursor?: string): Promise<PlaylistCollectionResponse>;
65
+ private simulateDelay;
66
+ }
67
+
49
68
  /**
50
69
  * Configuration options for MockLoggerAdapter
51
70
  */
@@ -446,9 +465,9 @@ declare class MockInteractionAdapter implements IInteraction {
446
465
  /**
447
466
  * Report a video
448
467
  *
449
- * @param _videoId - ID of the video to report
450
- * @param _reason - Report reason code
451
- * @param _description - Optional additional description
468
+ * @param videoId - ID of the video to report
469
+ * @param reason - Report reason code
470
+ * @param description - Optional additional description
452
471
  */
453
472
  report(_videoId: string, _reason: string, _description?: string): Promise<void>;
454
473
  /**
@@ -972,6 +991,22 @@ interface RESTEndpointMap {
972
991
  */
973
992
  detail: string;
974
993
  };
994
+ /**
995
+ * Playlist-related endpoints
996
+ */
997
+ playlist?: {
998
+ /**
999
+ * GET endpoint for playlist collection (listing)
1000
+ * Example: '/playlists'
1001
+ */
1002
+ list: string;
1003
+ /**
1004
+ * GET endpoint for playlist detail
1005
+ * :id will be replaced with playlist ID
1006
+ * Example: '/playlists/:id'
1007
+ */
1008
+ detail: string;
1009
+ };
975
1010
  /**
976
1011
  * Interaction endpoints
977
1012
  */
@@ -990,6 +1025,12 @@ interface RESTEndpointMap {
990
1025
  deleteComment: string;
991
1026
  /** POST /videos/:id/share (optional) */
992
1027
  share?: string;
1028
+ /** POST /content/:id/report (optional) */
1029
+ report?: string;
1030
+ /** GET /report-reasons (optional) */
1031
+ reportReasons?: string;
1032
+ /** POST /content/:id/not-interested (optional) */
1033
+ notInterested?: string;
993
1034
  };
994
1035
  /**
995
1036
  * Analytics endpoints (optional) - BATCH mode
@@ -1100,14 +1141,26 @@ interface RetryConfig {
1100
1141
  */
1101
1142
  exponentialBackoff?: boolean;
1102
1143
  }
1144
+ /**
1145
+ * Report reason from API
1146
+ */
1147
+ interface ReportReasonItem {
1148
+ id: string;
1149
+ label: string;
1150
+ description?: string;
1151
+ }
1103
1152
  /**
1104
1153
  * Response transform configuration
1105
1154
  */
1106
1155
  interface TransformConfig {
1107
1156
  /**
1108
- * Transform single video item from API response
1157
+ * Transform single content item from API response
1109
1158
  * If not provided, uses default transform
1110
1159
  */
1160
+ contentItem?: (apiResponse: unknown) => ContentItem;
1161
+ /**
1162
+ * @deprecated Use contentItem instead. Will be removed in v3.0
1163
+ */
1111
1164
  videoItem?: (apiResponse: unknown) => VideoItem;
1112
1165
  /**
1113
1166
  * Transform feed response from API
@@ -1118,6 +1171,51 @@ interface TransformConfig {
1118
1171
  nextCursor: string | null;
1119
1172
  hasMore: boolean;
1120
1173
  };
1174
+ /**
1175
+ * Transform playlist response from API
1176
+ * If not provided, uses default transform
1177
+ */
1178
+ playlist?: (apiResponse: unknown) => PlaylistData;
1179
+ /**
1180
+ * Transform playlist collection response from API
1181
+ * If not provided, uses default transform
1182
+ */
1183
+ playlistCollection?: (apiResponse: unknown) => PlaylistCollectionResponse;
1184
+ /**
1185
+ * Transform report reasons response from API
1186
+ * If not provided, uses default transform
1187
+ *
1188
+ * @example
1189
+ * ```ts
1190
+ * reportReasons: (response) => {
1191
+ * const data = response.data?.reasons || [];
1192
+ * return data.map(item => ({
1193
+ * id: item.id,
1194
+ * label: item.title,
1195
+ * description: item.description,
1196
+ * }));
1197
+ * }
1198
+ * ```
1199
+ */
1200
+ reportReasons?: (apiResponse: unknown) => ReportReasonItem[];
1201
+ /**
1202
+ * Transform report request body before sending to API
1203
+ * If not provided, uses default format: { reason, description }
1204
+ *
1205
+ * @example
1206
+ * ```ts
1207
+ * reportBody: ({ contentId, reasonId, description }) => ({
1208
+ * video_id: contentId,
1209
+ * reason_id: reasonId,
1210
+ * description: description || '',
1211
+ * })
1212
+ * ```
1213
+ */
1214
+ reportBody?: (input: {
1215
+ contentId: string;
1216
+ reasonId: string;
1217
+ description?: string;
1218
+ }) => Record<string, unknown>;
1121
1219
  /**
1122
1220
  * Field mapping for default transforms
1123
1221
  * Used when API field names differ from defaults
@@ -1134,6 +1232,11 @@ interface FieldMapConfig {
1134
1232
  * Example: { 'author.name': 'creator.display_name' }
1135
1233
  */
1136
1234
  video?: Record<string, string>;
1235
+ /**
1236
+ * Article field mapping
1237
+ * Example: { 'author.name': 'creator.display_name' }
1238
+ */
1239
+ article?: Record<string, string>;
1137
1240
  /**
1138
1241
  * FeedResponse field mapping
1139
1242
  */
@@ -1143,6 +1246,161 @@ interface FieldMapConfig {
1143
1246
  hasMore?: string;
1144
1247
  };
1145
1248
  }
1249
+ /**
1250
+ * Event types for batch analytics
1251
+ * Maps SDK internal types to API event types
1252
+ */
1253
+ type BatchAnalyticsEventType = 'view_start' | 'view_end' | 'scroll_pass' | 'like' | 'comment' | 'share' | 'follow_creator' | 'save' | 'report';
1254
+ /**
1255
+ * Device type for analytics context
1256
+ */
1257
+ type BatchAnalyticsDeviceType = 'ios' | 'android' | 'web';
1258
+ /**
1259
+ * Network type for analytics context
1260
+ */
1261
+ type BatchAnalyticsNetworkType = 'wifi' | '4g' | '5g' | 'other';
1262
+ /**
1263
+ * SDK internal analytics event data
1264
+ * Passed to transform function
1265
+ */
1266
+ interface BatchAnalyticsEventData {
1267
+ /** SDK event type (will be mapped to API event type) */
1268
+ sdkEventType: string;
1269
+ /** Video ID */
1270
+ videoId?: string;
1271
+ /** Event timestamp */
1272
+ timestamp: number;
1273
+ /** User ID (from setUser) */
1274
+ userId: string | null;
1275
+ /** User properties (from setUser) */
1276
+ userProperties: Record<string, unknown>;
1277
+ /** Additional event data from SDK */
1278
+ data?: Record<string, unknown>;
1279
+ }
1280
+ /**
1281
+ * Context data for analytics events
1282
+ * Provided by Host App via config
1283
+ */
1284
+ interface BatchAnalyticsContext {
1285
+ /** Get current session ID */
1286
+ getSessionId: () => string | null | Promise<string | null>;
1287
+ /** Get device type */
1288
+ getDeviceType: () => BatchAnalyticsDeviceType;
1289
+ /** Get network type */
1290
+ getNetworkType: () => BatchAnalyticsNetworkType | Promise<BatchAnalyticsNetworkType>;
1291
+ /** Get geo location (optional) */
1292
+ getGeoLocation?: () => string | null | Promise<string | null>;
1293
+ /** Get current video position index in feed */
1294
+ getPositionIndex?: () => number;
1295
+ /** Get scroll speed in ms (optional) */
1296
+ getScrollSpeed?: () => number | null;
1297
+ }
1298
+ /**
1299
+ * Single event in batch request body (after transform)
1300
+ */
1301
+ type BatchAnalyticsRequestEvent = Record<string, unknown>;
1302
+ /**
1303
+ * Full request body for batch analytics
1304
+ */
1305
+ interface BatchAnalyticsRequestBody {
1306
+ events: BatchAnalyticsRequestEvent[];
1307
+ }
1308
+ /**
1309
+ * Transform function to convert SDK event to API event format
1310
+ *
1311
+ * @example
1312
+ * ```typescript
1313
+ * const transform: BatchAnalyticsEventTransformer = async (event, context) => ({
1314
+ * event_id: crypto.randomUUID(),
1315
+ * user_id: event.userId,
1316
+ * video_id: event.videoId,
1317
+ * session_id: await context.getSessionId(),
1318
+ * event_type: mapEventType(event.sdkEventType),
1319
+ * position_index: context.getPositionIndex?.() ?? 0,
1320
+ * impression_timestamp: new Date(event.timestamp).toISOString(),
1321
+ * scroll_speed_ms: context.getScrollSpeed?.() ?? null,
1322
+ * device_type: context.getDeviceType(),
1323
+ * network_type: await context.getNetworkType(),
1324
+ * geo_location: await context.getGeoLocation?.() ?? null,
1325
+ * time_of_day: new Date(event.timestamp).getHours(),
1326
+ * day_of_week: new Date(event.timestamp).getDay(),
1327
+ * });
1328
+ * ```
1329
+ */
1330
+ type BatchAnalyticsEventTransformer = (event: BatchAnalyticsEventData, context: BatchAnalyticsContext) => BatchAnalyticsRequestEvent | Promise<BatchAnalyticsRequestEvent>;
1331
+ /**
1332
+ * Batch analytics configuration for preset
1333
+ *
1334
+ * @example
1335
+ * ```typescript
1336
+ * const batchAnalytics: BatchAnalyticsConfig = {
1337
+ * batchSize: 10,
1338
+ * flushInterval: 30000,
1339
+ * context: {
1340
+ * getSessionId: () => sessionStorage.getItem('session_id'),
1341
+ * getDeviceType: () => 'web',
1342
+ * getNetworkType: () => navigator.connection?.effectiveType === '4g' ? '4g' : 'wifi',
1343
+ * getGeoLocation: () => 'Ho Chi Minh City, Vietnam',
1344
+ * getPositionIndex: () => currentIndex,
1345
+ * },
1346
+ * transform: async (event, ctx) => ({
1347
+ * event_id: crypto.randomUUID(),
1348
+ * user_id: event.userId,
1349
+ * video_id: event.videoId,
1350
+ * session_id: await ctx.getSessionId(),
1351
+ * event_type: event.sdkEventType,
1352
+ * // ... more fields
1353
+ * }),
1354
+ * };
1355
+ * ```
1356
+ */
1357
+ interface BatchAnalyticsConfig {
1358
+ /**
1359
+ * Batch size threshold for auto-flush
1360
+ * @default 10
1361
+ */
1362
+ batchSize?: number;
1363
+ /**
1364
+ * Flush interval in milliseconds
1365
+ * @default 30000 (30 seconds)
1366
+ */
1367
+ flushInterval?: number;
1368
+ /**
1369
+ * Context providers for enriching events
1370
+ * Required if using custom transform
1371
+ */
1372
+ context?: BatchAnalyticsContext;
1373
+ /**
1374
+ * Custom transform function
1375
+ * If not provided, uses default SDK format
1376
+ */
1377
+ transform?: BatchAnalyticsEventTransformer;
1378
+ /**
1379
+ * Map SDK event types to API event types
1380
+ * Used by default transform if no custom transform provided
1381
+ *
1382
+ * @example
1383
+ * ```typescript
1384
+ * eventTypeMap: {
1385
+ * 'video_view': 'view_start',
1386
+ * 'video_complete': 'view_end',
1387
+ * 'scroll': 'scroll_pass',
1388
+ * 'like': 'like',
1389
+ * 'follow': 'follow_creator',
1390
+ * }
1391
+ * ```
1392
+ */
1393
+ eventTypeMap?: Record<string, BatchAnalyticsEventType>;
1394
+ /**
1395
+ * Use sendBeacon API for flushing events
1396
+ *
1397
+ * sendBeacon is more reliable for page unload events but shows as "ping" in Network tab.
1398
+ * Set to false to always use HTTP POST (easier for debugging).
1399
+ *
1400
+ * @default true
1401
+ */
1402
+ useSendBeacon?: boolean;
1403
+ }
1146
1404
  /**
1147
1405
  * View event data passed to transformer
1148
1406
  */
@@ -1238,6 +1496,30 @@ interface RESTPresetConfig {
1238
1496
  * Only used if endpoints.viewTracking is configured
1239
1497
  */
1240
1498
  viewTracking?: ViewTrackingConfig;
1499
+ /**
1500
+ * Batch analytics configuration (optional)
1501
+ * Only used if endpoints.analytics is configured
1502
+ *
1503
+ * @example
1504
+ * ```typescript
1505
+ * batchAnalytics: {
1506
+ * batchSize: 10,
1507
+ * flushInterval: 30000,
1508
+ * context: {
1509
+ * getSessionId: () => sessionStorage.getItem('session_id'),
1510
+ * getDeviceType: () => 'web',
1511
+ * getNetworkType: () => 'wifi',
1512
+ * },
1513
+ * transform: (event, ctx) => ({
1514
+ * event_id: crypto.randomUUID(),
1515
+ * user_id: event.userId,
1516
+ * video_id: event.videoId,
1517
+ * // ... custom format
1518
+ * }),
1519
+ * }
1520
+ * ```
1521
+ */
1522
+ batchAnalytics?: BatchAnalyticsConfig;
1241
1523
  /**
1242
1524
  * Logger adapter for error/warning logging
1243
1525
  * If not provided, uses console in dev, silent in prod
@@ -1251,6 +1533,8 @@ interface PresetAdapters {
1251
1533
  dataSource: IDataSource;
1252
1534
  interaction: IInteraction;
1253
1535
  analytics: IAnalytics;
1536
+ /** Playlist adapter (optional) */
1537
+ playlist?: IPlaylistDataSource;
1254
1538
  /** Comment adapter (only if comment endpoints are configured) */
1255
1539
  comment?: ICommentAdapter;
1256
1540
  }
@@ -1520,6 +1804,13 @@ declare class LocalStorageAdapter implements IStorage {
1520
1804
  * Clear all SDK-namespaced keys
1521
1805
  */
1522
1806
  clear(): Promise<void>;
1807
+ /**
1808
+ * Get a value from localStorage synchronously
1809
+ *
1810
+ * Used for zero-flash cache hydration during React render phase.
1811
+ * localStorage is inherently synchronous, so this bypasses the async wrapper.
1812
+ */
1813
+ getSync<T>(key: string): T | null;
1523
1814
  /**
1524
1815
  * Get all SDK-namespaced keys
1525
1816
  */
@@ -1718,6 +2009,8 @@ interface FullPresetAdapters {
1718
2009
  videoLoader: IVideoLoader;
1719
2010
  /** Poster preloader (Image) */
1720
2011
  posterLoader: IPosterLoader;
2012
+ /** Playlist adapter (REST API, optional) */
2013
+ playlist?: IPlaylistDataSource;
1721
2014
  /** Comment adapter (REST API, only if comment endpoints configured) */
1722
2015
  comment?: ICommentAdapter;
1723
2016
  /** Logger (passed through) */
@@ -1812,6 +2105,10 @@ declare class HttpClient {
1812
2105
  private readonly config;
1813
2106
  private readonly retryConfig;
1814
2107
  private readonly requestConfig;
2108
+ /**
2109
+ * Get base URL (for sendBeacon which needs full URL)
2110
+ */
2111
+ getBaseUrl(): string;
1815
2112
  private isRefreshing;
1816
2113
  private refreshPromise;
1817
2114
  constructor(config: HttpClientConfig);
@@ -1905,12 +2202,17 @@ declare function defaultFeedResponseTransform(apiResponse: unknown, fieldMap?: F
1905
2202
  * Create transforms with custom overrides
1906
2203
  */
1907
2204
  interface ResolvedTransforms {
2205
+ /** Map raw API item to ContentItem (Video or Article) */
2206
+ contentItem: (data: unknown) => ContentItem;
2207
+ /** @deprecated Use contentItem instead */
1908
2208
  videoItem: (data: unknown) => VideoItem;
1909
2209
  feedResponse: (data: unknown) => {
1910
2210
  items: unknown[];
1911
2211
  nextCursor: string | null;
1912
2212
  hasMore: boolean;
1913
2213
  };
2214
+ playlist: (data: unknown) => PlaylistData;
2215
+ playlistCollection: (data: unknown) => PlaylistCollectionResponse;
1914
2216
  }
1915
2217
  declare function createTransforms(config?: TransformConfig, logger?: ILogger): ResolvedTransforms;
1916
2218
 
@@ -1918,8 +2220,8 @@ declare function createTransforms(config?: TransformConfig, logger?: ILogger): R
1918
2220
  * REST Data Adapter - IDataSource implementation for REST APIs
1919
2221
  *
1920
2222
  * Implements:
1921
- * - fetchFeed: GET /videos with pagination
1922
- * - getVideoDetail: GET /videos/:id
2223
+ * - fetchFeed: GET /items with pagination
2224
+ * - getContentDetail: GET /items/:id
1923
2225
  * - prefetch: Optional prefetch support
1924
2226
  */
1925
2227
 
@@ -1948,11 +2250,15 @@ declare class RESTDataAdapter implements IDataSource {
1948
2250
  */
1949
2251
  fetchFeed(cursor?: string): Promise<FeedResponse>;
1950
2252
  /**
1951
- * Get video detail by ID
2253
+ * Get content detail by ID
2254
+ */
2255
+ getContentDetail(id: string): Promise<ContentItem>;
2256
+ /**
2257
+ * @deprecated Use getContentDetail instead
1952
2258
  */
1953
2259
  getVideoDetail(id: string): Promise<VideoItem>;
1954
2260
  /**
1955
- * Optional: Prefetch videos
2261
+ * Optional: Prefetch content
1956
2262
  * This is a no-op by default, can be overridden if API supports batch fetch
1957
2263
  */
1958
2264
  prefetch(ids: string[]): Promise<void>;
@@ -1961,9 +2267,9 @@ declare class RESTDataAdapter implements IDataSource {
1961
2267
  */
1962
2268
  private unwrapResponse;
1963
2269
  /**
1964
- * Create fallback video item when transform fails
2270
+ * Create fallback content item when transform fails
1965
2271
  */
1966
- private createFallbackVideoItem;
2272
+ private createFallbackItem;
1967
2273
  }
1968
2274
 
1969
2275
  /**
@@ -1976,6 +2282,14 @@ declare class RESTDataAdapter implements IDataSource {
1976
2282
  * - share (optional)
1977
2283
  */
1978
2284
 
2285
+ /**
2286
+ * Report body input from SDK
2287
+ */
2288
+ interface ReportBodyInput {
2289
+ contentId: string;
2290
+ reasonId: string;
2291
+ description?: string;
2292
+ }
1979
2293
  /**
1980
2294
  * REST Interaction Adapter configuration
1981
2295
  */
@@ -1983,6 +2297,10 @@ interface RESTInteractionAdapterConfig {
1983
2297
  httpClient: HttpClient;
1984
2298
  endpoints: RESTEndpointMap['interaction'];
1985
2299
  logger?: ILogger;
2300
+ /** Custom transform for report reasons response */
2301
+ transformReportReasons?: (apiResponse: unknown) => ReportReasonItem[];
2302
+ /** Custom transform for report request body */
2303
+ transformReportBody?: (input: ReportBodyInput) => Record<string, unknown>;
1986
2304
  }
1987
2305
  /**
1988
2306
  * REST Interaction Adapter
@@ -1991,6 +2309,8 @@ declare class RESTInteractionAdapter implements IInteraction {
1991
2309
  private readonly httpClient;
1992
2310
  private readonly endpoints;
1993
2311
  private readonly logger?;
2312
+ private readonly customTransformReportReasons?;
2313
+ private readonly customTransformReportBody?;
1994
2314
  constructor(config: RESTInteractionAdapterConfig);
1995
2315
  /**
1996
2316
  * Like a video
@@ -2028,6 +2348,38 @@ declare class RESTInteractionAdapter implements IInteraction {
2028
2348
  * Share a video (optional tracking)
2029
2349
  */
2030
2350
  share(videoId: string, platform?: string): Promise<void>;
2351
+ /**
2352
+ * Report content (video or image post)
2353
+ *
2354
+ * @param contentId - ID of the content to report
2355
+ * @param reason - Report reason code/ID
2356
+ * @param description - Optional additional description
2357
+ */
2358
+ report(contentId: string, reason: string, description?: string): Promise<void>;
2359
+ /**
2360
+ * Get available report reasons
2361
+ *
2362
+ * @returns Array of report reasons, or empty array if not configured
2363
+ */
2364
+ getReportReasons(): Promise<ReportReason[]>;
2365
+ /**
2366
+ * Mark content as "not interested"
2367
+ *
2368
+ * Used for recommendation algorithm feedback.
2369
+ * Content should be hidden from feed after this action.
2370
+ *
2371
+ * @param contentId - ID of the content (video or image post)
2372
+ */
2373
+ notInterested(contentId: string): Promise<void>;
2374
+ /**
2375
+ * Default transform for API report reasons response to ReportReason[]
2376
+ *
2377
+ * Expected format: [{ id, label, description }]
2378
+ * Or wrapped: { data: [{ id, label, description }] }
2379
+ *
2380
+ * For custom API formats, use `transforms.reportReasons` in preset config.
2381
+ */
2382
+ private transformReportReasons;
2031
2383
  /**
2032
2384
  * Transform API comment response to Comment type
2033
2385
  */
@@ -2045,6 +2397,34 @@ declare class RESTInteractionAdapter implements IInteraction {
2045
2397
  * - Events queued internally
2046
2398
  * - Flush conditions: queue > 10, video change, visibility change
2047
2399
  * - Uses sendBeacon for reliability when available
2400
+ *
2401
+ * Supports custom transform for flexible API formats:
2402
+ * - Default: SDK format { events: [...] }
2403
+ * - Custom: Any format via transform function
2404
+ *
2405
+ * @example
2406
+ * ```typescript
2407
+ * // With custom transform for specific API format
2408
+ * const adapter = new RESTAnalyticsAdapter({
2409
+ * httpClient,
2410
+ * endpoints: { batch: '/api/v1/events/track-batch' },
2411
+ * config: {
2412
+ * context: {
2413
+ * getSessionId: () => sessionStorage.getItem('session_id'),
2414
+ * getDeviceType: () => 'web',
2415
+ * getNetworkType: () => 'wifi',
2416
+ * },
2417
+ * transform: async (event, ctx) => ({
2418
+ * event_id: crypto.randomUUID(),
2419
+ * user_id: event.userId,
2420
+ * video_id: event.videoId,
2421
+ * session_id: await ctx.getSessionId(),
2422
+ * event_type: event.sdkEventType,
2423
+ * // ... more fields
2424
+ * }),
2425
+ * },
2426
+ * });
2427
+ * ```
2048
2428
  */
2049
2429
 
2050
2430
  /**
@@ -2053,22 +2433,35 @@ declare class RESTInteractionAdapter implements IInteraction {
2053
2433
  interface RESTAnalyticsAdapterConfig {
2054
2434
  httpClient: HttpClient;
2055
2435
  endpoints: NonNullable<RESTEndpointMap['analytics']>;
2436
+ /** Batch analytics config with transform and context */
2437
+ config?: BatchAnalyticsConfig;
2438
+ /** @deprecated Use config.batchSize instead */
2056
2439
  batchSize?: number;
2440
+ /** @deprecated Use config.flushInterval instead */
2057
2441
  flushInterval?: number;
2058
2442
  logger?: ILogger;
2059
2443
  }
2060
2444
  /**
2061
2445
  * REST Analytics Adapter
2446
+ *
2447
+ * Supports two modes:
2448
+ * 1. Default mode: Uses SDK format { events: [...] }
2449
+ * 2. Custom mode: Uses transform function for custom API format
2062
2450
  */
2063
2451
  declare class RESTAnalyticsAdapter implements IAnalytics {
2064
2452
  private readonly httpClient;
2065
2453
  private readonly endpoint;
2066
2454
  private readonly batchSize;
2067
2455
  private readonly logger?;
2456
+ private readonly transform?;
2457
+ private readonly context;
2458
+ private readonly eventTypeMap;
2459
+ private readonly useSendBeacon;
2068
2460
  private queue;
2069
2461
  private flushTimer;
2070
2462
  private userId;
2071
2463
  private userProperties;
2464
+ private viewedVideos;
2072
2465
  constructor(config: RESTAnalyticsAdapterConfig);
2073
2466
  /**
2074
2467
  * Track an analytics event
@@ -2080,9 +2473,23 @@ declare class RESTAnalyticsAdapter implements IAnalytics {
2080
2473
  */
2081
2474
  flush(): Promise<void>;
2082
2475
  /**
2083
- * Track video view duration (heartbeat)
2476
+ * Build request body from events
2477
+ * Uses custom transform if provided, otherwise SDK default format
2478
+ */
2479
+ private buildRequestBody;
2480
+ /**
2481
+ * Track video view duration
2482
+ *
2483
+ * Note: PlayerEngine calls this every second (heartbeat), but for batch analytics
2484
+ * we only need ONE view_start per video. This method deduplicates by videoId.
2485
+ *
2486
+ * If you need heartbeat tracking, use RESTViewTrackingAdapter instead.
2084
2487
  */
2085
2488
  trackViewDuration(videoId: string, duration: number, totalDuration: number): void;
2489
+ /**
2490
+ * Clear viewed videos cache (useful for testing or session reset)
2491
+ */
2492
+ clearViewedVideos(): void;
2086
2493
  /**
2087
2494
  * Track video completion
2088
2495
  */
@@ -2101,12 +2508,23 @@ declare class RESTAnalyticsAdapter implements IAnalytics {
2101
2508
  destroy(): void;
2102
2509
  /**
2103
2510
  * Try to send via sendBeacon (for reliability on page unload)
2511
+ * Note: sendBeacon shows as "ping" type in Network tab, not "POST"
2512
+ *
2513
+ * Set useSendBeacon: false in config to always use HTTP POST
2104
2514
  */
2105
2515
  private trySendBeacon;
2106
2516
  /**
2107
2517
  * Build full URL for sendBeacon
2108
2518
  */
2109
2519
  private buildFullUrl;
2520
+ /**
2521
+ * Get mapped API event type from SDK event type
2522
+ */
2523
+ getApiEventType(sdkEventType: string): BatchAnalyticsEventType;
2524
+ /**
2525
+ * Get current context (for debugging/testing)
2526
+ */
2527
+ getContext(): BatchAnalyticsContext;
2110
2528
  }
2111
2529
  /**
2112
2530
  * Create a no-op analytics adapter
@@ -2114,6 +2532,109 @@ declare class RESTAnalyticsAdapter implements IAnalytics {
2114
2532
  */
2115
2533
  declare function createNoOpAnalyticsAdapter(): IAnalytics;
2116
2534
 
2535
+ /**
2536
+ * REST View Tracking Adapter - Per-video view tracking via REST API
2537
+ *
2538
+ * Implements IAnalytics interface with throttled, fire-and-forget tracking.
2539
+ * Uses shared HttpClient from preset (auth, retry, timeout).
2540
+ *
2541
+ * @example
2542
+ * ```typescript
2543
+ * // Created automatically by createRESTAdapters when viewTracking is configured
2544
+ * const adapters = createRESTAdapters({
2545
+ * baseUrl: 'https://api.myapp.com/v1',
2546
+ * auth: { ... },
2547
+ * endpoints: {
2548
+ * feed: { ... },
2549
+ * interaction: { ... },
2550
+ * viewTracking: {
2551
+ * notify: '/reels/:id/notify-views',
2552
+ * },
2553
+ * },
2554
+ * });
2555
+ * ```
2556
+ */
2557
+
2558
+ /**
2559
+ * REST View Tracking Adapter configuration
2560
+ */
2561
+ interface RESTViewTrackingAdapterConfig {
2562
+ httpClient: HttpClient;
2563
+ endpoint: NonNullable<RESTEndpointMap['viewTracking']>;
2564
+ config?: ViewTrackingConfig;
2565
+ logger?: ILogger;
2566
+ }
2567
+ /**
2568
+ * RESTViewTrackingAdapter - Per-video view tracking via REST API
2569
+ *
2570
+ * Uses shared HttpClient (inherits auth, retry, timeout from preset).
2571
+ * Implements throttled, fire-and-forget tracking.
2572
+ */
2573
+ declare class RESTViewTrackingAdapter implements IAnalytics {
2574
+ private readonly httpClient;
2575
+ private readonly endpoint;
2576
+ private readonly transform;
2577
+ private readonly viewEventValue;
2578
+ private readonly heartbeatInterval;
2579
+ private readonly minWatchTime;
2580
+ private readonly trackLeaveEnabled;
2581
+ private readonly logger?;
2582
+ private lastTrackTime;
2583
+ private lastEventType;
2584
+ private _userId;
2585
+ private _userProperties;
2586
+ /** Get current user ID */
2587
+ get userId(): string | null;
2588
+ /** Get current user properties */
2589
+ get userProperties(): Record<string, unknown>;
2590
+ constructor(config: RESTViewTrackingAdapterConfig);
2591
+ /**
2592
+ * Track generic event
2593
+ * Delegates video events to specific handlers
2594
+ */
2595
+ track(event: AnalyticsEvent): void;
2596
+ /**
2597
+ * Flush - No-op since we send events immediately (fire-and-forget)
2598
+ */
2599
+ flush(): Promise<void>;
2600
+ /**
2601
+ * Track view duration (heartbeat)
2602
+ * Called periodically during video playback
2603
+ */
2604
+ trackViewDuration(videoId: string, duration: number, totalDuration: number): void;
2605
+ /**
2606
+ * Track video completion
2607
+ * Called when video ends or loops
2608
+ */
2609
+ trackCompletion(videoId: string, watchTime: number, loopCount: number): void;
2610
+ /**
2611
+ * Set user context
2612
+ */
2613
+ setUser(userId: string | null, properties?: Record<string, unknown>): void;
2614
+ /**
2615
+ * Get queue size (always 0 - no batching)
2616
+ */
2617
+ getQueueSize(): number;
2618
+ /**
2619
+ * Track when user leaves video
2620
+ * Called when user scrolls to another video
2621
+ */
2622
+ trackLeaveVideo(videoId: string, currentTime: number, duration: number): void;
2623
+ /**
2624
+ * Clear tracking state for a video
2625
+ * Call when video is removed from viewport
2626
+ */
2627
+ clearVideoState(videoId: string): void;
2628
+ /**
2629
+ * Clear all tracking state
2630
+ */
2631
+ reset(): void;
2632
+ /**
2633
+ * Send view event to API (fire-and-forget)
2634
+ */
2635
+ private sendViewEvent;
2636
+ }
2637
+
2117
2638
  /**
2118
2639
  * REST Comment Adapter - ICommentAdapter implementation for REST APIs
2119
2640
  *
@@ -2228,4 +2749,4 @@ declare class RESTCommentAdapter implements ICommentAdapter {
2228
2749
  private unwrapResponse;
2229
2750
  }
2230
2751
 
2231
- export { type AuthConfig, type AuthError, type BrowserAdaptersConfig, BrowserPosterLoader, BrowserVideoLoader, type BrowserVideoLoaderConfig, DEFAULT_REQUEST_CONFIG, DEFAULT_RETRY_CONFIG, type FieldMapConfig, type FullPresetAdapters, HttpClient, HttpError, LocalSessionStorageAdapter, LocalStorageAdapter, type LocalStorageConfig, MockAnalyticsAdapter, type MockAnalyticsAdapterOptions, MockCommentAdapter, MockDataAdapter, type MockDataAdapterOptions, MockInteractionAdapter, type MockInteractionAdapterOptions, MockLoggerAdapter, type MockLoggerAdapterOptions, MockNetworkAdapter, type MockNetworkAdapterOptions, MockPosterLoader, MockSessionStorageAdapter, type MockSessionStorageAdapterOptions, MockStorageAdapter, type MockStorageAdapterOptions, MockVideoLoader, type MockVideoLoaderOptions, type PresetAdapters, RESTAnalyticsAdapter, RESTCommentAdapter, type RESTCommentAdapterConfig, RESTDataAdapter, type RESTEndpointMap, RESTInteractionAdapter, type RESTPresetConfig, type RESTRequestConfig, type ResolvedTransforms, type RetryConfig, type TransformConfig, WebNetworkAdapter, type WebNetworkConfig, createBrowserAdapters, createBrowserPosterLoader, createBrowserVideoLoader, createLocalStorageAdapter, createNoOpAnalyticsAdapter, createRESTAdapters, createSessionStorageAdapter, createTransforms, createWebNetworkAdapter, defaultFeedResponseTransform, defaultVideoItemTransform };
2752
+ export { type AuthConfig, type AuthError, type BatchAnalyticsConfig, type BatchAnalyticsContext, type BatchAnalyticsDeviceType, type BatchAnalyticsEventData, type BatchAnalyticsEventTransformer, type BatchAnalyticsEventType, type BatchAnalyticsNetworkType, type BatchAnalyticsRequestBody, type BatchAnalyticsRequestEvent, type BrowserAdaptersConfig, BrowserPosterLoader, BrowserVideoLoader, type BrowserVideoLoaderConfig, DEFAULT_REQUEST_CONFIG, DEFAULT_RETRY_CONFIG, type FieldMapConfig, type FullPresetAdapters, HttpClient, HttpError, LocalSessionStorageAdapter, LocalStorageAdapter, type LocalStorageConfig, MockAnalyticsAdapter, type MockAnalyticsAdapterOptions, MockCommentAdapter, MockDataAdapter, type MockDataAdapterOptions, MockInteractionAdapter, type MockInteractionAdapterOptions, MockLoggerAdapter, type MockLoggerAdapterOptions, MockNetworkAdapter, type MockNetworkAdapterOptions, MockPlaylistAdapter, MockPosterLoader, MockSessionStorageAdapter, type MockSessionStorageAdapterOptions, MockStorageAdapter, type MockStorageAdapterOptions, MockVideoLoader, type MockVideoLoaderOptions, type PresetAdapters, RESTAnalyticsAdapter, type RESTAnalyticsAdapterConfig, RESTCommentAdapter, type RESTCommentAdapterConfig, RESTDataAdapter, type RESTEndpointMap, RESTInteractionAdapter, type RESTPresetConfig, type RESTRequestConfig, RESTViewTrackingAdapter, type RESTViewTrackingAdapterConfig, type ResolvedTransforms, type RetryConfig, type TransformConfig, type ViewEventData, type ViewEventRequestBody, type ViewEventTransformer, type ViewTrackingConfig, WebNetworkAdapter, type WebNetworkConfig, createBrowserAdapters, createBrowserPosterLoader, createBrowserVideoLoader, createLocalStorageAdapter, createNoOpAnalyticsAdapter, createRESTAdapters, createSessionStorageAdapter, createTransforms, createWebNetworkAdapter, defaultFeedResponseTransform, defaultVideoItemTransform };