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

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 +544 -19
  2. package/dist/index.js +688 -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,14 @@ 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;
2112
+ /**
2113
+ * Check if access token is available
2114
+ */
2115
+ hasAccessToken(): Promise<boolean>;
1815
2116
  private isRefreshing;
1816
2117
  private refreshPromise;
1817
2118
  constructor(config: HttpClientConfig);
@@ -1905,12 +2206,17 @@ declare function defaultFeedResponseTransform(apiResponse: unknown, fieldMap?: F
1905
2206
  * Create transforms with custom overrides
1906
2207
  */
1907
2208
  interface ResolvedTransforms {
2209
+ /** Map raw API item to ContentItem (Video or Article) */
2210
+ contentItem: (data: unknown) => ContentItem;
2211
+ /** @deprecated Use contentItem instead */
1908
2212
  videoItem: (data: unknown) => VideoItem;
1909
2213
  feedResponse: (data: unknown) => {
1910
2214
  items: unknown[];
1911
2215
  nextCursor: string | null;
1912
2216
  hasMore: boolean;
1913
2217
  };
2218
+ playlist: (data: unknown) => PlaylistData;
2219
+ playlistCollection: (data: unknown) => PlaylistCollectionResponse;
1914
2220
  }
1915
2221
  declare function createTransforms(config?: TransformConfig, logger?: ILogger): ResolvedTransforms;
1916
2222
 
@@ -1918,8 +2224,8 @@ declare function createTransforms(config?: TransformConfig, logger?: ILogger): R
1918
2224
  * REST Data Adapter - IDataSource implementation for REST APIs
1919
2225
  *
1920
2226
  * Implements:
1921
- * - fetchFeed: GET /videos with pagination
1922
- * - getVideoDetail: GET /videos/:id
2227
+ * - fetchFeed: GET /items with pagination
2228
+ * - getContentDetail: GET /items/:id
1923
2229
  * - prefetch: Optional prefetch support
1924
2230
  */
1925
2231
 
@@ -1948,11 +2254,15 @@ declare class RESTDataAdapter implements IDataSource {
1948
2254
  */
1949
2255
  fetchFeed(cursor?: string): Promise<FeedResponse>;
1950
2256
  /**
1951
- * Get video detail by ID
2257
+ * Get content detail by ID
2258
+ */
2259
+ getContentDetail(id: string): Promise<ContentItem>;
2260
+ /**
2261
+ * @deprecated Use getContentDetail instead
1952
2262
  */
1953
2263
  getVideoDetail(id: string): Promise<VideoItem>;
1954
2264
  /**
1955
- * Optional: Prefetch videos
2265
+ * Optional: Prefetch content
1956
2266
  * This is a no-op by default, can be overridden if API supports batch fetch
1957
2267
  */
1958
2268
  prefetch(ids: string[]): Promise<void>;
@@ -1961,9 +2271,9 @@ declare class RESTDataAdapter implements IDataSource {
1961
2271
  */
1962
2272
  private unwrapResponse;
1963
2273
  /**
1964
- * Create fallback video item when transform fails
2274
+ * Create fallback content item when transform fails
1965
2275
  */
1966
- private createFallbackVideoItem;
2276
+ private createFallbackItem;
1967
2277
  }
1968
2278
 
1969
2279
  /**
@@ -1976,6 +2286,14 @@ declare class RESTDataAdapter implements IDataSource {
1976
2286
  * - share (optional)
1977
2287
  */
1978
2288
 
2289
+ /**
2290
+ * Report body input from SDK
2291
+ */
2292
+ interface ReportBodyInput {
2293
+ contentId: string;
2294
+ reasonId: string;
2295
+ description?: string;
2296
+ }
1979
2297
  /**
1980
2298
  * REST Interaction Adapter configuration
1981
2299
  */
@@ -1983,6 +2301,10 @@ interface RESTInteractionAdapterConfig {
1983
2301
  httpClient: HttpClient;
1984
2302
  endpoints: RESTEndpointMap['interaction'];
1985
2303
  logger?: ILogger;
2304
+ /** Custom transform for report reasons response */
2305
+ transformReportReasons?: (apiResponse: unknown) => ReportReasonItem[];
2306
+ /** Custom transform for report request body */
2307
+ transformReportBody?: (input: ReportBodyInput) => Record<string, unknown>;
1986
2308
  }
1987
2309
  /**
1988
2310
  * REST Interaction Adapter
@@ -1991,6 +2313,8 @@ declare class RESTInteractionAdapter implements IInteraction {
1991
2313
  private readonly httpClient;
1992
2314
  private readonly endpoints;
1993
2315
  private readonly logger?;
2316
+ private readonly customTransformReportReasons?;
2317
+ private readonly customTransformReportBody?;
1994
2318
  constructor(config: RESTInteractionAdapterConfig);
1995
2319
  /**
1996
2320
  * Like a video
@@ -2028,6 +2352,38 @@ declare class RESTInteractionAdapter implements IInteraction {
2028
2352
  * Share a video (optional tracking)
2029
2353
  */
2030
2354
  share(videoId: string, platform?: string): Promise<void>;
2355
+ /**
2356
+ * Report content (video or image post)
2357
+ *
2358
+ * @param contentId - ID of the content to report
2359
+ * @param reason - Report reason code/ID
2360
+ * @param description - Optional additional description
2361
+ */
2362
+ report(contentId: string, reason: string, description?: string): Promise<void>;
2363
+ /**
2364
+ * Get available report reasons
2365
+ *
2366
+ * @returns Array of report reasons, or empty array if not configured
2367
+ */
2368
+ getReportReasons(): Promise<ReportReason[]>;
2369
+ /**
2370
+ * Mark content as "not interested"
2371
+ *
2372
+ * Used for recommendation algorithm feedback.
2373
+ * Content should be hidden from feed after this action.
2374
+ *
2375
+ * @param contentId - ID of the content (video or image post)
2376
+ */
2377
+ notInterested(contentId: string): Promise<void>;
2378
+ /**
2379
+ * Default transform for API report reasons response to ReportReason[]
2380
+ *
2381
+ * Expected format: [{ id, label, description }]
2382
+ * Or wrapped: { data: [{ id, label, description }] }
2383
+ *
2384
+ * For custom API formats, use `transforms.reportReasons` in preset config.
2385
+ */
2386
+ private transformReportReasons;
2031
2387
  /**
2032
2388
  * Transform API comment response to Comment type
2033
2389
  */
@@ -2045,6 +2401,34 @@ declare class RESTInteractionAdapter implements IInteraction {
2045
2401
  * - Events queued internally
2046
2402
  * - Flush conditions: queue > 10, video change, visibility change
2047
2403
  * - Uses sendBeacon for reliability when available
2404
+ *
2405
+ * Supports custom transform for flexible API formats:
2406
+ * - Default: SDK format { events: [...] }
2407
+ * - Custom: Any format via transform function
2408
+ *
2409
+ * @example
2410
+ * ```typescript
2411
+ * // With custom transform for specific API format
2412
+ * const adapter = new RESTAnalyticsAdapter({
2413
+ * httpClient,
2414
+ * endpoints: { batch: '/api/v1/events/track-batch' },
2415
+ * config: {
2416
+ * context: {
2417
+ * getSessionId: () => sessionStorage.getItem('session_id'),
2418
+ * getDeviceType: () => 'web',
2419
+ * getNetworkType: () => 'wifi',
2420
+ * },
2421
+ * transform: async (event, ctx) => ({
2422
+ * event_id: crypto.randomUUID(),
2423
+ * user_id: event.userId,
2424
+ * video_id: event.videoId,
2425
+ * session_id: await ctx.getSessionId(),
2426
+ * event_type: event.sdkEventType,
2427
+ * // ... more fields
2428
+ * }),
2429
+ * },
2430
+ * });
2431
+ * ```
2048
2432
  */
2049
2433
 
2050
2434
  /**
@@ -2053,22 +2437,35 @@ declare class RESTInteractionAdapter implements IInteraction {
2053
2437
  interface RESTAnalyticsAdapterConfig {
2054
2438
  httpClient: HttpClient;
2055
2439
  endpoints: NonNullable<RESTEndpointMap['analytics']>;
2440
+ /** Batch analytics config with transform and context */
2441
+ config?: BatchAnalyticsConfig;
2442
+ /** @deprecated Use config.batchSize instead */
2056
2443
  batchSize?: number;
2444
+ /** @deprecated Use config.flushInterval instead */
2057
2445
  flushInterval?: number;
2058
2446
  logger?: ILogger;
2059
2447
  }
2060
2448
  /**
2061
2449
  * REST Analytics Adapter
2450
+ *
2451
+ * Supports two modes:
2452
+ * 1. Default mode: Uses SDK format { events: [...] }
2453
+ * 2. Custom mode: Uses transform function for custom API format
2062
2454
  */
2063
2455
  declare class RESTAnalyticsAdapter implements IAnalytics {
2064
2456
  private readonly httpClient;
2065
2457
  private readonly endpoint;
2066
2458
  private readonly batchSize;
2067
2459
  private readonly logger?;
2460
+ private readonly transform?;
2461
+ private readonly context;
2462
+ private readonly eventTypeMap;
2463
+ private readonly useSendBeacon;
2068
2464
  private queue;
2069
2465
  private flushTimer;
2070
2466
  private userId;
2071
2467
  private userProperties;
2468
+ private viewedVideos;
2072
2469
  constructor(config: RESTAnalyticsAdapterConfig);
2073
2470
  /**
2074
2471
  * Track an analytics event
@@ -2080,9 +2477,23 @@ declare class RESTAnalyticsAdapter implements IAnalytics {
2080
2477
  */
2081
2478
  flush(): Promise<void>;
2082
2479
  /**
2083
- * Track video view duration (heartbeat)
2480
+ * Build request body from events
2481
+ * Uses custom transform if provided, otherwise SDK default format
2482
+ */
2483
+ private buildRequestBody;
2484
+ /**
2485
+ * Track video view duration
2486
+ *
2487
+ * Note: PlayerEngine calls this every second (heartbeat), but for batch analytics
2488
+ * we only need ONE view_start per video. This method deduplicates by videoId.
2489
+ *
2490
+ * If you need heartbeat tracking, use RESTViewTrackingAdapter instead.
2084
2491
  */
2085
2492
  trackViewDuration(videoId: string, duration: number, totalDuration: number): void;
2493
+ /**
2494
+ * Clear viewed videos cache (useful for testing or session reset)
2495
+ */
2496
+ clearViewedVideos(): void;
2086
2497
  /**
2087
2498
  * Track video completion
2088
2499
  */
@@ -2101,12 +2512,23 @@ declare class RESTAnalyticsAdapter implements IAnalytics {
2101
2512
  destroy(): void;
2102
2513
  /**
2103
2514
  * Try to send via sendBeacon (for reliability on page unload)
2515
+ * Note: sendBeacon shows as "ping" type in Network tab, not "POST"
2516
+ *
2517
+ * Set useSendBeacon: false in config to always use HTTP POST
2104
2518
  */
2105
2519
  private trySendBeacon;
2106
2520
  /**
2107
2521
  * Build full URL for sendBeacon
2108
2522
  */
2109
2523
  private buildFullUrl;
2524
+ /**
2525
+ * Get mapped API event type from SDK event type
2526
+ */
2527
+ getApiEventType(sdkEventType: string): BatchAnalyticsEventType;
2528
+ /**
2529
+ * Get current context (for debugging/testing)
2530
+ */
2531
+ getContext(): BatchAnalyticsContext;
2110
2532
  }
2111
2533
  /**
2112
2534
  * Create a no-op analytics adapter
@@ -2114,6 +2536,109 @@ declare class RESTAnalyticsAdapter implements IAnalytics {
2114
2536
  */
2115
2537
  declare function createNoOpAnalyticsAdapter(): IAnalytics;
2116
2538
 
2539
+ /**
2540
+ * REST View Tracking Adapter - Per-video view tracking via REST API
2541
+ *
2542
+ * Implements IAnalytics interface with throttled, fire-and-forget tracking.
2543
+ * Uses shared HttpClient from preset (auth, retry, timeout).
2544
+ *
2545
+ * @example
2546
+ * ```typescript
2547
+ * // Created automatically by createRESTAdapters when viewTracking is configured
2548
+ * const adapters = createRESTAdapters({
2549
+ * baseUrl: 'https://api.myapp.com/v1',
2550
+ * auth: { ... },
2551
+ * endpoints: {
2552
+ * feed: { ... },
2553
+ * interaction: { ... },
2554
+ * viewTracking: {
2555
+ * notify: '/reels/:id/notify-views',
2556
+ * },
2557
+ * },
2558
+ * });
2559
+ * ```
2560
+ */
2561
+
2562
+ /**
2563
+ * REST View Tracking Adapter configuration
2564
+ */
2565
+ interface RESTViewTrackingAdapterConfig {
2566
+ httpClient: HttpClient;
2567
+ endpoint: NonNullable<RESTEndpointMap['viewTracking']>;
2568
+ config?: ViewTrackingConfig;
2569
+ logger?: ILogger;
2570
+ }
2571
+ /**
2572
+ * RESTViewTrackingAdapter - Per-video view tracking via REST API
2573
+ *
2574
+ * Uses shared HttpClient (inherits auth, retry, timeout from preset).
2575
+ * Implements throttled, fire-and-forget tracking.
2576
+ */
2577
+ declare class RESTViewTrackingAdapter implements IAnalytics {
2578
+ private readonly httpClient;
2579
+ private readonly endpoint;
2580
+ private readonly transform;
2581
+ private readonly viewEventValue;
2582
+ private readonly heartbeatInterval;
2583
+ private readonly minWatchTime;
2584
+ private readonly trackLeaveEnabled;
2585
+ private readonly logger?;
2586
+ private lastTrackTime;
2587
+ private lastEventType;
2588
+ private _userId;
2589
+ private _userProperties;
2590
+ /** Get current user ID */
2591
+ get userId(): string | null;
2592
+ /** Get current user properties */
2593
+ get userProperties(): Record<string, unknown>;
2594
+ constructor(config: RESTViewTrackingAdapterConfig);
2595
+ /**
2596
+ * Track generic event
2597
+ * Delegates video events to specific handlers
2598
+ */
2599
+ track(event: AnalyticsEvent): void;
2600
+ /**
2601
+ * Flush - No-op since we send events immediately (fire-and-forget)
2602
+ */
2603
+ flush(): Promise<void>;
2604
+ /**
2605
+ * Track view duration (heartbeat)
2606
+ * Called periodically during video playback
2607
+ */
2608
+ trackViewDuration(videoId: string, duration: number, totalDuration: number): void;
2609
+ /**
2610
+ * Track video completion
2611
+ * Called when video ends or loops
2612
+ */
2613
+ trackCompletion(videoId: string, watchTime: number, loopCount: number): void;
2614
+ /**
2615
+ * Set user context
2616
+ */
2617
+ setUser(userId: string | null, properties?: Record<string, unknown>): void;
2618
+ /**
2619
+ * Get queue size (always 0 - no batching)
2620
+ */
2621
+ getQueueSize(): number;
2622
+ /**
2623
+ * Track when user leaves video
2624
+ * Called when user scrolls to another video
2625
+ */
2626
+ trackLeaveVideo(videoId: string, currentTime: number, duration: number): void;
2627
+ /**
2628
+ * Clear tracking state for a video
2629
+ * Call when video is removed from viewport
2630
+ */
2631
+ clearVideoState(videoId: string): void;
2632
+ /**
2633
+ * Clear all tracking state
2634
+ */
2635
+ reset(): void;
2636
+ /**
2637
+ * Send view event to API (fire-and-forget)
2638
+ */
2639
+ private sendViewEvent;
2640
+ }
2641
+
2117
2642
  /**
2118
2643
  * REST Comment Adapter - ICommentAdapter implementation for REST APIs
2119
2644
  *
@@ -2228,4 +2753,4 @@ declare class RESTCommentAdapter implements ICommentAdapter {
2228
2753
  private unwrapResponse;
2229
2754
  }
2230
2755
 
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 };
2756
+ 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 };