@xhub-short/sdk 0.1.0-beta.0

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/README.md ADDED
@@ -0,0 +1,596 @@
1
+ # @xhub-short/sdk
2
+
3
+ > **Glue Layer** - KαΊΏt nα»‘i Core Domain vα»›i React UI
4
+
5
+ ## πŸ“– SDK lΓ  gΓ¬?
6
+
7
+ **SDK (Software Development Kit)** lΓ  package chΓ­nh mΓ  Host App cΓ i Δ‘αΊ·t để tΓ­ch hợp Short Video Feed. NΓ³ Δ‘Γ³ng vai trΓ² **"Glue Layer"** - kαΊΏt nα»‘i tαΊ₯t cαΊ£ cΓ‘c thΓ nh phαΊ§n bΓͺn trong SDK thΓ nh mα»™t API thα»‘ng nhαΊ₯t, dα»… sα»­ dα»₯ng.
8
+
9
+ ```
10
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
11
+ β”‚ HOST APP (Your App) β”‚
12
+ β”‚ β”‚
13
+ β”‚ import { ShortVideoProvider, useFeed, usePlayer } from '@xhub-short/sdk';
14
+ β”‚ import { VideoFeed, VideoPlayer } from '@xhub-short/ui'; β”‚
15
+ β”‚ β”‚
16
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
17
+ β”‚ uses
18
+ β–Ό
19
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
20
+ β”‚ @xhub-short/ui β”‚
21
+ β”‚ (Lego Components - Phase 4) β”‚
22
+ β”‚ β”‚
23
+ β”‚ VideoFeed, VideoPlayer, InteractionBar, CommentSheet... β”‚
24
+ β”‚ β”‚
25
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
26
+ β”‚ imports hooks from
27
+ β–Ό
28
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
29
+ β”‚ @xhub-short/sdk β”‚
30
+ β”‚ (Glue Layer - Current) β”‚
31
+ β”‚ β”‚
32
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
33
+ β”‚ β”‚ Provider β”‚ β”‚ Hooks β”‚ β”‚ Factory (createSDK) β”‚ β”‚
34
+ β”‚ β”‚ (Context) β”‚ β”‚ (React) β”‚ β”‚ (Dependency Inject) β”‚ β”‚
35
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
36
+ β”‚ β”‚
37
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
38
+ β”‚ orchestrates
39
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
40
+ β–Ό β–Ό
41
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
42
+ β”‚ @core β”‚ β”‚ @adapters β”‚
43
+ β”‚ (Domain) β”‚ β”‚ (Infra) β”‚
44
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
45
+ ```
46
+
47
+ > **LΖ°u Γ½:** `@sdk` **KHΓ”NG** import tα»« `@ui`. MΕ©i tΓͺn chỉ hΖ°α»›ng dependency (ai import ai).
48
+
49
+ ---
50
+
51
+ ## 🎯 Tẑi sao cần SDK?
52
+
53
+ | VαΊ₯n đề | GiαΊ£i phΓ‘p cα»§a SDK |
54
+ |--------|-------------------|
55
+ | Host App phαΊ£i hiểu kiαΊΏn trΓΊc phα»©c tαΊ‘p bΓͺn trong | SDK expose API Δ‘Ζ‘n giαΊ£n: hooks + provider |
56
+ | KhΓ³ setup dependency injection cho adapters | `createSDK()` tα»± Δ‘α»™ng wire tαΊ₯t cαΊ£ |
57
+ | State management phα»©c tαΊ‘p (Feed, Player, Resource...) | Hooks abstract hαΊΏt complexity |
58
+ | SSR compatibility | `useSyncExternalStore` built-in |
59
+ | Memory leaks khi unmount | `sdk.destroy()` cleanup tα»± Δ‘α»™ng |
60
+
61
+ ---
62
+
63
+ ## πŸ“‹ Nhiệm vα»₯ chi tiαΊΏt cα»§a SDK
64
+
65
+ SDK thα»±c hiện **7 nhiệm vα»₯ chΓ­nh** để Host App cΓ³ thể tΓ­ch hợp dα»… dΓ ng:
66
+
67
+ ### 1. Dependency Injection & Wiring
68
+
69
+ SDK lΓ  nΖ‘i **duy nhαΊ₯t** thα»±c hiện dependency injection - kαΊΏt nα»‘i cΓ‘c adapters vα»›i core managers:
70
+
71
+ ```
72
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
73
+ β”‚ DEPENDENCY INJECTION MAP β”‚
74
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
75
+ β”‚ β”‚
76
+ β”‚ Adapter Interface ───► Core Component β”‚
77
+ β”‚ ───────────────── ────────────── β”‚
78
+ β”‚ IDataSource ───► FeedManager β”‚
79
+ β”‚ IInteraction ───► OptimisticManager β”‚
80
+ β”‚ ISessionStorage ───► LifecycleManager β”‚
81
+ β”‚ INetworkAdapter ───► ResourceGovernor β”‚
82
+ β”‚ IVideoLoader + IPosterLoader ───► ResourceGovernor β”‚
83
+ β”‚ IAnalytics ───► PlayerEngine (events) β”‚
84
+ β”‚ ILogger ───► All managers (debug) β”‚
85
+ β”‚ β”‚
86
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
87
+ ```
88
+
89
+ ### 2. Adapter Resolution
90
+
91
+ SDK tα»± Δ‘α»™ng resolve adapters theo thα»© tα»± Ζ°u tiΓͺn:
92
+
93
+ ```
94
+ Config Priority:
95
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
96
+ β”‚ β”‚
97
+ β”‚ 1. config.adapters.dataSource ◄── Highest (User-defined)β”‚
98
+ β”‚ β”‚ β”‚
99
+ β”‚ β–Ό fallback β”‚
100
+ β”‚ 2. config.preset β†’ createBrowserAdapters() β”‚
101
+ β”‚ β”‚ β”‚
102
+ β”‚ β–Ό fallback β”‚
103
+ β”‚ 3. MockAdapter ◄── Lowest (Development) β”‚
104
+ β”‚ β”‚
105
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
106
+ ```
107
+
108
+ Điều này cho phép:
109
+ - **Development**: KhΓ΄ng cαΊ§n config β†’ Mock adapters tα»± Δ‘α»™ng
110
+ - **Production vα»›i Preset**: Chỉ cαΊ§n `baseUrl + auth + endpoints`
111
+ - **Full Custom**: Override bαΊ₯t kα»³ adapter nΓ o
112
+
113
+ ### 3. State Synchronization (Core ↔ React)
114
+
115
+ Core Domain sα»­ dα»₯ng **vanilla stores** (khΓ΄ng React). SDK bridge chΓΊng sang React:
116
+
117
+ ```
118
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
119
+ β”‚ Core Store β”‚ β”‚ SDK Hook β”‚ β”‚ React UI β”‚
120
+ β”‚ (Vanilla) β”‚ ───► β”‚ (useSyncExternalβ”‚ ───► β”‚ (Re-render) β”‚
121
+ β”‚ β”‚ β”‚ Store) β”‚ β”‚ β”‚
122
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
123
+ β”‚ β”‚
124
+ β”‚ store.subscribe() β”‚ getSnapshot()
125
+ β”‚ store.setState() β”‚
126
+ β–Ό β–Ό
127
+ Framework-agnostic SSR-safe subscription
128
+ ```
129
+
130
+ **TαΊ‘i sao khΓ΄ng dΓΉng Zustand trα»±c tiαΊΏp trong Core?**
131
+ - Core phαΊ£i framework-agnostic (cΓ³ thể dΓΉng vα»›i Vue, Svelte...)
132
+ - GiαΊ£m bundle size cho Core package
133
+ - TΓ‘ch biệt concerns rΓ΅ rΓ ng
134
+
135
+ ### 4. Event Orchestration
136
+
137
+ SDK wire cΓ‘c events giα»―a managers để chΓΊng phα»‘i hợp:
138
+
139
+ ```
140
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
141
+ β”‚ EVENT WIRING β”‚
142
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
143
+ β”‚ β”‚
144
+ β”‚ PlayerEngine β”‚
145
+ β”‚ β”‚ β”‚
146
+ β”‚ β”œβ”€β”€ on('videoChange') ──────► Analytics.flush() β”‚
147
+ β”‚ β”‚ (Flush trΖ°α»›c khi Δ‘α»•i video) β”‚
148
+ β”‚ β”‚ β”‚
149
+ β”‚ └── on('timeUpdate') ───────► LifecycleManager.setPendingSave()β”‚
150
+ β”‚ (Auto-save playback position) β”‚
151
+ β”‚ β”‚
152
+ β”‚ LifecycleManager β”‚
153
+ β”‚ β”‚ β”‚
154
+ β”‚ └── on('visibilityChange') ─► Analytics.flush() β”‚
155
+ β”‚ (state === 'hidden') (Flush khi app background) β”‚
156
+ β”‚ β”‚
157
+ β”‚ ResourceGovernor β”‚
158
+ β”‚ β”‚ β”‚
159
+ β”‚ └── on('focusChange') ──────► PlayerEngine.load(video) β”‚
160
+ β”‚ (Load video khi swipe) β”‚
161
+ β”‚ β”‚
162
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
163
+ ```
164
+
165
+ ### 5. Lifecycle Management
166
+
167
+ SDK quαΊ£n lΓ½ toΓ n bα»™ vΓ²ng đời cα»§a cΓ‘c managers:
168
+
169
+ | Phase | SDK Actions |
170
+ |-------|-------------|
171
+ | **Init** | TαΊ‘o managers, inject adapters, wire events, restore session |
172
+ | **Active** | Managers hoαΊ‘t Δ‘α»™ng Δ‘α»™c lαΊ­p, SDK chỉ expose hooks |
173
+ | **Background** | Auto-save session, flush analytics |
174
+ | **Destroy** | Cleanup timers, unsubscribe events, clear cache |
175
+
176
+ ```typescript
177
+ // Tα»± Δ‘α»™ng trong Provider:
178
+ useEffect(() => {
179
+ const sdk = createSDK(config);
180
+ return () => sdk.destroy(); // Cleanup khi unmount
181
+ }, []);
182
+ ```
183
+
184
+ ### 6. Public API Surface
185
+
186
+ SDK expose API Δ‘Ζ‘n giαΊ£n, αΊ©n Δ‘i complexity bΓͺn trong:
187
+
188
+ | Exposed to Host App | Hidden from Host App |
189
+ |---------------------|----------------------|
190
+ | `useFeed()` - videos, loadMore | FeedManager internals |
191
+ | `usePlayer()` - play, pause, seek | PlayerEngine state machine |
192
+ | `useOptimistic()` - like, follow | Rollback queue, pending states |
193
+ | `useSwipeGesture()` - onSwipe | DOM allocation logic |
194
+ | Config vα»›i preset | Adapter creation |
195
+
196
+ ### 7. SSR Support
197
+
198
+ SDK Δ‘αΊ£m bαΊ£o hoαΊ‘t Δ‘α»™ng vα»›i Server-Side Rendering:
199
+
200
+ ```
201
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
202
+ β”‚ SSR STRATEGY β”‚
203
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
204
+ β”‚ β”‚
205
+ β”‚ Server: β”‚
206
+ β”‚ β”œβ”€ ShortVideoProvider renders vα»›i empty state β”‚
207
+ β”‚ β”œβ”€ Hooks return initial/fallback values β”‚
208
+ β”‚ └─ KhΓ΄ng tαΊ‘o SDK instance β”‚
209
+ β”‚ β”‚
210
+ β”‚ Client (Hydration): β”‚
211
+ β”‚ β”œβ”€ useEffect tαΊ‘o SDK instance β”‚
212
+ β”‚ β”œβ”€ Restore session tα»« localStorage β”‚
213
+ β”‚ └─ useSyncExternalStore subscribe to stores β”‚
214
+ β”‚ β”‚
215
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
216
+ ```
217
+
218
+ ---
219
+
220
+ ## πŸ—οΈ KiαΊΏn trΓΊc
221
+
222
+ ### Vα»‹ trΓ­ trong hệ thα»‘ng
223
+
224
+ ```
225
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
226
+ β”‚ HEXAGONAL ARCHITECTURE β”‚
227
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
228
+ β”‚ β”‚
229
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
230
+ β”‚ β”‚ @xhub-short/sdk β”‚ β”‚
231
+ β”‚ β”‚ ════════════════ β”‚ β”‚
232
+ β”‚ β”‚ β”‚ β”‚
233
+ β”‚ β”‚ ShortVideoProvider ──────┬──────── createSDK() β”‚ β”‚
234
+ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
235
+ β”‚ β”‚ β”‚ Dependency Injection β”‚ β”‚ β”‚
236
+ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
237
+ β”‚ β”‚ β–Ό β–Ό β–Ό β”‚ β”‚
238
+ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
239
+ β”‚ β”‚ β”‚ Hooks β”‚ β”‚ Core β”‚ β”‚ Adapters β”‚ β”‚ β”‚
240
+ β”‚ β”‚ β”‚ (React) │◀────▢│ Managers │◀──│ (Inject) β”‚ β”‚ β”‚
241
+ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
242
+ β”‚ β”‚ β”‚ β”‚
243
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
244
+ β”‚ β”‚
245
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
246
+ β”‚ β”‚ @contracts β”‚ β”‚ @core β”‚ β”‚ @adapters β”‚ β”‚
247
+ β”‚ β”‚ (Interfaces) β”‚ β”‚ (Domain) β”‚ β”‚ (Infrastructure) β”‚ β”‚
248
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
249
+ β”‚ β”‚
250
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
251
+ ```
252
+
253
+ ### Package Dependencies
254
+
255
+ ```
256
+ @xhub-short/sdk
257
+ β”œβ”€β”€ @xhub-short/contracts (types, interfaces)
258
+ β”œβ”€β”€ @xhub-short/core (domain logic)
259
+ β”œβ”€β”€ @xhub-short/adapters (mock + preset adapters)
260
+ └── react (peer dependency)
261
+ ```
262
+
263
+ ---
264
+
265
+ ## ✨ Chα»©c nΔƒng chΓ­nh
266
+
267
+ ### 1. **Provider** - Context cho toΓ n bα»™ SDK
268
+
269
+ ```tsx
270
+ <ShortVideoProvider config={{ preset: {...} }}>
271
+ <YourApp />
272
+ </ShortVideoProvider>
273
+ ```
274
+
275
+ ### 2. **Hooks** - React API để truy cαΊ­p SDK
276
+
277
+ | Hook | Mα»₯c Δ‘Γ­ch |
278
+ |------|----------|
279
+ | `useFeed()` | Video list, pagination, loading states |
280
+ | `usePlayer()` | Playback control, time, volume, handlers |
281
+ | `useResource()` | DOM allocations, prefetch queue |
282
+ | `useOptimistic()` | Like/Follow vα»›i instant UI + rollback |
283
+ | `useSwipeGesture()` | Vertical swipe navigation |
284
+
285
+ ### 3. **Wired Components** - Pre-connected UI Components
286
+
287
+ SDK exports pre-wired versions of UI components with SDK hooks already injected:
288
+
289
+ | Component | Description |
290
+ |-----------|-------------|
291
+ | `VideoFeed` | Wired VideoFeedHeadless with useFeed + useSwipeGesture |
292
+ | `VideoSlot` | Wired VideoSlotHeadless with useResourceAllocation + usePlayer |
293
+ | `VideoPlayer` | Wired VideoPlayerHeadless with usePlayer (auto-load, sync) |
294
+ | `ProgressBar` | Wired progress bar with Direct DOM Update (60fps smooth) |
295
+
296
+ #### VideoPlayer (Wired)
297
+
298
+ Pre-wired video player that auto-connects to SDK PlayerEngine.
299
+
300
+ ```tsx
301
+ import { VideoSlot, VideoPlayer } from '@xhub-short/sdk';
302
+ import { VideoSlotPoster, VideoSlotOverlay } from '@xhub-short/ui';
303
+
304
+ function FeedItem({ video }) {
305
+ return (
306
+ <VideoSlot video={video}>
307
+ <VideoPlayer
308
+ resetOnInactive={true} // TikTok-like: restart from beginning
309
+ />
310
+ <VideoSlotPoster />
311
+ <VideoSlotOverlay>...</VideoSlotOverlay>
312
+ </VideoSlot>
313
+ );
314
+ }
315
+ ```
316
+
317
+ | Prop | Type | Default | Description |
318
+ |------|------|---------|-------------|
319
+ | `video` | `VideoItem` | from context | Video to play (optional if inside VideoSlot) |
320
+ | `autoLoad` | `boolean` | `true` | Auto-load video into PlayerEngine |
321
+ | `autoPlay` | `boolean` | `true` | Auto-play when slot becomes active |
322
+ | `resetOnInactive` | `boolean` | `true` | Reset video to 0:00 when slot becomes inactive |
323
+ | `loop` | `boolean` | `true` | Loop video playback |
324
+ | `muted` | `boolean` | `true` | Start muted (required for autoplay) |
325
+
326
+ **`resetOnInactive` behavior:**
327
+ - `true` (default): TikTok-like - swiping back restarts video from beginning
328
+ - `false`: YouTube-like - video continues from where user left off
329
+
330
+ #### ProgressBar (Wired) - P11 Re-render Optimization
331
+
332
+ Pre-wired progress bar that uses **Direct DOM Update** for 60fps smooth animation.
333
+
334
+ ```tsx
335
+ import { VideoSlot, VideoPlayer, ProgressBar } from '@xhub-short/sdk';
336
+ import { VideoSlotOverlay } from '@xhub-short/ui';
337
+
338
+ function FeedItem({ video }) {
339
+ return (
340
+ <VideoSlot video={video}>
341
+ <VideoPlayer />
342
+ <VideoSlotOverlay>
343
+ <ProgressBar seekable={true} /> {/* 60fps smooth! */}
344
+ </VideoSlotOverlay>
345
+ </VideoSlot>
346
+ );
347
+ }
348
+ ```
349
+
350
+ | Prop | Type | Default | Description |
351
+ |------|------|---------|-------------|
352
+ | `seekable` | `boolean` | `true` | Enable click/drag to seek |
353
+ | `showTime` | `boolean` | `false` | Show current/duration text |
354
+ | `showTooltip` | `boolean` | `true` | Show tooltip on hover |
355
+ | `minimal` | `boolean` | `false` | Thin bar without handle |
356
+
357
+ **Performance Architecture:**
358
+
359
+ ```
360
+ PlayerEngine.store ───── subscribe() ───── fillRef.style.transform
361
+ (scaleX, GPU accelerated)
362
+ NOT React re-render!
363
+ ```
364
+
365
+ This component demonstrates ADR 005: Direct DOM Manipulation for high-frequency updates.
366
+ See `docs/issues/RE_RENDER_ANALYSIS.md` for detailed optimization rationale.
367
+
368
+ ### 4. **Factory** - Dependency Injection
369
+
370
+ ```typescript
371
+ const sdk = createSDK({
372
+ preset: { baseUrl, auth, endpoints }, // Auto-generate adapters
373
+ adapters: { dataSource, interaction }, // Or custom adapters
374
+ feed: { pageSize: 20 },
375
+ player: { autoplay: true },
376
+ });
377
+ ```
378
+
379
+ ---
380
+
381
+ ## πŸ”„ CΓ‘ch hoαΊ‘t Δ‘α»™ng
382
+
383
+ ### Flow: Tα»« Config Δ‘αΊΏn UI
384
+
385
+ ```
386
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
387
+ β”‚ INITIALIZATION β”‚
388
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
389
+ β”‚ β”‚
390
+ β”‚ 1. Host App mount <ShortVideoProvider config={...}> β”‚
391
+ β”‚ β”‚ β”‚
392
+ β”‚ β–Ό β”‚
393
+ β”‚ 2. createSDK(config) β”‚
394
+ β”‚ β”œβ”€ Resolve adapters (preset β†’ browser adapters) β”‚
395
+ β”‚ β”œβ”€ Create Core managers: β”‚
396
+ β”‚ β”‚ β”œβ”€ FeedManager (video list, deduplication, GC) β”‚
397
+ β”‚ β”‚ β”œβ”€ PlayerEngine (playback state machine) β”‚
398
+ β”‚ β”‚ β”œβ”€ ResourceGovernor (DOM allocation, prefetch) β”‚
399
+ β”‚ β”‚ β”œβ”€ OptimisticManager (like/follow with rollback) β”‚
400
+ β”‚ β”‚ └─ LifecycleManager (session persistence) β”‚
401
+ β”‚ └─ Wire analytics flush events β”‚
402
+ β”‚ β”‚ β”‚
403
+ β”‚ β–Ό β”‚
404
+ β”‚ 3. SDKContext.Provider value={sdk} β”‚
405
+ β”‚ β”‚ β”‚
406
+ β”‚ β–Ό β”‚
407
+ β”‚ 4. Hooks subscribe to managers via useSyncExternalStore β”‚
408
+ β”‚ β”‚
409
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
410
+ ```
411
+
412
+ ### Flow: User Interaction
413
+
414
+ ```
415
+ User swipes down
416
+ β”‚
417
+ β–Ό
418
+ useSwipeGesture() ─────────► ResourceGovernor.setFocusedIndex(n+1)
419
+ β”‚
420
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
421
+ β–Ό β–Ό β–Ό
422
+ Deallocate Allocate Preload
423
+ video[n-1] video[n+1] video[n+2]
424
+ β”‚
425
+ β–Ό
426
+ PlayerEngine.load(video)
427
+ β”‚
428
+ β–Ό
429
+ Analytics.track('video_view')
430
+ ```
431
+
432
+ ---
433
+
434
+ ## πŸ“¦ Exports
435
+
436
+ ### Provider
437
+
438
+ ```typescript
439
+ export { ShortVideoProvider } from './provider';
440
+ export type { ShortVideoProviderProps, SDKConfig } from './provider';
441
+ ```
442
+
443
+ ### Hooks
444
+
445
+ ```typescript
446
+ // Feed management
447
+ export { useFeed, useFeedSelector } from './hooks';
448
+
449
+ // Player control
450
+ export { usePlayer, usePlayerSelector, usePlayerForVideo } from './hooks';
451
+
452
+ // Resource management (DOM allocation)
453
+ export { useResource, useResourceSelector, useResourceAllocation } from './hooks';
454
+
455
+ // Optimistic UI (like/follow)
456
+ export { useOptimistic, useOptimisticSelector } from './hooks';
457
+
458
+ // Swipe navigation
459
+ export { useSwipeGesture } from './hooks';
460
+
461
+ // SDK context access
462
+ export { useSDK } from './hooks';
463
+ ```
464
+
465
+ ### Factory
466
+
467
+ ```typescript
468
+ export { createSDK } from './store';
469
+ export type { SDKInstance } from './store';
470
+ ```
471
+
472
+ ### Types (Re-exported)
473
+
474
+ ```typescript
475
+ // From @xhub-short/contracts
476
+ export type { VideoItem, FeedResponse, IDataSource, ... } from '@xhub-short/contracts';
477
+
478
+ // From @xhub-short/core
479
+ export type { FeedState, PlayerState, ResourceState, ... } from '@xhub-short/core';
480
+ ```
481
+
482
+ ---
483
+
484
+ ## πŸš€ Quick Start
485
+
486
+ ### Basic Usage
487
+
488
+ ```tsx
489
+ import { ShortVideoProvider, useFeed, usePlayer } from '@xhub-short/sdk';
490
+
491
+ function App() {
492
+ return (
493
+ <ShortVideoProvider
494
+ config={{
495
+ preset: {
496
+ baseUrl: 'https://api.example.com/v1',
497
+ auth: { getAccessToken: () => localStorage.getItem('token') },
498
+ endpoints: {
499
+ feed: { list: '/videos', detail: '/videos/:id' },
500
+ interaction: { like: '/videos/:id/like', ... },
501
+ },
502
+ },
503
+ }}
504
+ >
505
+ <VideoFeed />
506
+ </ShortVideoProvider>
507
+ );
508
+ }
509
+
510
+ function VideoFeed() {
511
+ const { videos, loadInitial, loadMore, hasMore } = useFeed();
512
+ const { load, play, pause, isPlaying } = usePlayer();
513
+
514
+ // Your UI here...
515
+ }
516
+ ```
517
+
518
+ ### With Custom Adapters
519
+
520
+ ```tsx
521
+ <ShortVideoProvider
522
+ config={{
523
+ adapters: {
524
+ dataSource: new MyGraphQLAdapter(),
525
+ interaction: new MyFlutterBridgeAdapter(),
526
+ },
527
+ }}
528
+ >
529
+ <App />
530
+ </ShortVideoProvider>
531
+ ```
532
+
533
+ ---
534
+
535
+ ## πŸ”— LiΓͺn kαΊΏt vα»›i cΓ‘c Packages
536
+
537
+ | Package | Quan hệ vα»›i SDK |
538
+ |---------|-----------------|
539
+ | `@xhub-short/contracts` | SDK re-export types/interfaces |
540
+ | `@xhub-short/core` | SDK wraps core managers vα»›i React hooks |
541
+ | `@xhub-short/adapters` | SDK inject adapters vΓ o core managers |
542
+ | `@xhub-short/ui` | UI components sα»­ dα»₯ng SDK hooks (Phase 4) |
543
+ | `@xhub-short/bridge` | Optional Flutter integration |
544
+
545
+ ### Dependency Flow
546
+
547
+ ```
548
+ contracts ◀─────────────────────────────────────────┐
549
+ β–² β”‚
550
+ β”‚ β”‚
551
+ core ◀──────────────────────────┐ β”‚
552
+ β–² β”‚ β”‚
553
+ β”‚ β”‚ β”‚
554
+ adapters ◀──────────┐ β”‚ β”‚
555
+ β–² β”‚ β”‚ β”‚
556
+ β”‚ β”‚ β”‚ β”‚
557
+ └───────────────┴──────────┴────────── sdk β”€β”€β”€β”˜
558
+ β”‚
559
+ β–Ό
560
+ Host App
561
+ ```
562
+
563
+ ---
564
+
565
+ ## ⚠️ Lưu ý quan trọng
566
+
567
+ ### SSR Safety
568
+ - TαΊ₯t cαΊ£ hooks sα»­ dα»₯ng `useSyncExternalStore`
569
+ - Provider render fallback trΓͺn server
570
+ - SDK instance chỉ tαΊ‘o trΓͺn client
571
+
572
+ ### Memory Management
573
+ - `sdk.destroy()` được gọi tα»± Δ‘α»™ng khi Provider unmount
574
+ - Max 3 video DOM nodes (via ResourceGovernor)
575
+ - LRU cache eviction trong FeedManager
576
+
577
+ ### Deprecated APIs
578
+
579
+ ```typescript
580
+ // ❌ DEPRECATED - Singleton gΓ’y issues vα»›i SSR/testing
581
+ const sdk = getSDK(config);
582
+
583
+ // βœ… RECOMMENDED - Sα»­ dα»₯ng Provider
584
+ <ShortVideoProvider config={config}>
585
+ <App />
586
+ </ShortVideoProvider>
587
+ ```
588
+
589
+ ---
590
+
591
+ ## πŸ“š TΓ i liệu liΓͺn quan
592
+
593
+ - [ADD.md](/docs/ADD.md) - System Architecture
594
+ - [TECH_STACK.md](/docs/TECH_STACK.md) - Technology Stack
595
+ - [packages/core/README.md](/packages/core/README.md) - Core Domain
596
+ - [packages/adapters/README.md](/packages/adapters/README.md) - Adapters