@jaaq/jaaq-sdk-js 1.1.1 → 1.2.0-dev-ec79f7e-20260605

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 (45) hide show
  1. package/README.md +18 -7
  2. package/dist/embed/embed-collection.html +17 -4
  3. package/dist/embed/embed.html +15 -3
  4. package/dist/index.cjs +57 -11
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.ts +100 -24
  7. package/dist/index.mjs +56 -12
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/jaaq-sdk.min.js +1 -1
  10. package/dist/jaaq-sdk.min.js.map +1 -1
  11. package/dist/ui/index.cjs +102 -17
  12. package/dist/ui/index.cjs.map +1 -1
  13. package/dist/ui/index.d.ts +89 -10
  14. package/dist/ui/index.mjs +102 -17
  15. package/dist/ui/index.mjs.map +1 -1
  16. package/dist/ui/jaaq-ui-bundled.min.js +2 -2
  17. package/dist/ui/jaaq-ui-bundled.min.js.map +1 -1
  18. package/dist/ui/jaaq-ui.min.js +2 -2
  19. package/dist/ui/jaaq-ui.min.js.map +1 -1
  20. package/dist/ui/react/index.cjs +78 -18
  21. package/dist/ui/react/index.cjs.map +1 -1
  22. package/dist/ui/react/index.d.ts +84 -7
  23. package/dist/ui/react/index.mjs +78 -18
  24. package/dist/ui/react/index.mjs.map +1 -1
  25. package/dist/ui/react/jaaq-ui-react.min.js +2 -2
  26. package/dist/ui/react/jaaq-ui-react.min.js.map +1 -1
  27. package/dist/ui/vanilla/index.cjs +102 -17
  28. package/dist/ui/vanilla/index.cjs.map +1 -1
  29. package/dist/ui/vanilla/index.d.ts +89 -10
  30. package/dist/ui/vanilla/index.mjs +102 -17
  31. package/dist/ui/vanilla/index.mjs.map +1 -1
  32. package/dist/ui/vanilla/jaaq-vanilla-bundled.min.js +2 -2
  33. package/dist/ui/vanilla/jaaq-vanilla-bundled.min.js.map +1 -1
  34. package/dist/ui/vanilla/jaaq-vanilla.min.js +2 -2
  35. package/dist/ui/vanilla/jaaq-vanilla.min.js.map +1 -1
  36. package/dist/ui/webcomponents/index.cjs +74 -14
  37. package/dist/ui/webcomponents/index.cjs.map +1 -1
  38. package/dist/ui/webcomponents/index.d.ts +86 -9
  39. package/dist/ui/webcomponents/index.mjs +74 -14
  40. package/dist/ui/webcomponents/index.mjs.map +1 -1
  41. package/dist/ui/webcomponents/jaaq-webcomponents-bundled.min.js +2 -2
  42. package/dist/ui/webcomponents/jaaq-webcomponents-bundled.min.js.map +1 -1
  43. package/dist/ui/webcomponents/jaaq-webcomponents.min.js +2 -2
  44. package/dist/ui/webcomponents/jaaq-webcomponents.min.js.map +1 -1
  45. package/package.json +38 -35
@@ -27,10 +27,6 @@ type VideoDTO = {
27
27
  creatorBiography?: string;
28
28
  };
29
29
 
