@bitbitpress/client 0.1.0 → 0.1.1

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 (2) hide show
  1. package/README.md +473 -2
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -33,6 +33,477 @@ await client.user.authenticate('your-user\'s-auth-sso-token');
33
33
 
34
34
  **Note:** You must call `authenticate()` before using any other user methods (recommendations, synthesize, etc.).
35
35
 
36
- ### API
36
+ ### API Reference
37
37
 
38
- See API.md for more details or reference your control room API docs: https://your-control-room.api.dev.bitbitpress.com/docs
38
+ - [BitBitPressClient](#bitbitpressclient)
39
+ - [Authentication](#authentication)
40
+ - [User Methods](#user-methods)
41
+ - [authenticate](#authenticate)
42
+ - [token](#token)
43
+ - [recommendations](#recommendations)
44
+ - [signal](#signal)
45
+ - [synthesizeItem](#synthesizeitem)
46
+ - [synthesize](#synthesize)
47
+ - [Types](#types)
48
+
49
+ ## BitBitPressClient
50
+
51
+ Main client class for interacting with the BitBitPress API.
52
+
53
+ ### Constructor
54
+
55
+ ```typescript
56
+ new BitBitPressClient(options: BitBitPressClientOptions)
57
+ ```
58
+
59
+ #### Parameters
60
+
61
+ - `options.baseUrl` (required): Base URL of the API server (your custom Control Room API Url)
62
+ - `options.fetch` (optional): Custom fetch implementation (useful for React Native or Node.js polyfills)
63
+ - `options.headers` (optional): Additional headers to include in all requests
64
+ - `options.timeout` (optional): Request timeout in milliseconds (default: `30000`)
65
+ - `options.synthesizeBatchTimeout` (optional): Batch timeout for `synthesizeItem` in milliseconds (default: `250`)
66
+
67
+ #### Example
68
+
69
+ ```typescript
70
+ const client = new BitBitPressClient({
71
+ baseUrl: 'https://your-control-room.api.dev.bitbitpress.com',
72
+ timeout: 30000,
73
+ synthesizeBatchTimeout: 250,
74
+ });
75
+ ```
76
+
77
+ ### Methods
78
+
79
+ #### `setBaseUrl(baseUrl: string): void`
80
+
81
+ Update the base URL for API requests.
82
+
83
+ #### `get user`
84
+
85
+ Returns an object with user-related API methods. See [User Methods](#user-methods) below.
86
+
87
+ ## Authentication
88
+
89
+ All user methods require authentication. You must call `client.user.authenticate()` before using other user methods.
90
+
91
+ ## User Methods
92
+
93
+ ### authenticate
94
+
95
+ Exchanges an SSO token for an authentication token and automatically sets it for all subsequent user method calls.
96
+
97
+ ```typescript
98
+ await client.user.authenticate(ssoToken: string): Promise<void>
99
+ ```
100
+
101
+ #### Parameters
102
+
103
+ - `ssoToken` (required): The SSO token from your authentication provider
104
+
105
+ #### Returns
106
+
107
+ - `Promise<void>`: Resolves when authentication is complete
108
+
109
+ #### Example
110
+
111
+ ```typescript
112
+ await client.user.authenticate('your-user-s-auth-sso-token');
113
+ // Token is now automatically set for all user methods
114
+ ```
115
+
116
+ #### Throws
117
+
118
+ - `Error`: If token exchange fails or no access token is returned
119
+
120
+ ---
121
+
122
+ ### token
123
+
124
+ Exchanges an SSO token for an authentication token without automatically setting it for user methods.
125
+
126
+ ```typescript
127
+ client.user.token(ssoToken: string): Promise<TokenResponse>
128
+ ```
129
+
130
+ #### Parameters
131
+
132
+ - `ssoToken` (required): The SSO token from your authentication provider
133
+
134
+ #### Returns
135
+
136
+ - `Promise<TokenResponse>`: The token response containing:
137
+ - `idToken?: string`
138
+ - `accessToken?: string`
139
+ - `refreshToken?: string`
140
+ - `expiresIn?: number`
141
+
142
+ #### Example
143
+
144
+ ```typescript
145
+ const tokenResponse = await client.user.token('your-sso-token');
146
+ console.log('Access token:', tokenResponse.accessToken);
147
+ ```
148
+
149
+ ---
150
+
151
+ ### recommendations
152
+
153
+ Get recommended articles for the authenticated user.
154
+
155
+ ```typescript
156
+ client.user.recommendations(options?: RecommendationsRequest): Promise<RecommendationsResponse>
157
+ ```
158
+
159
+ #### Parameters
160
+
161
+ - `options.limit` (optional): Maximum number of recommendations to return
162
+ - `options.cursor` (optional): Cursor from previous response to fetch the next page
163
+
164
+ #### Returns
165
+
166
+ - `Promise<RecommendationsResponse>`: Response containing:
167
+ - `items?: Array<RecommendationItem>`: List of recommended articles
168
+ - `cursor?: string`: Cursor to request the next page, if any
169
+
170
+ #### RecommendationItem
171
+
172
+ - `id?: string`: Your article ID
173
+ - `assetId?: string`: BitBitPress's ID
174
+ - `title?: string`: Article title
175
+ - `summary?: string`: Generated summary
176
+ - `content?: string`: Article content
177
+ - `publishedAt?: string`: Publication date (e.g., "2021-01-01")
178
+ - `score?: number`: Recommendation score (e.g., 0.95)
179
+
180
+ #### Example
181
+
182
+ ```typescript
183
+ const recommendations = await client.user.recommendations({
184
+ limit: 10,
185
+ cursor: 'optional-cursor-from-previous-response',
186
+ });
187
+
188
+ console.log('Recommendations:', recommendations.items);
189
+ console.log('Next cursor:', recommendations.cursor);
190
+ ```
191
+
192
+ #### Throws
193
+
194
+ - `Error`: If the request fails or no data is returned
195
+
196
+ ---
197
+
198
+ ### signal
199
+
200
+ Record a user signal (e.g., clicked topic, read article) to inform profile interests. Signals are used to power a user's recommendations.
201
+
202
+ ```typescript
203
+ client.user.signal(options: SignalRequest): Promise<SignalResponse>
204
+ ```
205
+
206
+ #### Parameters
207
+
208
+ - `options.signal` (required): User action with the text associated with the interaction (e.g., `'clicked "Warriors intend to keep Jimmy Butler despite season-ending injury"'`)
209
+ - `options.type` (required): Signal type - `"active"` or `"passive"`
210
+ - `"active"`: Explicit intent (click, search, subscribe)
211
+ - `"passive"`: Implicit intent (read, scroll, dwell)
212
+ - `options.negative` (optional): When `true`, indicates the signal is negative (e.g., dislike, unfollow). Defaults to `false`. Use sparingly.
213
+ - `options.contentContext` (optional): Context about the content that triggered this signal
214
+ - `contentId` (required): The ID of the content (e.g., article ID)
215
+ - `contentType` (required): The type of content (currently only `"article"`)
216
+
217
+ #### Returns
218
+
219
+ - `Promise<SignalResponse>`: Response containing:
220
+ - `recorded?: boolean`: Whether the signal was recorded (false if no app user or empty signal)
221
+
222
+ #### Example
223
+
224
+ ```typescript
225
+ // Active signal (explicit intent)
226
+ await client.user.signal({
227
+ signal: 'clicked "Warriors intend to keep Jimmy Butler despite season-ending injury"',
228
+ type: 'active',
229
+ contentContext: {
230
+ contentId: 'article-123',
231
+ contentType: 'article',
232
+ },
233
+ });
234
+
235
+ // Passive signal (implicit intent)
236
+ await client.user.signal({
237
+ signal: 'read article about NBA trades',
238
+ type: 'passive',
239
+ contentContext: {
240
+ contentId: 'article-456',
241
+ contentType: 'article',
242
+ },
243
+ });
244
+
245
+ // Negative signal (use sparingly)
246
+ await client.user.signal({
247
+ signal: 'unfollowed topic "Politics"',
248
+ type: 'active',
249
+ negative: true,
250
+ });
251
+ ```
252
+
253
+ #### Throws
254
+
255
+ - `Error`: If the request fails or no data is returned
256
+
257
+ ---
258
+
259
+ ### synthesizeItem
260
+
261
+ Synthesize a single item (batched). Items are automatically batched and sent together after the configured timeout. Returns a promise that resolves with the `data` field from the event (excluding 'connected' and 'complete' events).
262
+
263
+ ```typescript
264
+ client.user.synthesizeItem(item: SynthesizeRequest['items'][number]): Promise<unknown>
265
+ ```
266
+
267
+ #### Parameters
268
+
269
+ - `item` (required): A single synthesize item (same format as items in `synthesize`)
270
+
271
+ #### Returns
272
+
273
+ - `Promise<unknown>`: A promise that resolves with the `data` field from the event for this specific item. The data will be:
274
+ - For `DAILY_SUMMARY`: `{ summary: string | null }`
275
+ - For `CUSTOM`: An object following your schema input, where `fieldNames` are keys
276
+
277
+ #### Behavior
278
+
279
+ - Items added within the batch timeout window (default: 250ms) are grouped together and sent in a single request
280
+ - Each item's promise resolves immediately when its data event arrives (based on the `index` field)
281
+ - The batching happens in the background - promises resolve as soon as the batch request is sent
282
+ - Only data events (DAILY_SUMMARY or CUSTOM) resolve the promise - 'connected' and 'complete' events are ignored
283
+ - The batch timeout can be configured when creating the client via `synthesizeBatchTimeout`
284
+
285
+ #### Example
286
+
287
+ ```typescript
288
+ // Items are automatically batched and sent together after the timeout
289
+ // Each promise resolves with the data field from the event
290
+ const dailySummaryData = await client.user.synthesizeItem({
291
+ type: 'DAILY_SUMMARY',
292
+ });
293
+ // dailySummaryData will be: { summary: string | null }
294
+ console.log('Daily summary:', dailySummaryData);
295
+
296
+ const customData = await client.user.synthesizeItem({
297
+ type: 'CUSTOM',
298
+ schema: [{ fieldName: 'title', fieldDescription: 'The article title' }],
299
+ contentContext: {
300
+ contentId: 'article-123',
301
+ contentType: 'article',
302
+ },
303
+ });
304
+ // customData will be an object with keys matching your schema fieldNames
305
+ console.log('Custom data:', customData);
306
+
307
+ // Both items are sent together in a single batch request
308
+ // Each promise resolves immediately when its data event arrives
309
+ ```
310
+
311
+ ---
312
+
313
+ ### synthesize
314
+
315
+ Synthesize user content (streaming). Returns a stream of events for all items.
316
+
317
+ ```typescript
318
+ client.user.synthesize(items: SynthesizeRequest['items']): Promise<AsyncIterable<SynthesizeEvent>>
319
+ ```
320
+
321
+ #### Parameters
322
+
323
+ - `items` (required): Array of items to synthesize. Each item can be:
324
+ - `{ type: "DAILY_SUMMARY" }`: Generate a daily summary
325
+ - `{ type: "CUSTOM", schema: Array<SchemaField>, contentContext: ContentContext }`: Custom synthesis with schema (contentContext is required for CUSTOM items)
326
+
327
+ #### SchemaField
328
+
329
+ - `fieldName` (required): Name of the field
330
+ - `fieldDescription` (required): A prompt describing the value of the field
331
+
332
+ #### ContentContext (required for CUSTOM items)
333
+
334
+ - `contentId` (optional): Your content ID
335
+ - `contentType` (optional): The type of content to synthesize (currently only `"article"`)
336
+
337
+ #### Returns
338
+
339
+ - `Promise<AsyncIterable<SynthesizeEvent>>`: An async iterable stream of events
340
+
341
+ #### SynthesizeEvent
342
+
343
+ Events in the stream can be:
344
+
345
+ - `{ type: "connected" }`: Connection established
346
+ - `{ type: "DAILY_SUMMARY", index: number, data: { summary: string | null } }`: Daily summary data
347
+ - `{ type: "CUSTOM", index: number, data: {...} }`: Custom data following your schema
348
+ - `{ type: "complete" }`: Stream complete
349
+
350
+ #### Example
351
+
352
+ ```typescript
353
+ const stream = await client.user.synthesize([
354
+ {
355
+ type: 'DAILY_SUMMARY',
356
+ },
357
+ {
358
+ type: 'CUSTOM',
359
+ schema: [
360
+ { fieldName: 'title', fieldDescription: 'The article title' },
361
+ { fieldName: 'summary', fieldDescription: 'A brief summary' },
362
+ ],
363
+ contentContext: {
364
+ contentId: 'article-123',
365
+ contentType: 'article',
366
+ },
367
+ },
368
+ ]);
369
+
370
+ for await (const event of stream) {
371
+ switch (event.type) {
372
+ case 'connected':
373
+ console.log('Stream connected');
374
+ break;
375
+ case 'DAILY_SUMMARY':
376
+ console.log('Daily summary:', event.data);
377
+ break;
378
+ case 'CUSTOM':
379
+ console.log('Custom data:', event.data);
380
+ break;
381
+ case 'complete':
382
+ console.log('Stream complete');
383
+ break;
384
+ }
385
+ }
386
+ ```
387
+
388
+ ---
389
+
390
+ ## Types
391
+
392
+ ### BitBitPressClientConfig
393
+
394
+ ```typescript
395
+ interface BitBitPressClientConfig {
396
+ baseUrl: string;
397
+ fetch?: typeof fetch;
398
+ headers?: Record<string, string>;
399
+ timeout?: number;
400
+ synthesizeBatchTimeout?: number;
401
+ }
402
+ ```
403
+
404
+ ### TokenRequest
405
+
406
+ ```typescript
407
+ type TokenRequest = {
408
+ ssoToken: string;
409
+ }
410
+ ```
411
+
412
+ ### TokenResponse
413
+
414
+ ```typescript
415
+ type TokenResponse = {
416
+ idToken?: string;
417
+ accessToken?: string;
418
+ refreshToken?: string;
419
+ expiresIn?: number;
420
+ }
421
+ ```
422
+
423
+ ### RecommendationsRequest
424
+
425
+ ```typescript
426
+ type RecommendationsRequest = {
427
+ limit?: number;
428
+ cursor?: string;
429
+ }
430
+ ```
431
+
432
+ ### RecommendationsResponse
433
+
434
+ ```typescript
435
+ type RecommendationsResponse = {
436
+ items?: Array<{
437
+ id?: string;
438
+ assetId?: string;
439
+ title?: string;
440
+ summary?: string;
441
+ content?: string;
442
+ publishedAt?: string;
443
+ score?: number;
444
+ }>;
445
+ cursor?: string;
446
+ }
447
+ ```
448
+
449
+ ### SignalRequest
450
+
451
+ ```typescript
452
+ type SignalRequest = {
453
+ signal: string;
454
+ type: 'active' | 'passive';
455
+ negative?: boolean;
456
+ contentContext?: {
457
+ contentId: string;
458
+ contentType: 'article';
459
+ };
460
+ }
461
+ ```
462
+
463
+ ### SignalResponse
464
+
465
+ ```typescript
466
+ type SignalResponse = {
467
+ recorded?: boolean;
468
+ }
469
+ ```
470
+
471
+ ### SynthesizeRequest
472
+
473
+ ```typescript
474
+ type SynthesizeRequest = {
475
+ items: Array<
476
+ | { type: 'DAILY_SUMMARY' }
477
+ | {
478
+ type: 'CUSTOM';
479
+ schema: Array<{
480
+ fieldName: string;
481
+ fieldDescription: string;
482
+ }>;
483
+ contentContext: {
484
+ contentId?: string;
485
+ contentType?: 'article';
486
+ };
487
+ }
488
+ >;
489
+ }
490
+ ```
491
+
492
+ ### SynthesizeEvent
493
+
494
+ ```typescript
495
+ type SynthesizeEvent = {
496
+ type: 'DAILY_SUMMARY' | 'CUSTOM' | 'connected' | 'complete';
497
+ index?: number;
498
+ data?: unknown;
499
+ }
500
+ ```
501
+
502
+ For `DAILY_SUMMARY` events, `data` will be:
503
+ ```typescript
504
+ {
505
+ summary: string | null;
506
+ }
507
+ ```
508
+
509
+ For `CUSTOM` events, `data` will be an object following your schema input, where `fieldNames` are keys.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitbitpress/client",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "BitBitPress TypeScript client library",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",