@jaaq/jaaq-sdk-js 1.0.1 → 1.1.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.
Files changed (41) hide show
  1. package/README.md +733 -92
  2. package/dist/embed/embed-collection.html +275 -0
  3. package/dist/embed/embed.html +270 -0
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/jaaq-sdk.min.js.map +1 -1
  7. package/dist/ui/index.cjs +5051 -0
  8. package/dist/ui/index.cjs.map +1 -0
  9. package/dist/ui/index.d.ts +378 -0
  10. package/dist/ui/index.mjs +5044 -0
  11. package/dist/ui/index.mjs.map +1 -0
  12. package/dist/ui/jaaq-ui-bundled.min.js +8 -0
  13. package/dist/ui/jaaq-ui-bundled.min.js.map +1 -0
  14. package/dist/ui/jaaq-ui.min.js +8 -0
  15. package/dist/ui/jaaq-ui.min.js.map +1 -0
  16. package/dist/ui/react/index.cjs +4756 -0
  17. package/dist/ui/react/index.cjs.map +1 -0
  18. package/dist/ui/react/index.d.ts +182 -0
  19. package/dist/ui/react/index.mjs +4735 -0
  20. package/dist/ui/react/index.mjs.map +1 -0
  21. package/dist/ui/react/jaaq-ui-react.min.js +8 -0
  22. package/dist/ui/react/jaaq-ui-react.min.js.map +1 -0
  23. package/dist/ui/vanilla/index.cjs +5052 -0
  24. package/dist/ui/vanilla/index.cjs.map +1 -0
  25. package/dist/ui/vanilla/index.d.ts +465 -0
  26. package/dist/ui/vanilla/index.mjs +5044 -0
  27. package/dist/ui/vanilla/index.mjs.map +1 -0
  28. package/dist/ui/vanilla/jaaq-vanilla-bundled.min.js +8 -0
  29. package/dist/ui/vanilla/jaaq-vanilla-bundled.min.js.map +1 -0
  30. package/dist/ui/vanilla/jaaq-vanilla.min.js +8 -0
  31. package/dist/ui/vanilla/jaaq-vanilla.min.js.map +1 -0
  32. package/dist/ui/webcomponents/index.cjs +4619 -0
  33. package/dist/ui/webcomponents/index.cjs.map +1 -0
  34. package/dist/ui/webcomponents/index.d.ts +288 -0
  35. package/dist/ui/webcomponents/index.mjs +4614 -0
  36. package/dist/ui/webcomponents/index.mjs.map +1 -0
  37. package/dist/ui/webcomponents/jaaq-webcomponents-bundled.min.js +8 -0
  38. package/dist/ui/webcomponents/jaaq-webcomponents-bundled.min.js.map +1 -0
  39. package/dist/ui/webcomponents/jaaq-webcomponents.min.js +8 -0
  40. package/dist/ui/webcomponents/jaaq-webcomponents.min.js.map +1 -0
  41. package/package.json +42 -2
package/README.md CHANGED
@@ -1,150 +1,791 @@
1
- # JAAQ TypeScript SDK
1
+ # JAAQ JavaScript/TypeScript SDK
2
2
 
3
- A lightweight, type-safe SDK for interacting with the JAAQ API. Built with TypeScript and optimized for modern JavaScript frameworks.
3
+ Official JavaScript SDK for the JAAQ API.
4
+
5
+ It includes:
6
+
7
+ - Core API client (`createJaaqClient`, `JaaqClient`) for Videos + Collections
8
+ - UI players (vanilla JS classes, web components, React wrappers)
9
+ - A CDN-hosted iframe embed player (`embed.html`) with `postMessage` control
4
10
 
5
11
  ## Installation
6
12
 
7
13
  ```bash
8
- npm install @jaaq/jaaq-sdk-js
14
+ pnpm add @jaaq/jaaq-sdk-js
9
15
  ```
10
16
 
11
17
  ```bash
12
- yarn add @jaaq/jaaq-sdk-js
18
+ npm install @jaaq/jaaq-sdk-js
13
19
  ```
14
20
 
15
21
  ```bash
16
- pnpm add @jaaq/jaaq-sdk-js
22
+ yarn add @jaaq/jaaq-sdk-js
17
23
  ```
18
24
 
19
- ## Quick Start
25
+ ## Exports
26
+
27
+ - Core SDK: `@jaaq/jaaq-sdk-js`
28
+ - UI (vanilla + helpers): `@jaaq/jaaq-sdk-js/ui`
29
+ - React wrappers: `@jaaq/jaaq-sdk-js/ui/react`
30
+ - Web components: `@jaaq/jaaq-sdk-js/ui/webcomponents`
31
+
32
+ ## Core SDK
20
33
 
21
- ### Using JaaqClient (Class-based)
34
+ ### Create a client
22
35
 
