@boldvideo/bold-js 1.8.0 → 1.9.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/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @boldvideo/bold-js
2
2
 
3
+ ## 1.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ff2f021: Transform all API responses to use camelCase (TypeScript/JavaScript convention)
8
+
9
+ **Breaking Changes:**
10
+
11
+ All response types now use camelCase consistently across the entire SDK:
12
+
13
+ - **Videos**: `playback_id` → `playbackId`, `published_at` → `publishedAt`, `stream_url` → `streamUrl`, `meta_data` → `metaData`, `captions_label` → `captionsLabel`, `download_urls` → `downloadUrls`, etc.
14
+ - **Playlists**: `is_private` → `isPrivate`
15
+ - **Settings**: `featured_playlists` → `featuredPlaylists`, `menu_items` → `menuItems`, `theme_config` → `themeConfig`, `ai_avatar` → `aiAvatar`, `logo_url` → `logoUrl`, etc.
16
+ - **Portal/Theme**: `show_chapters` → `showChapters`, `font_body` → `fontBody`, `color_scheme` → `colorScheme`, `css_overrides` → `cssOverrides`, etc.
17
+ - **AI responses**: (already camelCase in v1.8.0)
18
+
19
+ **Internal:**
20
+
21
+ - Applied `camelizeKeys()` transformation in `fetchers.ts` at the transport boundary
22
+ - Updated all type definitions in `types.ts` to use camelCase
23
+
3
24
  ## 1.8.0
4
25
 
5
26
  ### Minor Changes
