@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 +20 -0
- package/README.md +20 -0
- package/dist/index.cjs +22 -2
- package/dist/index.d.ts +15 -15
- package/dist/index.js +22 -2
- package/llms.txt +2 -0
- package/package.json +1 -1
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
|
|
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
|
-
|
|
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
|
-
|
|
186
|
+
videoId: string;
|
|
187
187
|
title: string;
|
|
188
188
|
text: string;
|
|
189
189
|
timestamp: number;
|
|
190
|
-
|
|
191
|
-
|
|
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
|
-
|
|
199
|
-
|
|
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
|
-
|
|
207
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
299
|
+
videoId: string;
|
|
299
300
|
title: string;
|
|
300
|
-
|
|
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
|
|
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
|
-
|
|
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)
|