23
36
  ```typescript
24
- import { JaaqClient } from '@jaaq/jaaq-sdk-js';
37
+ import { createJaaqClient } from '@jaaq/jaaq-sdk-js';
25
38
 
26
- const client = JaaqClient.init({
27
- apiKey: '<YOUR_API_KEY>',
28
- clientId: '<YOUR_CLIENT_ID>',
39
+ const client = createJaaqClient({
40
+ apiKey: 'YOUR_API_KEY',
41
+ clientId: 'YOUR_CLIENT_ID',
29
42
  });
30
43
  ```
31
44
 
32
- ### Using createJaaqClient (Functional)
45
+ Class-based init:
33
46
 
34
47
  ```typescript
35
- import { createJaaqClient } from '@jaaq/jaaq-sdk-js';
48
+ import { JaaqClient } from '@jaaq/jaaq-sdk-js';
36
49
 
37
- const client = createJaaqClient({
38
- apiKey: '<YOUR_API_KEY>',
39
- clientId: '<YOUR_CLIENT_ID>',
50
+ const client = JaaqClient.init({
51
+ apiKey: 'YOUR_API_KEY',
52
+ clientId: 'YOUR_CLIENT_ID',
40
53
  });
41
54
  ```
42
55
 
43
- ## Usage
44
-
45
- ### Accessing Resources
56
+ ### Use resources
46
57
 
47
58
  ```typescript
48
59
  const video = await client.videos.getById('video-id');
49
60
  const collections = await client.collections.list();
61
+ const collection = await client.collections.getById('collection-id');
50
62
  ```
51
63
 
52
- ### React Example: Basic Video
64
+ ### Client config
53
65
 
54
- ```typescript
55
- import { useEffect, useRef } from "react";
56
- import { createJaaqClient } from "@jaaq/jaaq-sdk-js";
57
-
58
- const API_KEY = import.meta.env.VITE_JAAQ_API_KEY;
59
- const CLIENT_ID = import.meta.env.VITE_JAAQ_CLIENT_ID;
60
-
61
- export default function VideoExample({ id }: { id: string }) {
62
- const videoRef = useRef<HTMLVideoElement | null>(null);
63
-
64
- useEffect(() => {
65
- (async () => {
66
- const client = createJaaqClient({
67
- apiKey: API_KEY,
68
- clientId: CLIENT_ID
69
- });
70
- const resp = await client.videos.getById(id);
71
- const url = resp.video.videoUrl;
72
- videoRef.current.src = url;
73
- })();
74
- }, [id]);
66
+ | Option | Type | Required | Default | Notes |
67
+ | ----------- | -------------- | -------- | ---------------------- | ------------------------------------ |
68
+ | `apiKey` | `string` | Yes | - | Required for authentication |
69
+ | `clientId` | `string` | Yes | - | Used as subscription identifier |
70
+ | `baseUrl` | `string` | No | `https://api.jaaq.app` | API base URL |
71
+ | `fetch` | `typeof fetch` | No | `globalThis.fetch` | Provide for Node/custom runtimes |
72
+ | `timeoutMs` | `number` | No | - | Passed through to HTTP client config |
75
73
 
76
- return (
77
- <video
78
- ref={videoRef}
79
- autoPlay
80
- controls
81
- />
82
- );
83
- }
74
+ ## UI Overview
75
+
76
+ There are 3 ways to use the player UI:
77
+
78
+ - Web components (recommended): `<jaaq-video-player>`, `<jaaq-collection-player>`
79
+ - React wrappers: `VideoPlayer`, `CollectionPlayer`
80
+ - Vanilla JS classes: `JaaqVideoPlayer`, `JaaqCollectionPlayer`
81
+
82
+ All implementations expose the same core capabilities:
83
+
84
+ - Custom controls + HLS playback
85
+ - Events for player state
86
+ - Imperative methods (`play`, `pause`, `seek`, `setVolume`, `getState`, `destroy`)
87
+
88
+ ## Web Components
89
+
90
+ ### Install
91
+
92
+ ```bash
93
+ pnpm add @jaaq/jaaq-sdk-js
84
94
  ```
85
95
 
86
- ### React Example: HLS Streaming (.m3u8)
96
+ ### Register
87
97
 
