@boldvideo/bold-js 1.7.0 → 1.8.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,25 @@
1
1
  # @boldvideo/bold-js
2
2
 
3
+ ## 1.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 065d7ea: Transform all API responses to use camelCase (TypeScript/JavaScript convention)
8
+
9
+ **Breaking Changes:**
10
+
11
+ - **All response types now use camelCase** (was snake_case). API responses are transformed at the SDK boundary.
12
+ - `video_id` → `videoId`
13
+ - `timestamp_end` → `timestampEnd`
14
+ - `playback_id` → `playbackId`
15
+ - `input_tokens` → `inputTokens`
16
+ - `conversation_id` → `conversationId`
17
+
18
+ **Internal:**
19
+
20
+ - Added `camelizeKeys` utility for deep snake_case → camelCase transformation
21
+ - Applied transformation in `jsonRequest()` and `parseSSE()` at the transport boundary
22
+
3
23
  ## 1.7.0
4
24
 
5
25
  ### Minor Changes
package/README.md CHANGED
@@ -271,6 +271,26 @@ import type {
271
271
 
272
272
  ## Migration from v1.6.x
273
273
 
274
+ ### Breaking: Response types now use camelCase
275
+
276
+ All API responses are now transformed to use idiomatic TypeScript/JavaScript naming:
277
+
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
292
+ ```
293
+
274
294
  ### Method Changes
275
295
 
276
296
  | Old | New | Notes |
package/dist/index.cjs CHANGED
@@ -221,6 +221,24 @@ function basicInfos() {
221
221
  };
222
222
  }
223
223
 
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
+
224
242
  // src/lib/ai.ts
225
243
  async function* parseSSE(response) {
226
244
  const reader = response.body?.getReader();
@@ -248,7 +266,8 @@ async function* parseSSE(response) {
248
266
  if (!json)
249
267
  continue;
250
268
  try {
251
- const event = JSON.parse(json);
269
+ const raw = JSON.parse(json);
270
+ const event = camelizeKeys(raw);
252
271
  yield event;
253
272
  if (event.type === "message_complete" || event.type === "error") {
254
273
  await reader.cancel();
@@ -298,7 +317,8 @@ async function jsonRequest(path, body, config) {
298
317
  if (!response.ok) {
299
318
  throw new Error(`AI request failed: ${response.status} ${response.statusText}`);
300
319
  }
301
- return response.json();
320
+ const raw = await response.json();
321
+ return camelizeKeys(raw);
302
322
  }
303
323
  function createAI(config) {
304
324
  async function chat(options) {
package/dist/index.d.ts CHANGED
@@ -183,29 +183,28 @@ type Settings = {
183
183
  */
184
184
  interface Source {
185
185
  id: string;
186
- video_id: string;
186
+ videoId: string;
187
187
  title: string;
188
188
  text: string;
189
189
  timestamp: number;
190
- timestamp_end: number;
191
- playback_id: string;
190
+ timestampEnd: number;
191
+ playbackId: string;
192
192
  speaker?: string;
193
193
  }
194
194
  /**
195
195
  * Token usage statistics
196
196
  */
197
197
  interface AIUsage {
198
- input_tokens: number;
199
- output_tokens: number;
198
+ inputTokens: number;
199
+ outputTokens: number;
200
200
  }
201
201
  /**
202
202
  * SSE event types for AI streaming responses
203
203
  */
204
204
  type AIEvent = {
205
205
  type: "message_start";
206
- id: string;
207
- conversation_id?: string;
208
- video_id?: string;
206
+ conversationId?: string;
207
+ videoId?: string;
209
208
  } | {
210
209
  type: "sources";
211
210
  sources: Source[];
@@ -221,8 +220,7 @@ type AIEvent = {
221
220
  recommendations: Recommendation[];
222
221
  } | {
223
222
  type: "message_complete";
224
- id: string;
225
- conversation_id?: string;
223
+ conversationId?: string;
226
224
  content: string;
227
225
  sources: Source[];
228
226
  usage?: AIUsage;
@@ -236,10 +234,13 @@ type AIEvent = {
236
234
  retryable: boolean;
237
235
  };
238
236
  /**
239
- * Non-streaming AI response
237
+ * Non-streaming AI response for /ai/chat, /ai/videos/:id/chat, and /ai/search
240
238
  */
241
239
  interface AIResponse {
242
- id: string;
240
+ conversationId?: string;
241
+ videoId?: string;
242
+ /** @deprecated Use conversationId instead. Will be removed in v2. */
243
+ id?: string;
243
244
  content: string;
244
245
  sources: Source[];
245
246
  usage: AIUsage;
@@ -295,9 +296,9 @@ interface SearchOptions {
295
296
  * A recommended video with relevance score
296
297
  */
297
298
  interface RecommendationVideo {
298
- video_id: string;
299
+ videoId: string;
299
300
  title: string;
300
- playback_id: string;
301
+ playbackId: string;
301
302
  relevance: number;
302
303
  reason: string;
303
304
  }
@@ -328,7 +329,6 @@ type RecommendOptions = RecommendationsOptions;
328
329
  * Non-streaming response for recommendations endpoint
329
330
  */
330
331
  interface RecommendationsResponse {
331
- id: string;
332
332
  recommendations: Recommendation[];
333
333
  guidance: string;
334
334
  sources: Source[];
package/dist/index.js CHANGED
@@ -183,6 +183,24 @@ function basicInfos() {
183
183
  };
184
184
  }
185
185
 
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
+
186
204
  // src/lib/ai.ts
187
205
  async function* parseSSE(response) {
188
206
  const reader = response.body?.getReader();
@@ -210,7 +228,8 @@ async function* parseSSE(response) {
210
228
  if (!json)
211
229
  continue;
212
230
  try {
213
- const event = JSON.parse(json);
231
+ const raw = JSON.parse(json);
232
+ const event = camelizeKeys(raw);
214
233
  yield event;
215
234
  if (event.type === "message_complete" || event.type === "error") {
216
235
  await reader.cancel();
@@ -260,7 +279,8 @@ async function jsonRequest(path, body, config) {
260
279
  if (!response.ok) {
261
280
  throw new Error(`AI request failed: ${response.status} ${response.statusText}`);
262
281
  }
263
- return response.json();
282
+ const raw = await response.json();
283
+ return camelizeKeys(raw);
264
284
  }
265
285
  function createAI(config) {
266
286
  async function chat(options) {
package/llms.txt CHANGED
@@ -110,6 +110,8 @@ 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`).
114
+
113
115
  ## Links
114
116
 
115
117
  - [GitHub](https://github.com/boldvideo/bold-js)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@boldvideo/bold-js",
3
3
  "license": "MIT",
4
- "version": "1.7.0",
4
+ "version": "1.8.0",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
7
7
  "types": "dist/index.d.ts",