@xhub-short/adapters 0.1.0-beta.11 → 0.1.0-beta.13
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.d.ts +47 -2
- package/dist/index.js +263 -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, ReportReason, CommentTransformers } from '@xhub-short/contracts';
|
|
1
|
+
import { IDataSource, VideoItem, FeedResponse, 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, IVideoLoader, VideoSource, PreloadConfig, PreloadResult, PreloadStatus, IPosterLoader, ReportReason, CommentTransformers } from '@xhub-short/contracts';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* MockDataAdapter - Development/Testing Data Source
|
|
@@ -46,6 +46,19 @@ interface MockDataAdapterOptions {
|
|
|
46
46
|
delay?: number;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* MockPlaylistAdapter - Development/Testing Playlist Data Source
|
|
51
|
+
*/
|
|
52
|
+
declare class MockPlaylistAdapter implements IPlaylistDataSource {
|
|
53
|
+
private readonly delay;
|
|
54
|
+
constructor(options?: {
|
|
55
|
+
delay?: number;
|
|
56
|
+
});
|
|
57
|
+
fetchPlaylist(id: string): Promise<PlaylistData>;
|
|
58
|
+
fetchPlaylistCollection(cursor?: string): Promise<PlaylistCollectionResponse>;
|
|
59
|
+
private simulateDelay;
|
|
60
|
+
}
|
|
61
|
+
|
|
49
62
|
/**
|
|
50
63
|
* Configuration options for MockLoggerAdapter
|
|
51
64
|
*/
|
|
@@ -972,6 +985,22 @@ interface RESTEndpointMap {
|
|
|
972
985
|
*/
|
|
973
986
|
detail: string;
|
|
974
987
|
};
|
|
988
|
+
/**
|
|
989
|
+
* Playlist-related endpoints
|
|
990
|
+
*/
|
|
991
|
+
playlist?: {
|
|
992
|
+
/**
|
|
993
|
+
* GET endpoint for playlist collection (listing)
|
|
994
|
+
* Example: '/playlists'
|
|
995
|
+
*/
|
|
996
|
+
list: string;
|
|
997
|
+
/**
|
|
998
|
+
* GET endpoint for playlist detail
|
|
999
|
+
* :id will be replaced with playlist ID
|
|
1000
|
+
* Example: '/playlists/:id'
|
|
1001
|
+
*/
|
|
1002
|
+
detail: string;
|
|
1003
|
+
};
|
|
975
1004
|
/**
|
|
976
1005
|
* Interaction endpoints
|
|
977
1006
|
*/
|
|
@@ -1132,6 +1161,16 @@ interface TransformConfig {
|
|
|
1132
1161
|
nextCursor: string | null;
|
|
1133
1162
|
hasMore: boolean;
|
|
1134
1163
|
};
|
|
1164
|
+
/**
|
|
1165
|
+
* Transform playlist response from API
|
|
1166
|
+
* If not provided, uses default transform
|
|
1167
|
+
*/
|
|
1168
|
+
playlist?: (apiResponse: unknown) => PlaylistData;
|
|
1169
|
+
/**
|
|
1170
|
+
* Transform playlist collection response from API
|
|
1171
|
+
* If not provided, uses default transform
|
|
1172
|
+
*/
|
|
1173
|
+
playlistCollection?: (apiResponse: unknown) => PlaylistCollectionResponse;
|
|
1135
1174
|
/**
|
|
1136
1175
|
* Transform report reasons response from API
|
|
1137
1176
|
* If not provided, uses default transform
|
|
@@ -1479,6 +1518,8 @@ interface PresetAdapters {
|
|
|
1479
1518
|
dataSource: IDataSource;
|
|
1480
1519
|
interaction: IInteraction;
|
|
1481
1520
|
analytics: IAnalytics;
|
|
1521
|
+
/** Playlist adapter (optional) */
|
|
1522
|
+
playlist?: IPlaylistDataSource;
|
|
1482
1523
|
/** Comment adapter (only if comment endpoints are configured) */
|
|
1483
1524
|
comment?: ICommentAdapter;
|
|
1484
1525
|
}
|
|
@@ -1946,6 +1987,8 @@ interface FullPresetAdapters {
|
|
|
1946
1987
|
videoLoader: IVideoLoader;
|
|
1947
1988
|
/** Poster preloader (Image) */
|
|
1948
1989
|
posterLoader: IPosterLoader;
|
|
1990
|
+
/** Playlist adapter (REST API, optional) */
|
|
1991
|
+
playlist?: IPlaylistDataSource;
|
|
1949
1992
|
/** Comment adapter (REST API, only if comment endpoints configured) */
|
|
1950
1993
|
comment?: ICommentAdapter;
|
|
1951
1994
|
/** Logger (passed through) */
|
|
@@ -2143,6 +2186,8 @@ interface ResolvedTransforms {
|
|
|
2143
2186
|
nextCursor: string | null;
|
|
2144
2187
|
hasMore: boolean;
|
|
2145
2188
|
};
|
|
2189
|
+
playlist: (data: unknown) => PlaylistData;
|
|
2190
|
+
playlistCollection: (data: unknown) => PlaylistCollectionResponse;
|
|
2146
2191
|
}
|
|
2147
2192
|
declare function createTransforms(config?: TransformConfig, logger?: ILogger): ResolvedTransforms;
|
|
2148
2193
|
|
|
@@ -2675,4 +2720,4 @@ declare class RESTCommentAdapter implements ICommentAdapter {
|
|
|
2675
2720
|
private unwrapResponse;
|
|
2676
2721
|
}
|
|
2677
2722
|
|
|
2678
|
-
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, 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 };
|
|
2723
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ var MOCK_VIDEOS = [
|
|
|
4
4
|
// HLS Videos (for testing hls.js integration)
|
|
5
5
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
6
6
|
{
|
|
7
|
+
type: "video",
|
|
7
8
|
id: "video-1",
|
|
8
9
|
source: {
|
|
9
10
|
url: "https://peertube.teknix.services/static/streaming-playlists/hls/dd8de71d-0b75-4677-a1a2-6f60e673bee4/465faffa-6d08-4f34-ae40-691cc904ce7b-master.m3u8",
|
|
@@ -30,6 +31,7 @@ var MOCK_VIDEOS = [
|
|
|
30
31
|
hashtags: ["hls", "streaming", "test"]
|
|
31
32
|
},
|
|
32
33
|
{
|
|
34
|
+
type: "video",
|
|
33
35
|
id: "video-2",
|
|
34
36
|
source: {
|
|
35
37
|
url: "https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8",
|
|
@@ -59,6 +61,7 @@ var MOCK_VIDEOS = [
|
|
|
59
61
|
// MP4 Videos
|
|
60
62
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
61
63
|
{
|
|
64
|
+
type: "video",
|
|
62
65
|
id: "video-3",
|
|
63
66
|
source: {
|
|
64
67
|
url: "https://peertube.teknix.services/static/streaming-playlists/hls/ea58b245-b3bf-4958-b2f0-b31f8113d142/83f1bb91-e76a-4dcd-8034-2ec37cb70ead-master.m3u8",
|
|
@@ -85,6 +88,7 @@ var MOCK_VIDEOS = [
|
|
|
85
88
|
hashtags: ["chrome", "blazes"]
|
|
86
89
|
},
|
|
87
90
|
{
|
|
91
|
+
type: "video",
|
|
88
92
|
id: "video-4",
|
|
89
93
|
source: {
|
|
90
94
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4",
|
|
@@ -111,6 +115,7 @@ var MOCK_VIDEOS = [
|
|
|
111
115
|
hashtags: ["chrome", "escapes"]
|
|
112
116
|
},
|
|
113
117
|
{
|
|
118
|
+
type: "video",
|
|
114
119
|
id: "video-5",
|
|
115
120
|
source: {
|
|
116
121
|
url: "https://peertube.teknix.services/static/streaming-playlists/hls/003a41a3-25c1-419b-9548-7a1597adc85f/9cc93564-c9c9-4107-ae12-cd22d0db8046-master.m3u8",
|
|
@@ -137,6 +142,7 @@ var MOCK_VIDEOS = [
|
|
|
137
142
|
hashtags: ["chrome", "fun"]
|
|
138
143
|
},
|
|
139
144
|
{
|
|
145
|
+
type: "video",
|
|
140
146
|
id: "video-6",
|
|
141
147
|
source: {
|
|
142
148
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
|
|
@@ -163,6 +169,7 @@ var MOCK_VIDEOS = [
|
|
|
163
169
|
hashtags: ["adventure", "joyride", "travel"]
|
|
164
170
|
},
|
|
165
171
|
{
|
|
172
|
+
type: "video",
|
|
166
173
|
id: "video-7",
|
|
167
174
|
source: {
|
|
168
175
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerMeltdowns.mp4",
|
|
@@ -189,6 +196,7 @@ var MOCK_VIDEOS = [
|
|
|
189
196
|
hashtags: ["satisfying", "icecream", "asmr"]
|
|
190
197
|
},
|
|
191
198
|
{
|
|
199
|
+
type: "video",
|
|
192
200
|
id: "video-8",
|
|
193
201
|
source: {
|
|
194
202
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4",
|
|
@@ -215,6 +223,7 @@ var MOCK_VIDEOS = [
|
|
|
215
223
|
hashtags: ["fantasy", "animation", "sintel", "blender"]
|
|
216
224
|
},
|
|
217
225
|
{
|
|
226
|
+
type: "video",
|
|
218
227
|
id: "video-9",
|
|
219
228
|
source: {
|
|
220
229
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/SubaruOutbackOnStreetAndDirt.mp4",
|
|
@@ -241,6 +250,7 @@ var MOCK_VIDEOS = [
|
|
|
241
250
|
hashtags: ["cars", "subaru", "offroad", "review"]
|
|
242
251
|
},
|
|
243
252
|
{
|
|
253
|
+
type: "video",
|
|
244
254
|
id: "video-10",
|
|
245
255
|
source: {
|
|
246
256
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4",
|
|
@@ -267,6 +277,7 @@ var MOCK_VIDEOS = [
|
|
|
267
277
|
hashtags: ["scifi", "drama", "blender", "vfx"]
|
|
268
278
|
},
|
|
269
279
|
{
|
|
280
|
+
type: "video",
|
|
270
281
|
id: "video-11",
|
|
271
282
|
source: {
|
|
272
283
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/VolkswagenGTIReview.mp4",
|
|
@@ -293,6 +304,7 @@ var MOCK_VIDEOS = [
|
|
|
293
304
|
hashtags: ["cars", "vw", "gti", "hothatch"]
|
|
294
305
|
},
|
|
295
306
|
{
|
|
307
|
+
type: "video",
|
|
296
308
|
id: "video-12",
|
|
297
309
|
source: {
|
|
298
310
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/WeAreGoingOnBullrun.mp4",
|
|
@@ -319,6 +331,7 @@ var MOCK_VIDEOS = [
|
|
|
319
331
|
hashtags: ["rally", "racing", "bullrun", "supercars"]
|
|
320
332
|
},
|
|
321
333
|
{
|
|
334
|
+
type: "video",
|
|
322
335
|
id: "video-13",
|
|
323
336
|
source: {
|
|
324
337
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/WhatCarCanYouGetForAGrand.mp4",
|
|
@@ -345,6 +358,7 @@ var MOCK_VIDEOS = [
|
|
|
345
358
|
hashtags: ["budget", "usedcars", "tips", "bargain"]
|
|
346
359
|
},
|
|
347
360
|
{
|
|
361
|
+
type: "video",
|
|
348
362
|
id: "video-14",
|
|
349
363
|
source: {
|
|
350
364
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
|
|
@@ -371,6 +385,7 @@ var MOCK_VIDEOS = [
|
|
|
371
385
|
hashtags: ["bts", "animation", "3d", "making"]
|
|
372
386
|
},
|
|
373
387
|
{
|
|
388
|
+
type: "video",
|
|
374
389
|
id: "video-15",
|
|
375
390
|
source: {
|
|
376
391
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4",
|
|
@@ -397,6 +412,7 @@ var MOCK_VIDEOS = [
|
|
|
397
412
|
hashtags: ["tutorial", "animation", "blender", "makingof"]
|
|
398
413
|
},
|
|
399
414
|
{
|
|
415
|
+
type: "video",
|
|
400
416
|
id: "video-16",
|
|
401
417
|
source: {
|
|
402
418
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4",
|
|
@@ -423,6 +439,7 @@ var MOCK_VIDEOS = [
|
|
|
423
439
|
hashtags: ["characterdesign", "sintel", "tutorial", "art"]
|
|
424
440
|
},
|
|
425
441
|
{
|
|
442
|
+
type: "video",
|
|
426
443
|
id: "video-17",
|
|
427
444
|
source: {
|
|
428
445
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4",
|
|
@@ -449,6 +466,7 @@ var MOCK_VIDEOS = [
|
|
|
449
466
|
hashtags: ["vfx", "breakdown", "compositing", "cgi"]
|
|
450
467
|
},
|
|
451
468
|
{
|
|
469
|
+
type: "video",
|
|
452
470
|
id: "video-18",
|
|
453
471
|
source: {
|
|
454
472
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
|
|
@@ -475,6 +493,7 @@ var MOCK_VIDEOS = [
|
|
|
475
493
|
hashtags: ["pov", "roadtrip", "travel", "wanderlust"]
|
|
476
494
|
},
|
|
477
495
|
{
|
|
496
|
+
type: "video",
|
|
478
497
|
id: "video-19",
|
|
479
498
|
source: {
|
|
480
499
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4",
|
|
@@ -501,6 +520,7 @@ var MOCK_VIDEOS = [
|
|
|
501
520
|
hashtags: ["satisfying", "fire", "asmr", "relaxing"]
|
|
502
521
|
},
|
|
503
522
|
{
|
|
523
|
+
type: "video",
|
|
504
524
|
id: "video-20",
|
|
505
525
|
source: {
|
|
506
526
|
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerMeltdowns.mp4",
|
|
@@ -576,6 +596,86 @@ var MockDataAdapter = class {
|
|
|
576
596
|
}
|
|
577
597
|
};
|
|
578
598
|
|
|
599
|
+
// src/playlist/MockPlaylistAdapter.ts
|
|
600
|
+
var MOCK_PLAYLISTS = [
|
|
601
|
+
{
|
|
602
|
+
id: "p1",
|
|
603
|
+
title: "Workout Jams",
|
|
604
|
+
description: "High energy tracks for your workout",
|
|
605
|
+
cover: "https://images.unsplash.com/photo-1534438327276-14e5300c3a48?w=400&h=600&fit=crop",
|
|
606
|
+
totalItems: 4,
|
|
607
|
+
items: []
|
|
608
|
+
// Populated on fetchPlaylist
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
id: "p2",
|
|
612
|
+
title: "Chill Vibes",
|
|
613
|
+
description: "Relax and unwind with these lo-fi beats",
|
|
614
|
+
cover: "https://images.unsplash.com/photo-1516280440614-37939bbacd81?w=400&h=600&fit=crop",
|
|
615
|
+
totalItems: 4,
|
|
616
|
+
items: []
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
id: "p3",
|
|
620
|
+
title: "Travel Diaries",
|
|
621
|
+
description: "Explore the world through music and video",
|
|
622
|
+
cover: "https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?w=400&h=600&fit=crop",
|
|
623
|
+
totalItems: 4,
|
|
624
|
+
items: []
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
id: "p4",
|
|
628
|
+
title: "Cooking with Chef loct",
|
|
629
|
+
description: "Delicious recipes and kitchen tips",
|
|
630
|
+
cover: "https://images.unsplash.com/photo-1556910103-1c02745aae4d?w=400&h=600&fit=crop",
|
|
631
|
+
totalItems: 4,
|
|
632
|
+
items: []
|
|
633
|
+
}
|
|
634
|
+
];
|
|
635
|
+
var MockPlaylistAdapter = class {
|
|
636
|
+
constructor(options = {}) {
|
|
637
|
+
this.delay = options.delay ?? 300;
|
|
638
|
+
}
|
|
639
|
+
async fetchPlaylist(id) {
|
|
640
|
+
await this.simulateDelay();
|
|
641
|
+
const playlist = MOCK_PLAYLISTS.find((p) => p.id === id);
|
|
642
|
+
if (!playlist) throw new Error(`Playlist ${id} not found`);
|
|
643
|
+
let items = [];
|
|
644
|
+
if (id === "p1") items = MOCK_VIDEOS.slice(0, 4);
|
|
645
|
+
else if (id === "p2") items = MOCK_VIDEOS.slice(4, 8);
|
|
646
|
+
else if (id === "p3") items = MOCK_VIDEOS.slice(8, 12);
|
|
647
|
+
else if (id === "p4") items = MOCK_VIDEOS.slice(12, 16);
|
|
648
|
+
return { ...playlist, items };
|
|
649
|
+
}
|
|
650
|
+
async fetchPlaylistCollection(cursor) {
|
|
651
|
+
await this.simulateDelay();
|
|
652
|
+
const offset = cursor ? Number.parseInt(cursor, 10) : 0;
|
|
653
|
+
const limit = 4;
|
|
654
|
+
const items = MOCK_PLAYLISTS.slice(offset, offset + limit);
|
|
655
|
+
const nextOffset = offset + limit;
|
|
656
|
+
const hasMore = nextOffset < MOCK_PLAYLISTS.length;
|
|
657
|
+
const playlists = items.map((p) => ({
|
|
658
|
+
id: p.id,
|
|
659
|
+
title: p.title,
|
|
660
|
+
description: p.description,
|
|
661
|
+
cover: p.cover,
|
|
662
|
+
totalItems: p.totalItems,
|
|
663
|
+
author: { id: "a1", name: "System" },
|
|
664
|
+
updatedAt: "2 days ago"
|
|
665
|
+
}));
|
|
666
|
+
return {
|
|
667
|
+
playlists,
|
|
668
|
+
nextCursor: hasMore ? String(nextOffset) : null,
|
|
669
|
+
hasMore
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
async simulateDelay() {
|
|
673
|
+
if (this.delay > 0) {
|
|
674
|
+
await new Promise((resolve) => setTimeout(resolve, this.delay));
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
|
|
579
679
|
// src/logger/mock.ts
|
|
580
680
|
var LOG_LEVEL_PRIORITY = {
|
|
581
681
|
debug: 0,
|
|
@@ -2610,6 +2710,7 @@ var RESTDataAdapter = class {
|
|
|
2610
2710
|
createFallbackVideoItem(data) {
|
|
2611
2711
|
const obj = data ?? {};
|
|
2612
2712
|
return {
|
|
2713
|
+
type: "video",
|
|
2613
2714
|
id: String(obj.id ?? obj.video_id ?? `fallback-${Date.now()}`),
|
|
2614
2715
|
source: {
|
|
2615
2716
|
url: String(obj.video_url ?? obj.url ?? ""),
|
|
@@ -2900,6 +3001,69 @@ var RESTInteractionAdapter = class {
|
|
|
2900
3001
|
}
|
|
2901
3002
|
};
|
|
2902
3003
|
|
|
3004
|
+
// src/preset/adapters/RESTPlaylistAdapter.ts
|
|
3005
|
+
var RESTPlaylistAdapter = class {
|
|
3006
|
+
constructor(config) {
|
|
3007
|
+
this.httpClient = config.httpClient;
|
|
3008
|
+
this.endpoint = config.endpoint;
|
|
3009
|
+
this.collectionEndpoint = config.collectionEndpoint;
|
|
3010
|
+
this.transforms = config.transforms;
|
|
3011
|
+
this.logger = config.logger;
|
|
3012
|
+
}
|
|
3013
|
+
/**
|
|
3014
|
+
* Fetch a complete playlist by ID
|
|
3015
|
+
*
|
|
3016
|
+
* @param id - The playlist ID
|
|
3017
|
+
* @returns Promise resolving to PlaylistData
|
|
3018
|
+
*/
|
|
3019
|
+
async fetchPlaylist(id) {
|
|
3020
|
+
try {
|
|
3021
|
+
this.logger?.info(`[RESTPlaylistAdapter] Fetching playlist: ${id}`);
|
|
3022
|
+
const path = this.endpoint.replace(":id", id);
|
|
3023
|
+
const response = await this.httpClient.request({
|
|
3024
|
+
method: "GET",
|
|
3025
|
+
path
|
|
3026
|
+
});
|
|
3027
|
+
const playlist = this.transforms.playlist(response);
|
|
3028
|
+
if (playlist.items.length === 0) {
|
|
3029
|
+
this.logger?.warn(`[RESTPlaylistAdapter] Playlist ${id} is empty`);
|
|
3030
|
+
}
|
|
3031
|
+
return playlist;
|
|
3032
|
+
} catch (error) {
|
|
3033
|
+
this.logger?.error(`[RESTPlaylistAdapter] Failed to fetch playlist: ${id}`, error);
|
|
3034
|
+
throw error;
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
/**
|
|
3038
|
+
* Fetch a collection of playlists
|
|
3039
|
+
*
|
|
3040
|
+
* @param cursor - Pagination cursor
|
|
3041
|
+
* @returns Promise resolving to PlaylistCollectionResponse
|
|
3042
|
+
*/
|
|
3043
|
+
async fetchPlaylistCollection(cursor) {
|
|
3044
|
+
try {
|
|
3045
|
+
if (!this.collectionEndpoint || !this.transforms.collection) {
|
|
3046
|
+
throw new Error(
|
|
3047
|
+
"[RESTPlaylistAdapter] collectionEndpoint or collection transform not configured"
|
|
3048
|
+
);
|
|
3049
|
+
}
|
|
3050
|
+
this.logger?.info(`[RESTPlaylistAdapter] Fetching playlist collection (cursor: ${cursor})`);
|
|
3051
|
+
const path = cursor ? `${this.collectionEndpoint}?cursor=${cursor}` : this.collectionEndpoint;
|
|
3052
|
+
const response = await this.httpClient.request({
|
|
3053
|
+
method: "GET",
|
|
3054
|
+
path
|
|
3055
|
+
});
|
|
3056
|
+
return this.transforms.collection(response);
|
|
3057
|
+
} catch (error) {
|
|
3058
|
+
this.logger?.error(
|
|
3059
|
+
"[RESTPlaylistAdapter] Failed to fetch playlist collection",
|
|
3060
|
+
error
|
|
3061
|
+
);
|
|
3062
|
+
throw error;
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
};
|
|
3066
|
+
|
|
2903
3067
|
// src/preset/adapters/RESTViewTrackingAdapter.ts
|
|
2904
3068
|
var DEFAULT_VIEW_EVENT_VALUE = "seek";
|
|
2905
3069
|
var DEFAULT_HEARTBEAT_INTERVAL = 1e4;
|
|
@@ -3370,6 +3534,83 @@ var HttpClient = class {
|
|
|
3370
3534
|
}
|
|
3371
3535
|
};
|
|
3372
3536
|
|
|
3537
|
+
// src/preset/transforms/playlist.ts
|
|
3538
|
+
function defaultPlaylistTransform(apiResponse, videoItemTransform, logger) {
|
|
3539
|
+
if (!apiResponse || typeof apiResponse !== "object") {
|
|
3540
|
+
logger?.error("[PlaylistTransform] Invalid API response", void 0, {
|
|
3541
|
+
apiResponse: String(apiResponse)
|
|
3542
|
+
});
|
|
3543
|
+
return createEmptyPlaylist();
|
|
3544
|
+
}
|
|
3545
|
+
const obj = apiResponse;
|
|
3546
|
+
const data = obj.data ?? obj.result ?? obj.playlist ?? obj;
|
|
3547
|
+
const rawItems = data.items ?? data.reels ?? data.videos ?? data.list ?? [];
|
|
3548
|
+
if (!Array.isArray(rawItems)) {
|
|
3549
|
+
logger?.warn("[PlaylistTransform] Items is not an array", { data });
|
|
3550
|
+
return createEmptyPlaylist(data);
|
|
3551
|
+
}
|
|
3552
|
+
const items = rawItems.map((item) => {
|
|
3553
|
+
try {
|
|
3554
|
+
return videoItemTransform(item);
|
|
3555
|
+
} catch (error) {
|
|
3556
|
+
logger?.error("[PlaylistTransform] Failed to transform item", error);
|
|
3557
|
+
return null;
|
|
3558
|
+
}
|
|
3559
|
+
}).filter((item) => item !== null);
|
|
3560
|
+
return {
|
|
3561
|
+
id: String(data.id ?? data.playlist_id ?? ""),
|
|
3562
|
+
title: String(data.title ?? data.name ?? "Untitled Playlist"),
|
|
3563
|
+
description: String(data.description ?? ""),
|
|
3564
|
+
cover: String(data.cover ?? data.cover_url ?? data.thumbnail ?? ""),
|
|
3565
|
+
items,
|
|
3566
|
+
totalItems: Number(data.total_items ?? data.total ?? items.length)
|
|
3567
|
+
};
|
|
3568
|
+
}
|
|
3569
|
+
function defaultPlaylistSummaryTransform(data) {
|
|
3570
|
+
const obj = data;
|
|
3571
|
+
const authorObj = obj.author ?? obj.user ?? obj.creator ?? {};
|
|
3572
|
+
return {
|
|
3573
|
+
id: String(obj.id ?? obj.playlist_id ?? ""),
|
|
3574
|
+
title: String(obj.title ?? obj.name ?? "Untitled Playlist"),
|
|
3575
|
+
description: String(obj.description ?? ""),
|
|
3576
|
+
cover: String(obj.cover ?? obj.cover_url ?? obj.thumbnail ?? ""),
|
|
3577
|
+
totalItems: Number(obj.total_items ?? obj.items_count ?? 0),
|
|
3578
|
+
author: {
|
|
3579
|
+
id: String(authorObj.id ?? authorObj.user_id ?? ""),
|
|
3580
|
+
name: String(authorObj.name ?? authorObj.display_name ?? authorObj.username ?? "Unknown")
|
|
3581
|
+
},
|
|
3582
|
+
updatedAt: String(obj.updated_at ?? obj.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString())
|
|
3583
|
+
};
|
|
3584
|
+
}
|
|
3585
|
+
function defaultPlaylistCollectionTransform(apiResponse, logger) {
|
|
3586
|
+
if (!apiResponse || typeof apiResponse !== "object") {
|
|
3587
|
+
return { playlists: [], nextCursor: null, hasMore: false };
|
|
3588
|
+
}
|
|
3589
|
+
const obj = apiResponse;
|
|
3590
|
+
const data = obj.data ?? obj.result ?? obj;
|
|
3591
|
+
const rawPlaylists = data.playlists ?? data.items ?? data.list ?? [];
|
|
3592
|
+
if (!Array.isArray(rawPlaylists)) {
|
|
3593
|
+
logger?.warn("[PlaylistTransform] Playlists is not an array", { data });
|
|
3594
|
+
return { playlists: [], nextCursor: null, hasMore: false };
|
|
3595
|
+
}
|
|
3596
|
+
const playlists = rawPlaylists.map(defaultPlaylistSummaryTransform);
|
|
3597
|
+
const nextCursor = String(data.next_cursor ?? data.cursor ?? data.nextCursor ?? null);
|
|
3598
|
+
const hasMore = Boolean(data.has_more ?? data.hasMore ?? (nextCursor && nextCursor !== "null"));
|
|
3599
|
+
return {
|
|
3600
|
+
playlists,
|
|
3601
|
+
nextCursor: nextCursor === "null" ? null : nextCursor,
|
|
3602
|
+
hasMore
|
|
3603
|
+
};
|
|
3604
|
+
}
|
|
3605
|
+
function createEmptyPlaylist(data) {
|
|
3606
|
+
return {
|
|
3607
|
+
id: String(data?.id ?? ""),
|
|
3608
|
+
title: String(data?.title ?? "Empty Playlist"),
|
|
3609
|
+
items: [],
|
|
3610
|
+
totalItems: 0
|
|
3611
|
+
};
|
|
3612
|
+
}
|
|
3613
|
+
|
|
3373
3614
|
// src/preset/transforms/defaults.ts
|
|
3374
3615
|
function getNestedValue(obj, path) {
|
|
3375
3616
|
if (!obj || typeof obj !== "object") return void 0;
|
|
@@ -3477,6 +3718,7 @@ function defaultVideoItemTransform(apiResponse, fieldMap, logger) {
|
|
|
3477
3718
|
const author = defaultAuthorTransform(obj);
|
|
3478
3719
|
const stats = defaultStatsTransform(obj);
|
|
3479
3720
|
const videoItem = {
|
|
3721
|
+
type: "video",
|
|
3480
3722
|
id,
|
|
3481
3723
|
source,
|
|
3482
3724
|
poster: toSafeString(
|
|
@@ -3558,7 +3800,13 @@ function defaultFeedResponseTransform(apiResponse, fieldMap, logger) {
|
|
|
3558
3800
|
function createTransforms(config, logger) {
|
|
3559
3801
|
return {
|
|
3560
3802
|
videoItem: config?.videoItem ? config.videoItem : (data) => defaultVideoItemTransform(data, config?.fieldMap?.video, logger),
|
|
3561
|
-
feedResponse: config?.feedResponse ? config.feedResponse : (data) => defaultFeedResponseTransform(data, config?.fieldMap?.feed, logger)
|
|
3803
|
+
feedResponse: config?.feedResponse ? config.feedResponse : (data) => defaultFeedResponseTransform(data, config?.fieldMap?.feed, logger),
|
|
3804
|
+
playlist: config?.playlist ? config.playlist : (data) => defaultPlaylistTransform(
|
|
3805
|
+
data,
|
|
3806
|
+
(item) => config?.videoItem ? config.videoItem(item) : defaultVideoItemTransform(item, config?.fieldMap?.video, logger),
|
|
3807
|
+
logger
|
|
3808
|
+
),
|
|
3809
|
+
playlistCollection: config?.playlistCollection ? config.playlistCollection : (data) => defaultPlaylistCollectionTransform(data, logger)
|
|
3562
3810
|
};
|
|
3563
3811
|
}
|
|
3564
3812
|
|
|
@@ -3637,11 +3885,22 @@ function createRESTAdapters(config) {
|
|
|
3637
3885
|
endpoints: endpoints.comment,
|
|
3638
3886
|
logger
|
|
3639
3887
|
}) : void 0;
|
|
3888
|
+
const playlist = endpoints.playlist ? new RESTPlaylistAdapter({
|
|
3889
|
+
httpClient,
|
|
3890
|
+
endpoint: endpoints.playlist.detail,
|
|
3891
|
+
collectionEndpoint: endpoints.playlist.list,
|
|
3892
|
+
transforms: {
|
|
3893
|
+
playlist: resolvedTransforms.playlist,
|
|
3894
|
+
collection: (data) => resolvedTransforms.playlistCollection(data)
|
|
3895
|
+
},
|
|
3896
|
+
logger
|
|
3897
|
+
}) : void 0;
|
|
3640
3898
|
return {
|
|
3641
3899
|
dataSource,
|
|
3642
3900
|
interaction,
|
|
3643
3901
|
analytics,
|
|
3644
|
-
comment
|
|
3902
|
+
comment,
|
|
3903
|
+
playlist
|
|
3645
3904
|
};
|
|
3646
3905
|
}
|
|
3647
3906
|
|
|
@@ -4276,8 +4535,9 @@ function createBrowserAdapters(config) {
|
|
|
4276
4535
|
videoLoader,
|
|
4277
4536
|
posterLoader,
|
|
4278
4537
|
comment,
|
|
4538
|
+
playlist: restAdapters.playlist,
|
|
4279
4539
|
logger: config.logger
|
|
4280
4540
|
};
|
|
4281
4541
|
}
|
|
4282
4542
|
|
|
4283
|
-
export { BrowserPosterLoader, BrowserVideoLoader, DEFAULT_REQUEST_CONFIG, DEFAULT_RETRY_CONFIG, HttpClient, HttpError, LocalSessionStorageAdapter, LocalStorageAdapter, MockAnalyticsAdapter, MockCommentAdapter, MockDataAdapter, MockInteractionAdapter, MockLoggerAdapter, MockNetworkAdapter, MockPosterLoader, MockSessionStorageAdapter, MockStorageAdapter, MockVideoLoader, RESTAnalyticsAdapter, RESTCommentAdapter, RESTDataAdapter, RESTInteractionAdapter, RESTViewTrackingAdapter, WebNetworkAdapter, createBrowserAdapters, createBrowserPosterLoader, createBrowserVideoLoader, createLocalStorageAdapter, createNoOpAnalyticsAdapter, createRESTAdapters, createSessionStorageAdapter, createTransforms, createWebNetworkAdapter, defaultFeedResponseTransform, defaultVideoItemTransform };
|
|
4543
|
+
export { BrowserPosterLoader, BrowserVideoLoader, DEFAULT_REQUEST_CONFIG, DEFAULT_RETRY_CONFIG, HttpClient, HttpError, LocalSessionStorageAdapter, LocalStorageAdapter, MockAnalyticsAdapter, MockCommentAdapter, MockDataAdapter, MockInteractionAdapter, MockLoggerAdapter, MockNetworkAdapter, MockPlaylistAdapter, MockPosterLoader, MockSessionStorageAdapter, MockStorageAdapter, MockVideoLoader, RESTAnalyticsAdapter, RESTCommentAdapter, RESTDataAdapter, RESTInteractionAdapter, RESTViewTrackingAdapter, WebNetworkAdapter, createBrowserAdapters, createBrowserPosterLoader, createBrowserVideoLoader, createLocalStorageAdapter, createNoOpAnalyticsAdapter, createRESTAdapters, createSessionStorageAdapter, createTransforms, createWebNetworkAdapter, defaultFeedResponseTransform, defaultVideoItemTransform };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xhub-short/adapters",
|
|
3
3
|
"sideEffects": false,
|
|
4
|
-
"version": "0.1.0-beta.
|
|
4
|
+
"version": "0.1.0-beta.13",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"dist"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@xhub-short/contracts": "0.1.0-beta.
|
|
23
|
+
"@xhub-short/contracts": "0.1.0-beta.13"
|
|
24
24
|
},
|
|
25
25
|
"optionalDependencies": {
|
|
26
26
|
"hls.js": "^1.5.0"
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"tsup": "^8.3.0",
|
|
30
30
|
"typescript": "^5.7.0",
|
|
31
31
|
"vitest": "^2.1.0",
|
|
32
|
-
"@xhub-short/tsconfig": "0.0.
|
|
33
|
-
"@xhub-short/vitest-config": "0.1.0-beta.
|
|
32
|
+
"@xhub-short/tsconfig": "0.0.1-beta.1",
|
|
33
|
+
"@xhub-short/vitest-config": "0.1.0-beta.12"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsup",
|