88
- ```typescript
89
- import { useEffect, useRef } from "react";
90
- import { createJaaqClient } from "@jaaq/jaaq-sdk-js";
91
- import Hls from "hls.js";
98
+ Auto-register (recommended):
99
+
100
+ ```javascript
101
+ import '@jaaq/jaaq-sdk-js/ui/webcomponents';
102
+ ```
103
+
104
+ Manual registration:
105
+
106
+ ```javascript
107
+ import { registerJaaqComponents } from '@jaaq/jaaq-sdk-js/ui/webcomponents';
108
+
109
+ registerJaaqComponents();
110
+ ```
92
111
 
93
- const API_KEY = import.meta.env.VITE_JAAQ_API_KEY!;
94
- const CLIENT_ID = import.meta.env.VITE_JAAQ_CLIENT_ID!;
112
+ ### `<jaaq-video-player>`
95
113
 
96
- export default function VideoExample({ id }: { id: string }) {
97
- const videoRef = useRef<HTMLVideoElement | null>(null);
114
+ Declarative usage:
98
115
 
99
- useEffect(() => {
100
- let hls: Hls | undefined;
116
+ ```html
117
+ <jaaq-video-player
118
+ video-id="your-video-id"
119
+ api-key="your-api-key"
120
+ client-id="your-client-id"
121
+ autoplay="false"
122
+ width="100%"
123
+ ></jaaq-video-player>
124
+ ```
125
+
126
+ Programmatic usage:
127
+
128
+ ```javascript
129
+ import '@jaaq/jaaq-sdk-js/ui/webcomponents';
130
+
131
+ const player = document.createElement('jaaq-video-player');
132
+ player.setAttribute('video-id', 'your-video-id');
133
+ player.setAttribute('api-key', 'your-api-key');
134
+ player.setAttribute('client-id', 'your-client-id');
135
+
136
+ player.addEventListener('jaaq:loaded', (e) => {
137
+ console.log(e.detail);
138
+ });
139
+
140
+ document.body.appendChild(player);
141
+ ```
142
+
143
+ #### Attributes
144
+
145
+ | Attribute | Type | Required | Default | Notes |
146
+ | ------------------ | --------- | ----------- | ---------------------- | ----------------------------------- |
147
+ | `video-id` | `string` | Yes | - | Video ID |
148
+ | `api-key` | `string` | Conditional | - | Required if you don’t set `.client` |
149
+ | `client-id` | `string` | Conditional | - | Required if you don’t set `.client` |
150
+ | `base-url` | `string` | No | `https://api.jaaq.app` | API base URL |
151
+ | `autoplay` | `boolean` | No | `false` | Any value except `"false"` enables |
152
+ | `width` | `string` | No | `100%` | Container width |
153
+ | `height` | `string` | No | `auto` | Container height |
154
+ | `controls` | `boolean` | No | `true` | Any value except `"false"` enables |
155
+ | `show-logo` | `boolean` | No | `true` | Any value except `"false"` enables |
156
+ | `show-title` | `boolean` | No | `true` | Any value except `"false"` enables |
157
+ | `show-author` | `boolean` | No | `true` | Any value except `"false"` enables |
158
+ | `show-description` | `boolean` | No | `true` | Any value except `"false"` enables |
159
+ | `show-captions` | `boolean` | No | `true` | Any value except `"false"` enables |
160
+
161
+ #### Properties / methods
162
+
163
+ | Member | Type |
164
+ | ------------------- | --------------------------- |
165
+ | `client` | `JaaqClient` |
166
+ | `play()` | `() => void` |
167
+ | `pause()` | `() => void` |
168
+ | `seek(time)` | `(time: number) => void` |
169
+ | `setVolume(volume)` | `(volume: number) => void` |
170
+ | `toggleMute()` | `() => void` |
171
+ | `getState()` | `() => PlayerState \| null` |
172
+ | `destroy()` | `() => void` |
173
+
174
+ #### Events
175
+
176
+ | Event | Payload (`event.detail`) |
177
+ | ----------------------- | ------------------------ |
178
+ | `jaaq:loaded` | `VideoDTO` |
179
+ | `jaaq:play` | - |
180
+ | `jaaq:pause` | - |
181
+ | `jaaq:timeupdate` | `number` |
182
+ | `jaaq:volumechange` | `number` |
183
+ | `jaaq:ended` | - |
184
+ | `jaaq:error` | `Error` |
185
+ | `jaaq:fullscreenchange` | `boolean` |
186
+
187
+ ### `<jaaq-collection-player>`
188
+
189
+ This renders a carousel of videos in a collection.
190
+
191
+ Declarative usage:
192
+
193
+ ```html
194
+ <jaaq-collection-player
195
+ collection-id="your-collection-id"
196
+ api-key="your-api-key"
197
+ client-id="your-client-id"
198
+ autoplay="false"
199
+ show-arrows="true"
200
+ show-dots="true"
201
+ ></jaaq-collection-player>
202
+ ```
203
+
204
+ Programmatic usage:
205
+
206
+ ```javascript
207
+ import '@jaaq/jaaq-sdk-js/ui/webcomponents';
208
+
209
+ const player = document.createElement('jaaq-collection-player');
210
+ player.setAttribute('collection-id', 'your-collection-id');
211
+ player.setAttribute('api-key', 'your-api-key');
212
+ player.setAttribute('client-id', 'your-client-id');
213
+
214
+ player.addEventListener('jaaq:collection:loaded', (e) => {
215
+ console.log(e.detail);
216
+ });
217
+
218
+ document.body.appendChild(player);
219
+ ```
220
+
221
+ #### Attributes
222
+
223
+ | Attribute | Type | Required | Default | Notes |
224
+ | ----------------- | --------- | ----------- | ---------------------- | ----------------------------------- |
225
+ | `collection-id` | `string` | Yes | - | Collection ID |
226
+ | `api-key` | `string` | Conditional | - | Required if you don’t set `.client` |
227
+ | `client-id` | `string` | Conditional | - | Required if you don’t set `.client` |
228
+ | `subscription-id` | `string` | No | - | Accepted attribute |
229
+ | `base-url` | `string` | No | `https://api.jaaq.app` | API base URL |
230
+ | `autoplay` | `boolean` | No | `false` | Any value except `"false"` enables |
231
+ | `show-arrows` | `boolean` | No | `true` | Any value except `"false"` enables |
232
+ | `show-dots` | `boolean` | No | `true` | Any value except `"false"` enables |
233
+
234
+ #### Properties / methods
101
235
 