30
- type VideosResource = {
31
- getById(_id: string): Promise<VideoDTO>;
32
- };
33
-
34
30
  type CollectionDTO = {
35
31
  id: string;
36
32
  name: string;
@@ -40,33 +36,111 @@ type CollectionDTO = {
40
36
  videos: VideoDTO[];
41
37
  };
42
38
 
39
+ type CreatorV2DTO = {
40
+ id: string;
41
+ name: string;
42
+ biography: string;
43
+ imageUrl: string;
44
+ type: string;
45
+ };
46
+
47
+ type CtaV2DTO = {
48
+ url?: string;
49
+ label?: string;
50
+ labelColor?: string;
51
+ };
52
+
53
+ type SubtitleV2DTO = {
54
+ code: string;
55
+ url: string;
56
+ default?: boolean;
57
+ };
58
+
59
+ type VideoV2DTO = {
60
+ id: string;
61
+ videoId: string;
62
+ question: string;
63
+ transcription: string;
64
+ subtitles: SubtitleV2DTO[];
65
+ videoUrl: string;
66
+ tags: string[];
67
+ severity: number | null;
68
+ duration: number;
69
+ description: string;
70
+ creator?: CreatorV2DTO;
71
+ cta?: CtaV2DTO;
72
+ allowFeedbackWidget?: boolean;
73
+ };
74
+
75
+ type VideoGroupV2DTO = {
76
+ id: string;
77
+ title: string;
78
+ videos: VideoV2DTO[];
79
+ };
80
+
81
+ type CollectionV2DTO = {
82
+ id: string;
83
+ name: string;
84
+ description: string;
85
+ imageUrl: string;
86
+ idleVideo: {
87
+ id: string;
88
+ duration: number;
89
+ videoUrl: string;
90
+ } | null;
91
+ videoGroups: VideoGroupV2DTO[];
92
+ };
93
+
94
+ type VideosResource = {
95
+ getById(_id: string): Promise<VideoDTO>;
96
+ };
97
+
43
98
  type CollectionsResource = {
44
99
  list(): Promise<CollectionDTO[]>;
45
100
  getById(_id: string): Promise<CollectionDTO>;
46
101
  };
47
102
 
103
+ type VideosResourceV2 = {
104
+ getById(_id: string): Promise<VideoV2DTO>;
105
+ };
106
+
107
+ type CollectionsResourceV2 = {
108
+ list(): Promise<CollectionV2DTO[]>;
109
+ getById(_id: string): Promise<CollectionV2DTO>;
110
+ };
111
+
48
112
  interface SDKConfig {
49
113
  baseUrl?: string;
114
+ apiVersion?: string;
50
115
  apiKey: string;
51
116
  clientId: string;
52
117
  fetch?: FetchLike;
53
118
  timeoutMs?: number;
54
119
  }
55
- declare class JaaqClient {
56
- readonly videos: VideosResource;
57
- readonly collections: CollectionsResource;
120
+ type V1 = {
121
+ videos: VideosResource;
122
+ collections: CollectionsResource;
123
+ };
124
+ type V2 = {
125
+ videos: VideosResourceV2;
126
+ collections: CollectionsResourceV2;
127
+ };
128
+ type ClientVersion = V1 | V2;
129
+ declare class JaaqClient<T extends ClientVersion = V1> {
130
+ readonly videos: T['videos'];
131
+ readonly collections: T['collections'];
58
132
  private constructor();
59
133
  /**
60
134
  * Public "friend" constructor that remains inside the class boundary.
61
135
  * This method is callable from the module-level build function
62
136
  * without exposing `new JaaqClient(...)` to consumers.
63
137
  */
64
- static fromHttp(http: HttpClient): JaaqClient;
138
+ static fromHttp<T extends ClientVersion = V1>(http: HttpClient, apiVersion: string): JaaqClient<T>;
65
139
  /**
66
140
  * OO-friendly static initializer.
67
141
  * Delegates to the single source of truth: `buildClient`.
68
142
  */
69
- static init(config: SDKConfig): JaaqClient;
143
+ static init<T extends ClientVersion = V1>(config: SDKConfig): JaaqClient<T>;
70
144
  }
71
145
 
72
146
  /**
@@ -83,6 +157,8 @@ type PlayerConfig = {
83
157
  client?: JaaqClient;
84
158
  /** Custom API base URL */
85
159
  baseUrl?: string;
160
+ /** Custom API version */
161
+ apiVersion?: string;
86
162
  /** Whether to automatically start playback when video loads */
87
163
  autoplay?: boolean;
88
164
  /** Whether to show player controls */
@@ -161,7 +237,7 @@ type PlayerEventCallback<T> = (_data: T) => void;
161
237
  * Video settings that can be passed to carousel components
162
238
  * Excludes carousel-specific props that are handled separately
163
239
  */
164
- type VideoSettings = Omit<PlayerConfig, 'videoId' | 'apiKey' | 'clientId' | 'baseUrl' | 'client' | 'autoplay'>;
240
+ type VideoSettings = Omit<PlayerConfig, 'videoId' | 'apiKey' | 'clientId' | 'baseUrl' | 'apiVersion' | 'client' | 'autoplay'>;
165
241
 
166
242
  declare class JaaqVideoPlayer {
167
243
  private container;
@@ -252,6 +328,7 @@ type CollectionPlayerConfig = {
252
328
  apiKey?: string;
253
329
  clientId?: string;
254
330
  baseUrl?: string;
331
+ apiVersion?: string;
255
332
  autoplay?: boolean;
256
333
  showArrows?: boolean;
257
334
  showDots?: boolean;
@@ -282,6 +359,7 @@ declare class JaaqCollectionPlayer {
282
359
  private render;
283
360
  private initCarousel;
284
361
  private showLoading;
362
+ private getVideosFromCollection;
285
363
  private renderCarousel;
286
364
  private initSplide;
287
365
  private handleSlideChange;
@@ -437,6 +515,7 @@ declare class JaaqCollectionPlayerElement extends HTMLElement {
437
515
  disconnectedCallback(): void;
438
516
  attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
439
517
  private getBooleanAttr;
518
+ private getVideosFromCollection;
440
519
  private render;
441
520
  private initCarousel;
442
521
  private showLoading;
@@ -9,16 +9,22 @@ async function parseJson(res) {
9
9
  return undefined;
10
10
  return res.json();
11
11
  }
12
- function joinUrl(baseUrl, clientId, path) {
12
+ function joinUrl(baseUrl, apiVersion, clientId, path) {
13
13
  // return path if it is an absolute URL
14
14
  if (/^https?:\/\//i.test(path))
15
15
  return path;
16
16
  const base = baseUrl.replace(/\/+$/, '');
17
17
  const relative = path.replace(/^\/+/, '');
18
- return `${base}/b2b/v1/subscription/${encodeURIComponent(clientId)}${relative.startsWith('/') ? relative : `/${relative}`}`;
18
+ return `${base}/b2b/${apiVersion}/subscription/${encodeURIComponent(clientId)}${relative.startsWith('/') ? relative : `/${relative}`}`;
19
+ }
20
+ function convertToValidAPIVersion(version) {
21
+ const v = version.toLowerCase();
22
+ if (v === 'v1' || v === 'v2')
23
+ return v;
24
+ return 'v1'; // default to v1 if invalid version provided
19
25
  }
20
26
  function createHttpClient(config) {
21
- const { baseUrl, apiKey, clientId, fetch: fetchImpl } = config;
27
+ const { baseUrl, apiKey, clientId, fetch: fetchImpl, apiVersion } = config;
22
28
  const f = fetchImpl ?? globalThis.fetch;
23
29
  if (!f) {
24
30
  throw new Error('No fetch implementation found. Provide one in SDKConfig.fetch for Node or custom environments.');
@@ -27,7 +33,7 @@ function createHttpClient(config) {
27
33
  'Content-Type': 'application/json',
28
34
  'x-api-key': apiKey,
29
35
  };
30
- const fullUrl = (path) => joinUrl(baseUrl, clientId, path);
36
+ const fullUrl = (path) => joinUrl(baseUrl, convertToValidAPIVersion(apiVersion), clientId, path);
31
37
  const request = async (method, path, init, body) => {
32
38
  const reqInit = {
33
39
  method,
@@ -76,20 +82,51 @@ function createCollectionsResource(http) {
76
82
  };
77
83
  }
78
84
 
85
+ function createVideosResourceV2(http) {
86
+ return {
87
+ async getById(id) {
88
+ const path = `/videos/${encodeURIComponent(id)}`;
89
+ const response = await http.get(path);
90
+ return response.video;
91
+ },
92
+ };
93
+ }
94
+
95
+ function createCollectionsResourceV2(http) {
96
+ return {
97
+ async list() {
98
+ const path = '/collections';
99
+ const response = await http.get(path);
100
+ return response.collections;
101
+ },
102
+ async getById(id) {
103
+ const path = `/collections/${encodeURIComponent(id)}`;
104
+ const response = await http.get(path);
105
+ return response.collection;
106
+ },
107
+ };
108
+ }
109
+
79
110
  const BASE_URL = "https://api.jaaq.app";
80
111
  class JaaqClient {
81
112
  // Keep constructor private to enforce controlled instantiation.
82
- constructor(http) {
83
- this.videos = createVideosResource(http);
84
- this.collections = createCollectionsResource(http);
113
+ constructor(http, apiVersion) {
114
+ if (apiVersion === 'v2') {
115
+ this.videos = createVideosResourceV2(http);
116
+ this.collections = createCollectionsResourceV2(http);
117
+ }
118
+ else {
119
+ this.videos = createVideosResource(http);
120
+ this.collections = createCollectionsResource(http);
121
+ }
85
122
  }
86
123
  /**
87
124
  * Public "friend" constructor that remains inside the class boundary.
88
125
  * This method is callable from the module-level build function
89
126
  * without exposing `new JaaqClient(...)` to consumers.
90
127
  */
91
- static fromHttp(http) {
92
- return new JaaqClient(http);
128
+ static fromHttp(http, apiVersion) {
129
+ return new JaaqClient(http, apiVersion);
93
130
  }
94
131
  /**
95
132
  * OO-friendly static initializer.
@@ -112,14 +149,15 @@ function createJaaqClient(config) {
112
149
  * The constructor stays private; instantiation is funneled via `JaaqClient.fromHttp`.
113
150
  */
114
151
  function buildClient(config) {
115
- const { baseUrl = BASE_URL, apiKey, clientId, fetch: fetchImpl } = config;
152
+ const { baseUrl = BASE_URL, apiKey, clientId, fetch: fetchImpl, apiVersion = 'v1' } = config;
116
153
  const http = createHttpClient({
117
154
  baseUrl,
118
155
  apiKey,
119
156
  clientId,
120
157
  fetch: fetchImpl ?? globalThis.fetch,
158
+ apiVersion,
121
159
  });
122
- return JaaqClient.fromHttp(http);
160
+ return JaaqClient.fromHttp(http, apiVersion);
123
161
  }
124
162
 
125
163
  /**
@@ -4051,6 +4089,7 @@ class JaaqCollectionPlayer {
4051
4089
  apiKey: config.apiKey,
4052
4090
  clientId: config.clientId,
4053
4091
  baseUrl: config.baseUrl || BASE_URL,
4092
+ apiVersion: config.apiVersion,
4054
4093
  });
4055
4094
  }
4056
4095
  else {
@@ -4082,7 +4121,8 @@ class JaaqCollectionPlayer {
4082
4121
  throw new Error('Client is not initialized');
4083
4122
  }
4084
4123
  this.collectionData = await this.client.collections.getById(collectionId);
4085
- if (!this.collectionData.videos || this.collectionData.videos.length === 0) {
4124
+ const videos = this.getVideosFromCollection(this.collectionData);
4125
+ if (videos.length === 0) {
4086
4126
  this.emitError(new Error('No videos found in collection'));
4087
4127
  return;
4088
4128
  }
@@ -4103,6 +4143,21 @@ class JaaqCollectionPlayer {
4103
4143
  </div>
4104
4144
  `;
4105
4145
  }
4146
+ getVideosFromCollection(collection) {
4147
+ if (collection.videos && collection.videos.length > 0) {
4148
+ return collection.videos;
4149
+ }
4150
+ if (collection.videoGroups && collection.videoGroups.length > 0) {
4151
+ const videos = [];
4152
+ collection.videoGroups.forEach((group) => {
4153
+ if (group.videos && group.videos.length > 0) {
4154
+ videos.push(...group.videos);
4155
+ }
4156
+ });
4157
+ return videos;
4158
+ }
4159
+ return [];
4160
+ }
4106
4161
  renderCarousel() {
4107
4162
  if (!this.playerElement || !this.collectionData)
4108
4163
  return;
@@ -4113,7 +4168,8 @@ class JaaqCollectionPlayer {
4113
4168
  track.className = 'splide__track';
4114
4169
  const list = document.createElement('ul');
4115
4170
  list.className = 'splide__list';
4116
- this.collectionData.videos.forEach((video) => {
4171
+ const videos = this.getVideosFromCollection(this.collectionData);
4172
+ videos.forEach((video) => {
4117
4173
  const slide = document.createElement('li');
4118
4174
  slide.className = 'splide__slide';
4119
4175
  const player = document.createElement('jaaq-video-player');
@@ -4124,6 +4180,8 @@ class JaaqCollectionPlayer {
4124
4180
  player.setAttribute('client-id', this.config.clientId);
4125
4181
  if (this.config.baseUrl)
4126
4182
  player.setAttribute('base-url', this.config.baseUrl);
4183
+ if (this.config.apiVersion)
4184
+ player.setAttribute('api-version', this.config.apiVersion);
4127
4185
  player.setAttribute('autoplay', 'false');
4128
4186
  player.setAttribute('width', '100%');
4129
4187
  if (this.config.videoSettings) {
@@ -4193,7 +4251,8 @@ class JaaqCollectionPlayer {
4193
4251
  this.splide.on('moved', (newIndex) => {
4194
4252
  this.handleSlideChange(newIndex);
4195
4253
  if (this.collectionData) {
4196
- this.emit('slidechange', { index: newIndex, video: this.collectionData.videos[newIndex] });
4254
+ const videos = this.getVideosFromCollection(this.collectionData);
4255
+ this.emit('slidechange', { index: newIndex, video: videos[newIndex] });
4197
4256
  }
4198
4257
  });
4199
4258
  this.splide.mount();
@@ -4338,6 +4397,10 @@ function parseDataAttributes(element) {
4338
4397
  if (baseUrl) {
4339
4398
  config.baseUrl = baseUrl;
4340
4399
  }
4400
+ const apiVersion = element.getAttribute('data-api-version');
4401
+ if (apiVersion) {
4402
+ config.apiVersion = apiVersion;
4403
+ }
4341
4404
  const className = element.getAttribute('data-class-name');
4342
4405
  if (className) {
4343
4406
  config.className = className;
@@ -4589,6 +4652,7 @@ class JaaqVideoPlayerElement extends HTMLElement {
4589
4652
  const apiKey = this.getAttribute('api-key');
4590
4653
  const clientId = this.getAttribute('client-id');
4591
4654
  const baseUrl = this.getAttribute('base-url') || undefined;
4655
+ const apiVersion = this.getAttribute('api-version') || undefined;
4592
4656
  const autoplay = this.hasAttribute('autoplay') && this.getAttribute('autoplay') !== 'false';
4593
4657
  const controls = !this.hasAttribute('controls') || this.getAttribute('controls') !== 'false';
4594
4658
  const showLogo = !this.hasAttribute('show-logo') || this.getAttribute('show-logo') !== 'false';
@@ -4608,6 +4672,7 @@ class JaaqVideoPlayerElement extends HTMLElement {
4608
4672
  clientId: clientId ?? undefined,
4609
4673
  client: this.clientInstance || undefined,
4610
4674
  baseUrl,
4675
+ apiVersion,
4611
4676
  autoplay,
4612
4677
  controls,
4613
4678
  showLogo,
@@ -4846,6 +4911,21 @@ class JaaqCollectionPlayerElement extends HTMLElement {
4846
4911
  return defaultValue;
4847
4912
  return v !== 'false';
4848
4913
  }
4914
+ getVideosFromCollection(collection) {
4915
+ if (collection.videos && collection.videos.length > 0) {
4916
+ return collection.videos;
4917
+ }
4918
+ if (collection.videoGroups && collection.videoGroups.length > 0) {
4919
+ const videos = [];
4920
+ collection.videoGroups.forEach((group) => {
4921
+ if (group.videos && group.videos.length > 0) {
4922
+ videos.push(...group.videos);
4923
+ }
4924
+ });
4925
+ return videos;
4926
+ }
4927
+ return [];
4928
+ }
4849
4929
  render() {
4850
4930
  if (!this.shadowRoot)
4851
4931
  return;
@@ -4872,6 +4952,7 @@ class JaaqCollectionPlayerElement extends HTMLElement {
4872
4952
  const apiKey = this.getAttribute('api-key');
4873
4953
  const clientId = this.getAttribute('client-id');
4874
4954
  const baseUrl = this.getAttribute('base-url') || undefined;
4955
+ const apiVersion = this.getAttribute('api-version') || undefined;
4875
4956
  if (!this.clientInstance && !apiKey && !clientId) {
4876
4957
  this.emitError(new Error('Either client property or api-key and client-id attributes are required'));
4877
4958
  return;
@@ -4883,9 +4964,11 @@ class JaaqCollectionPlayerElement extends HTMLElement {
4883
4964
  apiKey: apiKey,
4884
4965
  clientId: clientId,
4885
4966
  baseUrl: baseUrl || BASE_URL,
4967
+ apiVersion: apiVersion,
4886
4968
  });
4887
4969
  this.collectionData = await client.collections.getById(collectionId);
4888
- if (!this.collectionData.videos || this.collectionData.videos.length === 0) {
4970
+ const videos = this.getVideosFromCollection(this.collectionData);
4971
+ if (videos.length === 0) {
4889
4972
  this.emitError(new Error('No videos found in collection'));
4890
4973
  return;
4891
4974
  }
@@ -4933,7 +5016,8 @@ class JaaqCollectionPlayerElement extends HTMLElement {
4933
5016
  console.warn('[CollectionPlayer] Failed to parse video-settings attribute', e);
4934
5017
  }
4935
5018
  }
4936
- this.collectionData.videos.forEach((video) => {
5019
+ const videos = this.getVideosFromCollection(this.collectionData);
5020
+ videos.forEach((video) => {
4937
5021
  const slide = document.createElement('li');
4938
5022
  slide.className = 'splide__slide';
4939
5023
  const player = document.createElement('jaaq-video-player');
@@ -5015,8 +5099,9 @@ class JaaqCollectionPlayerElement extends HTMLElement {
5015
5099
  Components: this.splide?.Components,
5016
5100
  });
5017
5101
  this.handleSlideChange(newIndex);
5102
+ const videos = this.collectionData ? this.getVideosFromCollection(this.collectionData) : [];
5018
5103
  this.dispatchEvent(new CustomEvent('jaaq:collection:slidechange', {
5019
- detail: { index: newIndex, video: this.collectionData?.videos[newIndex] },
5104
+ detail: { index: newIndex, video: videos[newIndex] },
5020
5105
  bubbles: true,
5021
5106
  composed: true,
5022
5107
  }));