package/README.md CHANGED
@@ -269,26 +269,32 @@ import type {
269
269
 
270
270
  ---
271
271
 
272
- ## Migration from v1.6.x
272
+ ## Migration from v1.7.x
273
273
 
274
- ### Breaking: Response types now use camelCase
274
+ ### Breaking: All response types now use camelCase
275
275
 
276
- All API responses are now transformed to use idiomatic TypeScript/JavaScript naming:
276
+ **All API responses** (videos, playlists, settings, AI) are now transformed to use idiomatic TypeScript/JavaScript naming:
277
277
 
278
278
  ```typescript
279
- // Before (v1.6.x)
280
- source.video_id
281
- source.timestamp_end
282
- source.playback_id
283
- usage.input_tokens
284
- event.conversation_id
285
-
286
- // After (v1.7.0)
287
- source.videoId
288
- source.timestampEnd
289
- source.playbackId
290
- usage.inputTokens
291
- event.conversationId
279
+ // Before (v1.7.x and earlier)
280
+ video.playback_id
281
+ video.published_at
282
+ video.stream_url
283
+ video.meta_data
284
+ settings.featured_playlists
285
+ settings.menu_items
286
+ settings.theme_config
287
+ playlist.is_private
288
+
289
+ // After (v1.8.0)
290
+ video.playbackId
291
+ video.publishedAt
292
+ video.streamUrl
293
+ video.metaData
294
+ settings.featuredPlaylists
295
+ settings.menuItems
296
+ settings.themeConfig
297
+ playlist.isPrivate
292
298
  ```
293
299
 
294
300
  ### Method Changes
package/dist/index.cjs CHANGED
@@ -39,6 +39,24 @@ module.exports = __toCommonJS(src_exports);
39
39
  // src/lib/client.ts
40
40
  var import_axios = __toESM(require("axios"), 1);
41
41
 
42
+ // src/util/camelize.ts
43
+ var isPlainObject = (value) => value !== null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
44
+ var snakeToCamel = (key) => key.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
45
+ function camelizeKeys(input) {
46
+ if (Array.isArray(input)) {
47
+ return input.map((item) => camelizeKeys(item));
48
+ }
49
+ if (!isPlainObject(input)) {
50
+ return input;
51
+ }
52
+ const out = {};
53
+ for (const [rawKey, value] of Object.entries(input)) {
54
+ const key = snakeToCamel(rawKey);
55
+ out[key] = camelizeKeys(value);
56
+ }
57
+ return out;
58
+ }
59
+
42
60
  // src/lib/fetchers.ts
43
61
  async function get(client, url) {
44
62
  try {
@@ -46,7 +64,7 @@ async function get(client, url) {
46
64
  if (res.status !== 200) {
47
65
  throw new Error(`Unexpected response status: ${res.status}`);
48
66
  }
49
- return res.data;
67
+ return camelizeKeys(res.data);
50
68
  } catch (error) {
51
69
  console.error(`Error fetching data from URL: ${url}`, error);
52
70
  throw error;
@@ -221,24 +239,6 @@ function basicInfos() {
221
239
  };
222
240
  }
223
241
 
224
- // src/util/camelize.ts
225
- var isPlainObject = (value) => value !== null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
226
- var snakeToCamel = (key) => key.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
227
- function camelizeKeys(input) {
228
- if (Array.isArray(input)) {
229
- return input.map((item) => camelizeKeys(item));
230
- }
231
- if (!isPlainObject(input)) {
232
- return input;
233
- }
234
- const out = {};
235
- for (const [rawKey, value] of Object.entries(input)) {
236
- const key = snakeToCamel(rawKey);
237
- out[key] = camelizeKeys(value);
238
- }
239
- return out;
240
- }
241
-
242
242
  // src/lib/ai.ts
243
243
  async function* parseSSE(response) {
244
244
  const reader = response.body?.getReader();
package/dist/index.d.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  type VideoAttachment = {
2
2
  id: string;
3
3
  title: string;
4
- file_url: string;
5
- file_size?: number;
6
- file_type?: string;
4
+ fileUrl: string;
5
+ fileSize?: number;
6
+ fileType?: string;
7
7
  };
8
8
  type VideoDownloadUrls = {
9
9
  mp4?: string;
10
10
  audio?: string;
11
- legacy_mp4?: string;
11
+ legacyMp4?: string;
12
12
  };
13
13
  type VideoSubtitles = {
14
14
  label: string;
@@ -27,27 +27,27 @@ type VideoMetadata = {
27
27
  };
28
28
  type Video = {
29
29
  captions: string;
30
- captions_label: string;
31
- captions_lang: string;
30
+ captionsLabel: string;
31
+ captionsLang: string;
32
32
  description: string | null;
33
33
  duration: number;
34
34
  id: string;
35
- imported_from: string | null;
36
- legacy_video_url: string | null;
37
- playback_id: string;
38
- published_at: string;
39
- stream_url: string;
35
+ importedFrom: string | null;
36
+ legacyVideoUrl: string | null;
37
+ playbackId: string;
38
+ publishedAt: string;
39
+ streamUrl: string;
40
40
  teaser: string | null;
41
41
  thumbnail: string;
42
42
  title: string;
43
43
  type: string;
44
- meta_data: VideoMetadata;
44
+ metaData: VideoMetadata;
45
45
  chapters?: string;
46
46
  attachments?: VideoAttachment[];
47
47
  cta?: any | null;
48
- download_urls?: VideoDownloadUrls;
49
- internal_id: string;
50
- playback_speed?: number;
48
+ downloadUrls?: VideoDownloadUrls;
49
+ internalId: string;
50
+ playbackSpeed?: number;
51
51
  subtitles?: VideoSubtitles;
52
52
  tags?: string[];
53
53
  transcript?: VideoTranscript;
@@ -55,20 +55,20 @@ type Video = {
55
55
  type Playlist = {
56
56
  description?: string;
57
57
  id: string;
58
- is_private: boolean;
58
+ isPrivate: boolean;
59
59
  title: string;
60
60
  type: string;
61
61
  videos: Video[];
62
62
  };
63
63
  type MenuItem = {
64
64
  icon: string;
65
- is_ext: boolean;
65
+ isExt: boolean;
66
66
  label: string;
67
67
  url: string;
68
68
  };
69
69
  type PortalDisplay = {
70
- show_chapters: boolean;
71
- show_transcripts: boolean;
70
+ showChapters: boolean;
71
+ showTranscripts: boolean;
72
72
  };
73
73
  type AssistantConfig = {
74
74
  headline: string;
@@ -76,36 +76,36 @@ type AssistantConfig = {
76
76
  suggestions: string[];
77
77
  };
78
78
  type PortalLayout = {
79
- assistant_config: AssistantConfig | null;
80
- show_playlists: boolean;
79
+ assistantConfig: AssistantConfig | null;
80
+ showPlaylists: boolean;
81
81
  type: string;
82
- videos_limit: number;
82
+ videosLimit: number;
83
83
  };
84
84
  type PortalNavigation = {
85
- show_ai_search: boolean;
86
- show_header: boolean;
87
- show_search: boolean;
85
+ showAiSearch: boolean;
86
+ showHeader: boolean;
87
+ showSearch: boolean;
88
88
  };
89
89
  type PortalTheme = {
90
90
  background: string;
91
91
  foreground: string;
92
92
  primary: string;
93
- font_body: string;
94
- font_header: string;
95
- logo_url: string;
96
- logo_dark_url: string;
97
- logo_width: number;
98
- logo_height: number;
99
- header_size: string;
93
+ fontBody: string;
94
+ fontHeader: string;
95
+ logoUrl: string;
96
+ logoDarkUrl: string;
97
+ logoWidth: number;
98
+ logoHeight: number;
99
+ headerSize: string;
100
100
  layout: string;
101
101
  radius: string;
102
- color_scheme: "toggle" | "light" | "dark";
102
+ colorScheme: "toggle" | "light" | "dark";
103
103
  light: ThemeColors;
104
104
  dark: ThemeColors;
105
- css_overrides: string | null;
105
+ cssOverrides: string | null;
106
106
  };
107
107
  type Portal = {
108
- color_scheme?: 'toggle' | 'light' | 'dark';
108
+ colorScheme?: 'toggle' | 'light' | 'dark';
109
109
  display: PortalDisplay;
110
110
  layout: PortalLayout;
111
111
  navigation: PortalNavigation;
@@ -115,21 +115,21 @@ type ThemeColors = {
115
115
  accent: string;
116
116
  background: string;
117
117
  foreground: string;
118
- accent_foreground: string;
118
+ accentForeground: string;
119
119
  muted: string;
120
- muted_foreground: string;
120
+ mutedForeground: string;
121
121
  border: string;
122
122
  ring: string;
123
123
  surface: string;
124
124
  };
125
125
  type ThemeConfig = {
126
126
  radius: string;
127
- color_scheme: "toggle" | "light" | "dark";
127
+ colorScheme: "toggle" | "light" | "dark";
128
128
  light: ThemeColors;
129
129
  dark: ThemeColors;
130
130
  };
131
131
  type AccountAI = {
132
- avatar_url: string;
132
+ avatarUrl: string;
133
133
  enabled: boolean;
134
134
  greeting: string;
135
135
  name: string;
@@ -141,7 +141,7 @@ type PersonaEnabled = {
141
141
  enabled: true;
142
142
  name: string;
143
143
  greeting: string;
144
- conversation_starters: string[];
144
+ conversationStarters: string[];
145
145
  };
146
146
  type PersonaDisabled = {
147
147
  enabled: false;
@@ -149,33 +149,33 @@ type PersonaDisabled = {
149
149
  type Persona = PersonaEnabled | PersonaDisabled;
150
150
  type Account = {
151
151
  ai: AccountAI;
152
- ai_search: AccountAISearch;
152
+ aiSearch: AccountAISearch;
153
153
  name: string;
154
154
  persona: Persona;
155
155
  slug: string;
156
156
  };
157
157
  type Settings = {
158
- featured_playlists: Playlist[];
159
- menu_items: MenuItem[];
160
- ai_avatar: string;
161
- ai_name: string;
162
- ai_greeting?: string;
163
- has_ai: boolean;
158
+ featuredPlaylists: Playlist[];
159
+ menuItems: MenuItem[];
160
+ aiAvatar: string;
161
+ aiName: string;
162
+ aiGreeting?: string;
163
+ hasAi: boolean;
164
164
  account: Account;
165
- favicon_url?: string;
166
- logo_dark_url?: string;
167
- logo_url?: string;
168
- meta_data: {
169
- channel_name: string;
165
+ faviconUrl?: string;
166
+ logoDarkUrl?: string;
167
+ logoUrl?: string;
168
+ metaData: {
169
+ channelName: string;
170
170
  description: string;
171
171
  image: string | null;
172
- no_seo: boolean;
173
- social_graph_image_url?: string;
172
+ noSeo: boolean;
173
+ socialGraphImageUrl?: string;
174
174
  title: string;
175
- title_suffix: string;
175
+ titleSuffix: string;
176
176
  };
177
177
  portal: Portal;
178
- theme_config: ThemeConfig;
178
+ themeConfig: ThemeConfig;
179
179
  version: string;
180
180
  };
181
181
  /**
package/dist/index.js CHANGED
@@ -1,6 +1,24 @@
1
1
  // src/lib/client.ts
2
2
  import axios from "axios";
3
3
 
4
+ // src/util/camelize.ts
5
+ var isPlainObject = (value) => value !== null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
6
+ var snakeToCamel = (key) => key.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
7
+ function camelizeKeys(input) {
8
+ if (Array.isArray(input)) {
9
+ return input.map((item) => camelizeKeys(item));
10
+ }
11
+ if (!isPlainObject(input)) {
12
+ return input;
13
+ }
14
+ const out = {};
15
+ for (const [rawKey, value] of Object.entries(input)) {
16
+ const key = snakeToCamel(rawKey);
17
+ out[key] = camelizeKeys(value);
18
+ }
19
+ return out;
20
+ }
21
+
4
22
  // src/lib/fetchers.ts
5
23
  async function get(client, url) {
6
24
  try {
@@ -8,7 +26,7 @@ async function get(client, url) {
8
26
  if (res.status !== 200) {
9
27
  throw new Error(`Unexpected response status: ${res.status}`);
10
28
  }
11
- return res.data;
29
+ return camelizeKeys(res.data);
12
30
  } catch (error) {
13
31
  console.error(`Error fetching data from URL: ${url}`, error);
14
32
  throw error;
@@ -183,24 +201,6 @@ function basicInfos() {
183
201
  };
184
202
  }
185
203
 
186
- // src/util/camelize.ts
187
- var isPlainObject = (value) => value !== null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
188
- var snakeToCamel = (key) => key.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
189
- function camelizeKeys(input) {
190
- if (Array.isArray(input)) {
191
- return input.map((item) => camelizeKeys(item));
192
- }
193
- if (!isPlainObject(input)) {
194
- return input;
195
- }
196
- const out = {};
197
- for (const [rawKey, value] of Object.entries(input)) {
198
- const key = snakeToCamel(rawKey);
199
- out[key] = camelizeKeys(value);
200
- }
201
- return out;
202
- }
203
-
204
204
  // src/lib/ai.ts
205
205
  async function* parseSSE(response) {
206
206
  const reader = response.body?.getReader();
package/llms.txt CHANGED
@@ -110,7 +110,7 @@ Key types exported:
110
110
  - `ChatOptions`, `SearchOptions`
111
111
  - `RecommendationsOptions`, `RecommendationsResponse`, `Recommendation`, `RecommendationVideo`
112
112
 
113
- All response types use camelCase (e.g., `source.videoId`, `source.timestampEnd`, `usage.inputTokens`).
113
+ All response types use camelCase (e.g., `video.playbackId`, `video.publishedAt`, `settings.featuredPlaylists`, `source.videoId`).
114
114
 
115
115
  ## Links
116
116
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@boldvideo/bold-js",
3
3
  "license": "MIT",
4
- "version": "1.8.0",
4
+ "version": "1.9.0",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
7
7
  "types": "dist/index.d.ts",