102
- (async () => {
103
- const client = createJaaqClient({ apiKey: API_KEY, clientId: CLIENT_ID });
104
- const resp = await client.videos.getById(id);
105
- const url = resp.video.videoUrl;
106
- const video = videoRef.current;
107
- if (!video || !url) return;
236
+ | Member | Type |
237
+ | ----------------- | ----------------------------- |
238
+ | `client` | `JaaqClient` |
239
+ | `refresh()` | `() => void` |
240
+ | `next()` | `() => void` |
241
+ | `prev()` | `() => void` |
242
+ | `go(index)` | `(index: number) => void` |
243
+ | `destroy()` | `() => void` |
244
+ | `getCollection()` | `() => CollectionDTO \| null` |
108
245
 
109
- if (Hls.isSupported()) {
110
- hls = new Hls();
111
- hls.loadSource(url);
112
- hls.attachMedia(video);
113
- }
114
- })();
246
+ #### Events
115
247
 
116
- return () => hls?.destroy();
117
- }, [id]);
248
+ | Event | Payload (`event.detail`) |
249
+ | ----------------------------- | ------------------------------------------------------ |
250
+ | `jaaq:collection:loaded` | `CollectionDTO` |
251
+ | `jaaq:collection:slidechange` | `{ index: number; video: CollectionDTO['videos'][0] }` |
252
+ | `jaaq:collection:error` | `Error` |
118
253
 
254
+ ## React
255
+
256
+ Install:
257
+
258
+ ```bash
259
+ pnpm add @jaaq/jaaq-sdk-js
260
+ ```
261
+
262
+ ### `<VideoPlayer />`
263
+
264
+ ```tsx
265
+ import { VideoPlayer } from '@jaaq/jaaq-sdk-js/ui/react';
266
+
267
+ export function App() {
268
+ return (
269
+ <VideoPlayer
270
+ videoId="your-video-id"
271
+ apiKey="your-api-key"
272
+ clientId="your-client-id"
273
+ autoplay={false}
274
+ controls={true}
275
+ showLogo={true}
276
+ showTitle={true}
277
+ showAuthor={true}
278
+ showDescription={true}
279
+ showCaptions={true}
280
+ onLoaded={(video) => console.log(video)}
281
+ onError={(err) => console.error(err)}
282
+ />
283
+ );
284
+ }
285
+ ```
286
+
287
+ #### Props
288
+
289
+ `VideoPlayer` props are `PlayerConfig` plus callbacks.
290
+
291
+ | Prop | Type | Required | Default |
292
+ | -------------------- | --------------------------------- | ----------- | ------- |
293
+ | `videoId` | `string` | Yes | - |
294
+ | `apiKey` | `string` | Conditional | - |
295
+ | `clientId` | `string` | Conditional | - |
296
+ | `client` | `JaaqClient` | Conditional | - |
297
+ | `baseUrl` | `string` | No | - |
298
+ | `autoplay` | `boolean` | No | `false` |
299
+ | `controls` | `boolean` | No | `true` |
300
+ | `width` | `string` | No | `100%` |
301
+ | `height` | `string` | No | `auto` |
302
+ | `className` | `string` | No | `''` |
303
+ | `showLogo` | `boolean` | No | `true` |
304
+ | `showTitle` | `boolean` | No | `true` |
305
+ | `showAuthor` | `boolean` | No | `true` |
306
+ | `showDescription` | `boolean` | No | `true` |
307
+ | `showCaptions` | `boolean` | No | `true` |
308
+ | `onPlay` | `() => void` | No | - |
309
+ | `onPause` | `() => void` | No | - |
310
+ | `onEnded` | `() => void` | No | - |
311
+ | `onTimeUpdate` | `(time: number) => void` | No | - |
312
+ | `onVolumeChange` | `(volume: number) => void` | No | - |
313
+ | `onFullscreenChange` | `(isFullscreen: boolean) => void` | No | - |
314
+ | `onLoaded` | `(video: VideoDTO) => void` | No | - |
315
+ | `onError` | `(error: Error) => void` | No | - |
316
+ | `showInfo` | `boolean` | No | `false` |
317
+
318
+ #### Ref handle
319
+
320
+ | Method | Type |
321
+ | ------------------- | --------------------------- |
322
+ | `play()` | `() => void` |
323
+ | `pause()` | `() => void` |
324
+ | `seek(time)` | `(time: number) => void` |
325
+ | `setVolume(volume)` | `(volume: number) => void` |
326
+ | `toggleMute()` | `() => void` |
327
+ | `getState()` | `() => PlayerState \| null` |
328
+ | `destroy()` | `() => void` |
329
+
330
+ ### `<CollectionPlayer />`
331
+
332
+ ```tsx
333
+ import { CollectionPlayer } from '@jaaq/jaaq-sdk-js/ui/react';
334
+
335
+ export function App() {
119
336
  return (
120
- <video
121
- ref={videoRef}
122
- autoPlay
123
- controls
337
+ <CollectionPlayer
338
+ collectionId="your-collection-id"
339
+ apiKey="your-api-key"
340
+ clientId="your-client-id"
341
+ autoplay={false}
342
+ showArrows={true}
343
+ showDots={true}
344
+ onLoaded={(collection) => console.log(collection)}
345
+ onSlideChange={(data) => console.log(data)}
346
+ onError={(err) => console.error(err)}
124
347
  />
125
348
  );
126
349
  }
127
350
  ```
128
351
 
129
- ## Configuration
352
+ #### Props
353
+
354
+ | Prop | Type | Required | Default |
355
+ | ---------------- | ---------------------------------------------------------------------- | ----------- | ------- |
356
+ | `collectionId` | `string` | Yes | - |
357
+ | `apiKey` | `string` | Conditional | - |
358
+ | `clientId` | `string` | Conditional | - |
359
+ | `subscriptionId` | `string` | No | - |
360
+ | `client` | `JaaqClient` | Conditional | - |
361
+ | `baseUrl` | `string` | No | - |
362
+ | `autoplay` | `boolean` | No | `false` |
363
+ | `showArrows` | `boolean` | No | `true` |
364
+ | `showDots` | `boolean` | No | `true` |
365
+ | `className` | `string` | No | `''` |
366
+ | `onLoaded` | `(collection: CollectionDTO) => void` | No | - |
367
+ | `onSlideChange` | `(data: { index: number; video: CollectionDTO['videos'][0] }) => void` | No | - |
368
+ | `onError` | `(error: Error) => void` | No | - |
369
+
370
+ #### Ref handle
371
+
372
+ | Method | Type |
373
+ | ----------------- | ----------------------------- |
374
+ | `refresh()` | `() => void` |
375
+ | `next()` | `() => void` |
376
+ | `prev()` | `() => void` |
377
+ | `go(index)` | `(index: number) => void` |
378
+ | `destroy()` | `() => void` |
379
+ | `getCollection()` | `() => CollectionDTO \| null` |
380
+
381
+ ## Vanilla UI
382
+
383
+ ### `JaaqVideoPlayer`
384
+
385
+ ```javascript
386
+ import { JaaqVideoPlayer } from '@jaaq/jaaq-sdk-js/ui';
387
+
388
+ const player = new JaaqVideoPlayer('#container', {
389
+ videoId: 'your-video-id',
390
+ apiKey: 'your-api-key',
391
+ clientId: 'your-client-id',
392
+ autoplay: false,
393
+ controls: true,
394
+ showLogo: true,
395
+ showTitle: true,
396
+ showAuthor: true,
397
+ showDescription: true,
398
+ showCaptions: true,
399
+ });
400
+
401
+ player.on('loaded', (video) => console.log(video));
402
+ player.on('error', (err) => console.error(err));
403
+ ```
404
+
405
+ #### Config (`PlayerConfig`)
406
+
407
+ | Option | Type | Required | Default |
408
+ | ----------------- | ------------ | ----------- | ------- |
409
+ | `videoId` | `string` | Yes | - |
410
+ | `apiKey` | `string` | Conditional | - |
411
+ | `clientId` | `string` | Conditional | - |
412
+ | `client` | `JaaqClient` | Conditional | - |
413
+ | `baseUrl` | `string` | No | - |
414
+ | `autoplay` | `boolean` | No | `false` |
415
+ | `controls` | `boolean` | No | `true` |
416
+ | `width` | `string` | No | `100%` |
417
+ | `height` | `string` | No | `auto` |
418
+ | `className` | `string` | No | `''` |
419
+ | `showLogo` | `boolean` | No | `true` |
420
+ | `showTitle` | `boolean` | No | `true` |
421
+ | `showAuthor` | `boolean` | No | `true` |
422
+ | `showDescription` | `boolean` | No | `true` |
423
+ | `showCaptions` | `boolean` | No | `true` |
424
+
425
+ #### Events
426
+
427
+ | Event | Payload |
428
+ | ------------------ | ---------- |
429
+ | `loaded` | `VideoDTO` |
430
+ | `play` | - |
431
+ | `pause` | - |
432
+ | `timeupdate` | `number` |
433
+ | `volumechange` | `number` |
434
+ | `ended` | - |
435
+ | `error` | `Error` |
436
+ | `fullscreenchange` | `boolean` |
437
+
438
+ #### Methods
439
+
440
+ | Method | Type |
441
+ | ------------------- | -------------------------- |
442
+ | `play()` | `() => void` |
443
+ | `pause()` | `() => void` |
444
+ | `seek(time)` | `(time: number) => void` |
445
+ | `setVolume(volume)` | `(volume: number) => void` |
446
+ | `toggleMute()` | `() => void` |
447
+ | `getState()` | `() => PlayerState` |
448
+ | `destroy()` | `() => void` |
449
+
450
+ ### `JaaqCollectionPlayer`
451
+
452
+ ```javascript
453
+ import { JaaqCollectionPlayer } from '@jaaq/jaaq-sdk-js/ui';
454
+
455
+ const player = new JaaqCollectionPlayer('#container', {
456
+ collectionId: 'your-collection-id',
457
+ apiKey: 'your-api-key',
458
+ clientId: 'your-client-id',
459
+ autoplay: false,
460
+ showArrows: true,
461
+ showDots: true,
462
+ });
463
+
464
+ player.on('loaded', (collection) => console.log(collection));
465
+ player.on('slidechange', (data) => console.log(data));
466
+ player.on('error', (err) => console.error(err));
467
+ ```
468
+
469
+ #### Config
470
+
471
+ | Option | Type | Required | Default |
472
+ | -------------- | ------------ | ----------- | ------- |
473
+ | `collectionId` | `string` | Yes | - |
474
+ | `apiKey` | `string` | Conditional | - |
475
+ | `clientId` | `string` | Conditional | - |
476
+ | `client` | `JaaqClient` | Conditional | - |
477
+ | `baseUrl` | `string` | No | - |
478
+ | `autoplay` | `boolean` | No | `false` |
479
+ | `showArrows` | `boolean` | No | `true` |
480
+ | `showDots` | `boolean` | No | `true` |
481
+ | `className` | `string` | No | `''` |
482
+
483
+ #### Events
484
+
485
+ | Event | Payload |
486
+ | ------------- | ------------------------------------ |
487
+ | `loaded` | `CollectionDTO` |
488
+ | `slidechange` | `{ index: number; video: VideoDTO }` |
489
+ | `error` | `Error` |
490
+
491
+ #### Methods
492
+
493
+ | Method | Type |
494
+ | ----------------- | ----------------------------- |
495
+ | `refresh()` | `() => void` |
496
+ | `next()` | `() => void` |
497
+ | `prev()` | `() => void` |
498
+ | `go(index)` | `(index: number) => void` |
499
+ | `destroy()` | `() => void` |
500
+ | `getCollection()` | `() => CollectionDTO \| null` |
501
+
502
+ ## Auto-init (data attributes)
503
+
504
+ This is a declarative auto-init API for the vanilla player.
505
+
506
+ ### HTML
507
+
508
+ ```html
509
+ <div
510
+ data-jaaq-player
511
+ data-api-key="your-api-key"
512
+ data-client-id="your-client-id"
513
+ data-video-id="your-video-id"
514
+ data-autoplay="false"
515
+ data-width="100%"
516
+ data-height="auto"
517
+ ></div>
518
+ ```
519
+
520
+ ### JS API
521
+
522
+ ```javascript
523
+ import { JaaqPlayer } from '@jaaq/jaaq-sdk-js/ui';
524
+
525
+ JaaqPlayer.init();
526
+
527
+ const player = JaaqPlayer.getPlayer('[data-video-id="your-video-id"]');
528
+ player?.play();
529
+ ```
530
+
531
+ ### Data attributes
532
+
533
+ Required:
534
+
535
+ - `data-api-key`
536
+ - `data-client-id`
537
+ - `data-video-id`
538
+
539
+ Optional:
540
+
541
+ - `data-autoplay` (`true` or `false`)
542
+ - `data-width`
543
+ - `data-height`
544
+ - `data-base-url`
545
+ - `data-class-name`
546
+
547
+ ## CDN Usage
548
+
549
+ CI publishes files under the `jaaq-sdk-js/latest/` prefix. Embed HTML files are also available under `jaaq-sdk-js/latest/embed/` for compatibility.
550
+
551
+ Base URL:
552
+
553
+ - `https://cdn.jaaq.app/jaaq-sdk-js/latest/`
554
+
555
+ ### Available files (published by CI)
556
+
557
+ | File | Description | Global |
558
+ | ----------------------------------- | --------------------------------------------------- | ------------------- |
559
+ | `jaaq-sdk.min.js` | Core SDK (UMD) | `JaaqSDK` |
560
+ | `jaaq-ui.min.js` | UI (UMD, requires `Hls` global for HLS) | `JaaqUI` |
561
+ | `jaaq-ui-bundled.min.js` | UI (UMD, bundled incl. hls.js) | `JaaqUI` |
562
+ | `jaaq-webcomponents.min.js` | Web components (UMD, requires `Hls` global for HLS) | `JaaqWebComponents` |
563
+ | `jaaq-webcomponents-bundled.min.js` | Web components (UMD, bundled incl. hls.js) | `JaaqWebComponents` |
564
+ | `embed.html` | Iframe embed player (single video) | - |
565
+ | `embed-collection.html` | Iframe embed carousel player (collection) | - |
566
+
567
+ ### Core SDK (UMD)
568
+
569
+ ```html
570
+ <script src="https://cdn.jaaq.app/jaaq-sdk-js/latest/jaaq-sdk.min.js"></script>
571
+ <script>
572
+ const client = JaaqSDK.createJaaqClient({
573
+ apiKey: 'YOUR_API_KEY',
574
+ clientId: 'YOUR_CLIENT_ID',
575
+ });
576
+
577
+ client.videos.getById('video-id').then((video) => console.log(video));
578
+ </script>
579
+ ```
580
+
581
+ ### UI (UMD)
582
+
583
+ Bundled (no external HLS dependency):
584
+
585
+ ```html
586
+ <script src="https://cdn.jaaq.app/jaaq-sdk-js/latest/jaaq-ui-bundled.min.js"></script>
587
+ <script>
588
+ const player = new JaaqUI.JaaqVideoPlayer(document.getElementById('player'), {
589
+ apiKey: 'YOUR_API_KEY',
590
+ clientId: 'YOUR_CLIENT_ID',
591
+ videoId: 'YOUR_VIDEO_ID',
592
+ });
593
+ </script>
594
+ ```
595
+
596
+ Non-bundled (load hls.js separately):
597
+
598
+ ```html
599
+ <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
600
+ <script src="https://cdn.jaaq.app/jaaq-sdk-js/latest/jaaq-ui.min.js"></script>
601
+ ```
602
+
603
+ ### Web components (UMD)
604
+
605
+ Bundled (no external HLS dependency):
606
+
607
+ ```html
608
+ <script src="https://cdn.jaaq.app/jaaq-sdk-js/latest/jaaq-webcomponents-bundled.min.js"></script>
609
+ <jaaq-video-player video-id="YOUR_VIDEO_ID" api-key="YOUR_API_KEY" client-id="YOUR_CLIENT_ID"></jaaq-video-player>
610
+ ```
611
+
612
+ Non-bundled (load hls.js separately):
613
+
614
+ ```html
615
+ <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
616
+ <script src="https://cdn.jaaq.app/jaaq-sdk-js/latest/jaaq-webcomponents.min.js"></script>
617
+ ```
618
+
619
+ ### React from CDN
620
+
621
+ The CI pipeline does not publish the React UMD bundle to `https://cdn.jaaq.app/jaaq-sdk-js/latest/`.
622
+
623
+ Use npm:
624
+
625
+ ```bash
626
+ pnpm add @jaaq/jaaq-sdk-js
627
+ ```
628
+
629
+ ```tsx
630
+ import { VideoPlayer } from '@jaaq/jaaq-sdk-js/ui/react';
631
+ ```
632
+
633
+ ## Embed via Iframe
634
+
635
+ ### URL
636
+
637
+ ```html
638
+ <iframe
639
+ src="https://cdn.jaaq.app/jaaq-sdk-js/latest/embed.html?apiKey=YOUR_API_KEY&clientId=YOUR_CLIENT_ID&videoId=YOUR_VIDEO_ID&autoplay=false"
640
+ width="800"
641
+ height="450"
642
+ frameborder="0"
643
+ allowfullscreen
644
+ ></iframe>
645
+ ```
646
+
647
+ ### URL parameters
648
+
649
+ | Parameter | Required | Notes |
650
+ | ---------- | -------- | ------------------------- |
651
+ | `apiKey` | Yes | API key |
652
+ | `clientId` | Yes | Client ID |
653
+ | `videoId` | Yes | Video ID |
654
+ | `autoplay` | No | `true`, `false`, `1`, `0` |
655
+ | `width` | No | CSS width |
656
+ | `height` | No | CSS height |
657
+ | `baseUrl` | No | API base URL |
658
+
659
+ ### postMessage protocol
660
+
661
+ Send commands:
662
+
663
+ ```javascript
664
+ const iframe = document.querySelector('iframe');
665
+
666
+ iframe.contentWindow.postMessage(
667
+ {
668
+ type: 'jaaq-player-command',
669
+ command: 'play',
670
+ },
671
+ '*',
672
+ );
673
+ ```
674
+
675
+ Commands:
676
+
677
+ | Command | args |
678
+ | ------------ | -------------------- |
679
+ | `play` | - |
680
+ | `pause` | - |
681
+ | `toggleMute` | - |
682
+ | `setVolume` | `{ volume: number }` |
683
+ | `seek` | `{ time: number }` |
684
+ | `getState` | - |
685
+
686
+ Listen for events:
687
+
688
+ ```javascript
689
+ window.addEventListener('message', (event) => {
690
+ if (event.data?.type !== 'jaaq-player-event') return;
691
+ console.log(event.data.event, event.data.data);
692
+ });
693
+ ```
694
+
695
+ Events:
696
+
697
+ | Event | data |
698
+ | ------------------ | --------------------------------------------------- |
699
+ | `ready` | `null` |
700
+ | `loaded` | `{ id: string; title?: string; question?: string }` |
701
+ | `play` | `null` |
702
+ | `pause` | `null` |
703
+ | `timeupdate` | `{ currentTime: number }` |
704
+ | `volumechange` | `{ volume: number }` |
705
+ | `ended` | `null` |
706
+ | `fullscreenchange` | `{ isFullscreen: boolean }` |
707
+ | `error` | `{ message: string }` |
708
+ | `state` | `PlayerState` |
709
+
710
+ ## Collection Carousel Embed
711
+
712
+ Embed a collection of videos in a carousel format:
713
+
714
+ ```html
715
+ <iframe
716
+ src="https://cdn.jaaq.app/jaaq-sdk-js/latest/embed-collection.html?apiKey=YOUR_API_KEY&clientId=YOUR_CLIENT_ID&collectionId=YOUR_COLLECTION_ID&autoplay=false"
717
+ width="100%"
718
+ height="600"
719
+ frameborder="0"
720
+ allow="autoplay"
721
+ ></iframe>
722
+ ```
723
+
724
+ ### URL parameters
725
+
726
+ | Parameter | Required | Notes |
727
+ | -------------- | -------- | ------------------------- |
728
+ | `apiKey` | Yes | API key |
729
+ | `clientId` | Yes | Client ID |
730
+ | `collectionId` | Yes | Collection ID |
731
+ | `autoplay` | No | `true`, `false`, `1`, `0` |
732
+ | `baseUrl` | No | API base URL |
733
+
734
+ ### postMessage protocol
735
+
736
+ Send commands:
737
+
738
+ ```javascript
739
+ const iframe = document.querySelector('iframe');
740
+
741
+ iframe.contentWindow.postMessage(
742
+ {
743
+ type: 'jaaq-collection-command',
744
+ command: 'next',
745
+ },
746
+ '*',
747
+ );
748
+ ```
749
+
750
+ Commands:
751
+
752
+ | Command | args |
753
+ | --------------- | ------------------- |
754
+ | `next` | - |
755
+ | `prev` | - |
756
+ | `goToSlide` | `{ index: number }` |
757
+ | `refresh` | - |
758
+ | `getCollection` | - |
759
+
760
+ Listen for events:
761
+
762
+ ```javascript
763
+ window.addEventListener('message', (event) => {
764
+ if (event.data?.type !== 'jaaq-collection-event') return;
765
+ console.log(event.data.event, event.data.data);
766
+ });
767
+ ```
768
+
769
+ Events:
130
770
 
131
- | Option | Type | Required | Default | Description |
132
- | ----------- | ---------- | -------- | ---------------------- | ------------------------------- |
133
- | `apiKey` | `string` | Yes | - | Your JAAQ API key |
134
- | `clientId` | `string` | Yes | - | Your client identifier |
135
- | `baseUrl` | `string` | No | `https://api.jaaq.app` | API base URL |
136
- | `fetch` | `Function` | No | `globalThis.fetch` | Custom fetch implementation |
137
- | `timeoutMs` | `number` | No | - | Request timeout in milliseconds |
771
+ | Event | data |
772
+ | ------------- | --------------------------------------------------------------- |
773
+ | `ready` | `null` |
774
+ | `loaded` | `{ collection: { id, name, description }, videoCount: number }` |
775
+ | `slidechange` | `{ index: number, video: { id, title, question } }` |
776
+ | `error` | `{ message: string }` |
138
777
 
139
- ## Resources
778
+ ## Examples
140
779
 
141
- - [Development Guide](./DEVELOPMENT.md) - For SDK contributors and developers
142
- - [Release Notes](./RELEASE.md) - Version history and changelog
780
+ - [examples/README.md](./examples/README.md)
781
+ - [examples/browser/README.md](./examples/browser/README.md)
782
+ - [examples/react-vite/README.md](./examples/react-vite/README.md)
143
783
 
144
- ## TypeScript Support
784
+ ## Development
145
785
 
146
- This SDK is written in TypeScript and includes complete type definitions. Types are automatically generated from the JAAQ OpenAPI specification.
786
+ - [DEVELOPMENT.md](./DEVELOPMENT.md)
787
+ - [RELEASE.md](./RELEASE.md)
147
788
 
148
789
  ## License
149
790
 
150
- MIT
791
+ ISC