@cobbl-ai/sdk 0.1.0 → 0.1.2
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/README.md +179 -55
- package/dist/admin.d.mts +90 -0
- package/dist/admin.d.ts +90 -0
- package/dist/admin.js +185 -0
- package/dist/admin.js.map +1 -0
- package/dist/admin.mjs +182 -0
- package/dist/admin.mjs.map +1 -0
- package/dist/cobbl-sdk.global.js +2 -0
- package/dist/cobbl-sdk.global.js.map +1 -0
- package/dist/errors-BaYZ2rGo.d.mts +208 -0
- package/dist/errors-BaYZ2rGo.d.ts +208 -0
- package/dist/index.d.mts +3 -348
- package/dist/index.d.ts +3 -348
- package/dist/index.js +222 -75
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +221 -75
- package/dist/index.mjs.map +1 -1
- package/dist/public.d.mts +130 -0
- package/dist/public.d.ts +130 -0
- package/dist/public.js +271 -0
- package/dist/public.js.map +1 -0
- package/dist/public.mjs +268 -0
- package/dist/public.mjs.map +1 -0
- package/package.json +40 -11
- package/src/__tests__/client.test.ts +362 -107
- package/src/__tests__/integration.test.ts +129 -38
- package/src/admin.ts +184 -0
- package/src/browser.ts +12 -0
- package/src/errors.ts +49 -0
- package/src/index.ts +35 -10
- package/src/public.ts +270 -0
- package/src/types.ts +164 -58
- package/src/validation.ts +52 -0
- package/src/client.ts +0 -257
package/dist/index.js
CHANGED
|
@@ -29,28 +29,76 @@ var CobblError = class _CobblError extends Error {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
|
+
var handleErrorResponse = async (response) => {
|
|
33
|
+
let errorData;
|
|
34
|
+
try {
|
|
35
|
+
errorData = await response.json();
|
|
36
|
+
} catch {
|
|
37
|
+
throw new CobblError(
|
|
38
|
+
`HTTP ${response.status}: ${response.statusText}`,
|
|
39
|
+
"API_ERROR",
|
|
40
|
+
{ status: response.status }
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
const message = errorData.error || errorData.message || "Unknown error";
|
|
44
|
+
const details = errorData.details;
|
|
45
|
+
switch (response.status) {
|
|
46
|
+
case 400:
|
|
47
|
+
throw new CobblError(message, "INVALID_REQUEST", details);
|
|
48
|
+
case 401:
|
|
49
|
+
throw new CobblError(message, "UNAUTHORIZED", details);
|
|
50
|
+
case 403:
|
|
51
|
+
throw new CobblError(message, "FORBIDDEN", details);
|
|
52
|
+
case 404:
|
|
53
|
+
throw new CobblError(message, "NOT_FOUND", details);
|
|
54
|
+
case 410:
|
|
55
|
+
throw new CobblError(message, "ARCHIVED", details);
|
|
56
|
+
case 429:
|
|
57
|
+
throw new CobblError(message, "RATE_LIMIT_EXCEEDED", details);
|
|
58
|
+
case 500:
|
|
59
|
+
case 502:
|
|
60
|
+
case 503:
|
|
61
|
+
case 504:
|
|
62
|
+
throw new CobblError(message, "SERVER_ERROR", details);
|
|
63
|
+
default:
|
|
64
|
+
throw new CobblError(message, "API_ERROR", {
|
|
65
|
+
status: response.status,
|
|
66
|
+
...details
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
};
|
|
32
70
|
|
|
33
|
-
// src/
|
|
71
|
+
// src/admin.ts
|
|
34
72
|
var REQUEST_TIMEOUT_MS = 3e4;
|
|
35
|
-
var
|
|
73
|
+
var CobblAdminClient = class {
|
|
36
74
|
/**
|
|
37
|
-
* Initialize the Cobbl SDK client
|
|
75
|
+
* Initialize the Cobbl Admin SDK client
|
|
38
76
|
*
|
|
39
77
|
* @param config - Configuration object
|
|
40
78
|
* @param config.apiKey - Your Cobbl API key
|
|
79
|
+
* @param config.baseUrl - Optional base URL for the API (defaults to 'https://api.cobbl.ai')
|
|
41
80
|
*
|
|
42
|
-
* @example
|
|
81
|
+
* @example Production (uses default URL)
|
|
43
82
|
* ```typescript
|
|
44
|
-
* const client = new
|
|
83
|
+
* const client = new CobblAdminClient({
|
|
45
84
|
* apiKey: process.env.COBBL_API_KEY
|
|
46
85
|
* })
|
|
47
86
|
* ```
|
|
87
|
+
*
|
|
88
|
+
* @example Local development with Firebase emulators
|
|
89
|
+
* ```typescript
|
|
90
|
+
* const client = new CobblAdminClient({
|
|
91
|
+
* apiKey: process.env.COBBL_API_KEY,
|
|
92
|
+
* baseUrl: 'http://localhost:5001/your-project-id/us-central1/externalApi'
|
|
93
|
+
* })
|
|
94
|
+
* ```
|
|
48
95
|
*/
|
|
49
96
|
constructor(config) {
|
|
50
97
|
if (!config.apiKey || config.apiKey.trim().length === 0) {
|
|
51
98
|
throw new CobblError("API key is required", "INVALID_CONFIG");
|
|
52
99
|
}
|
|
53
100
|
this.apiKey = config.apiKey;
|
|
101
|
+
this.baseUrl = config.baseUrl?.trim() || "https://api.cobbl.ai";
|
|
54
102
|
}
|
|
55
103
|
/**
|
|
56
104
|
* Execute a prompt with the given input variables
|
|
@@ -78,7 +126,7 @@ var CobblClient = class {
|
|
|
78
126
|
throw new CobblError("promptSlug is required", "INVALID_REQUEST");
|
|
79
127
|
}
|
|
80
128
|
try {
|
|
81
|
-
const response = await this.makeRequest("/prompt/run", {
|
|
129
|
+
const response = await this.makeRequest("/admin/v1/prompt/run", {
|
|
82
130
|
method: "POST",
|
|
83
131
|
body: JSON.stringify({
|
|
84
132
|
promptSlug: promptSlug.trim(),
|
|
@@ -86,7 +134,7 @@ var CobblClient = class {
|
|
|
86
134
|
})
|
|
87
135
|
});
|
|
88
136
|
if (!response.ok) {
|
|
89
|
-
await
|
|
137
|
+
await handleErrorResponse(response);
|
|
90
138
|
}
|
|
91
139
|
const data = await response.json();
|
|
92
140
|
return {
|
|
@@ -107,53 +155,191 @@ var CobblClient = class {
|
|
|
107
155
|
}
|
|
108
156
|
}
|
|
109
157
|
/**
|
|
110
|
-
*
|
|
158
|
+
* Make an HTTP request to the Cobbl API
|
|
159
|
+
* @private
|
|
160
|
+
*/
|
|
161
|
+
async makeRequest(path, options) {
|
|
162
|
+
const url = `${this.baseUrl}${path}`;
|
|
163
|
+
const controller = new AbortController();
|
|
164
|
+
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
165
|
+
try {
|
|
166
|
+
const response = await fetch(url, {
|
|
167
|
+
...options,
|
|
168
|
+
headers: {
|
|
169
|
+
"Content-Type": "application/json",
|
|
170
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
171
|
+
...options.headers
|
|
172
|
+
},
|
|
173
|
+
signal: controller.signal
|
|
174
|
+
});
|
|
175
|
+
return response;
|
|
176
|
+
} finally {
|
|
177
|
+
clearTimeout(timeoutId);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// src/validation.ts
|
|
183
|
+
var VALID_HELPFUL_VALUES = ["helpful", "not_helpful"];
|
|
184
|
+
function validateCreateFeedback(feedback) {
|
|
185
|
+
if (!feedback.runId || feedback.runId.trim().length === 0) {
|
|
186
|
+
return "runId is required";
|
|
187
|
+
}
|
|
188
|
+
if (feedback.helpful !== void 0 && !VALID_HELPFUL_VALUES.includes(feedback.helpful)) {
|
|
189
|
+
return 'helpful must be "helpful" or "not_helpful"';
|
|
190
|
+
}
|
|
191
|
+
if (feedback.userFeedback !== void 0 && feedback.userFeedback.trim().length === 0) {
|
|
192
|
+
return "userFeedback cannot be empty";
|
|
193
|
+
}
|
|
194
|
+
if (feedback.helpful === void 0 && feedback.userFeedback === void 0) {
|
|
195
|
+
return "At least one of helpful or userFeedback is required";
|
|
196
|
+
}
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
function validateUpdateFeedback(update) {
|
|
200
|
+
if (update.helpful !== void 0 && !VALID_HELPFUL_VALUES.includes(update.helpful)) {
|
|
201
|
+
return 'helpful must be "helpful" or "not_helpful"';
|
|
202
|
+
}
|
|
203
|
+
if (update.userFeedback !== void 0 && update.userFeedback.trim().length === 0) {
|
|
204
|
+
return "userFeedback cannot be empty";
|
|
205
|
+
}
|
|
206
|
+
if (update.helpful === void 0 && update.userFeedback === void 0) {
|
|
207
|
+
return "At least one of helpful or userFeedback is required";
|
|
208
|
+
}
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/public.ts
|
|
213
|
+
var REQUEST_TIMEOUT_MS2 = 3e4;
|
|
214
|
+
var CobblPublicClient = class {
|
|
215
|
+
/**
|
|
216
|
+
* Initialize the Cobbl Public SDK client
|
|
217
|
+
*
|
|
218
|
+
* @param config - Configuration object
|
|
219
|
+
* @param config.baseUrl - Optional base URL for the API (defaults to 'https://api.cobbl.ai')
|
|
220
|
+
*/
|
|
221
|
+
constructor(config = {}) {
|
|
222
|
+
this.baseUrl = config.baseUrl?.trim() || "https://api.cobbl.ai";
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Create user feedback for a prompt run
|
|
226
|
+
* Supports segmented feedback - you can provide just helpful, just userFeedback, or both
|
|
227
|
+
* Use updateFeedback to add additional data later
|
|
111
228
|
*
|
|
112
229
|
* @param feedback - Feedback submission data
|
|
113
230
|
* @param feedback.runId - The run ID from a previous runPrompt call
|
|
114
|
-
* @param feedback.helpful - Whether the output was helpful ('helpful' or 'not_helpful')
|
|
115
|
-
* @param feedback.userFeedback - Detailed feedback message from the user
|
|
231
|
+
* @param feedback.helpful - Whether the output was helpful ('helpful' or 'not_helpful') - optional
|
|
232
|
+
* @param feedback.userFeedback - Detailed feedback message from the user - optional
|
|
116
233
|
* @returns Promise containing the created feedback ID
|
|
117
234
|
*
|
|
118
235
|
* @throws {CobblError} When the request fails or API returns an error
|
|
119
236
|
*
|
|
120
|
-
* @example
|
|
237
|
+
* @example Submit just thumbs down first
|
|
121
238
|
* ```typescript
|
|
122
|
-
* await client.
|
|
239
|
+
* const { id } = await client.createFeedback({
|
|
240
|
+
* runId: result.runId,
|
|
241
|
+
* helpful: 'not_helpful'
|
|
242
|
+
* })
|
|
243
|
+
* // Later, add details
|
|
244
|
+
* await client.updateFeedback(id, {
|
|
245
|
+
* userFeedback: 'The response was too formal and lengthy'
|
|
246
|
+
* })
|
|
247
|
+
* ```
|
|
248
|
+
*
|
|
249
|
+
* @example Submit both at once
|
|
250
|
+
* ```typescript
|
|
251
|
+
* await client.createFeedback({
|
|
123
252
|
* runId: result.runId,
|
|
124
253
|
* helpful: 'not_helpful',
|
|
125
254
|
* userFeedback: 'The response was too formal and lengthy'
|
|
126
255
|
* })
|
|
127
256
|
* ```
|
|
128
257
|
*/
|
|
129
|
-
async
|
|
130
|
-
|
|
131
|
-
|
|
258
|
+
async createFeedback(feedback) {
|
|
259
|
+
const validationError = validateCreateFeedback(feedback);
|
|
260
|
+
if (validationError) {
|
|
261
|
+
throw new CobblError(validationError, "INVALID_REQUEST");
|
|
132
262
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
263
|
+
try {
|
|
264
|
+
const body = {
|
|
265
|
+
runId: feedback.runId.trim(),
|
|
266
|
+
helpful: feedback.helpful,
|
|
267
|
+
userFeedback: feedback.userFeedback?.trim()
|
|
268
|
+
};
|
|
269
|
+
const response = await this.makeRequest("/public/v1/feedback", {
|
|
270
|
+
method: "POST",
|
|
271
|
+
body: JSON.stringify(body)
|
|
272
|
+
});
|
|
273
|
+
if (!response.ok) {
|
|
274
|
+
await handleErrorResponse(response);
|
|
275
|
+
}
|
|
276
|
+
const data = await response.json();
|
|
277
|
+
return {
|
|
278
|
+
id: data.id,
|
|
279
|
+
message: data.message
|
|
280
|
+
};
|
|
281
|
+
} catch (error) {
|
|
282
|
+
if (error instanceof CobblError) {
|
|
283
|
+
throw error;
|
|
284
|
+
}
|
|
137
285
|
throw new CobblError(
|
|
138
|
-
|
|
139
|
-
"
|
|
286
|
+
`Failed to create feedback: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
287
|
+
"NETWORK_ERROR"
|
|
140
288
|
);
|
|
141
289
|
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Update existing feedback with additional data
|
|
293
|
+
* Use this to add helpful sentiment or detailed feedback after initial submission
|
|
294
|
+
*
|
|
295
|
+
* @param id - The ID returned from createFeedback
|
|
296
|
+
* @param update - The data to update
|
|
297
|
+
* @param update.helpful - Whether the output was helpful ('helpful' or 'not_helpful') - optional
|
|
298
|
+
* @param update.userFeedback - Detailed feedback message from the user - optional
|
|
299
|
+
* @returns Promise containing the updated feedback ID
|
|
300
|
+
*
|
|
301
|
+
* @throws {CobblError} When the request fails or API returns an error
|
|
302
|
+
*
|
|
303
|
+
* @example Add details after initial thumbs down
|
|
304
|
+
* ```typescript
|
|
305
|
+
* // First, submit just the rating
|
|
306
|
+
* const { id } = await client.createFeedback({
|
|
307
|
+
* runId: result.runId,
|
|
308
|
+
* helpful: 'not_helpful'
|
|
309
|
+
* })
|
|
310
|
+
*
|
|
311
|
+
* // Later, add detailed feedback
|
|
312
|
+
* await client.updateFeedback(id, {
|
|
313
|
+
* userFeedback: 'The response was too formal and lengthy'
|
|
314
|
+
* })
|
|
315
|
+
* ```
|
|
316
|
+
*/
|
|
317
|
+
async updateFeedback(id, update) {
|
|
318
|
+
if (!id || id.trim().length === 0) {
|
|
319
|
+
throw new CobblError("id is required", "INVALID_REQUEST");
|
|
320
|
+
}
|
|
321
|
+
const validationError = validateUpdateFeedback(update);
|
|
322
|
+
if (validationError) {
|
|
323
|
+
throw new CobblError(validationError, "INVALID_REQUEST");
|
|
324
|
+
}
|
|
142
325
|
try {
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
326
|
+
const body = {
|
|
327
|
+
helpful: update.helpful,
|
|
328
|
+
userFeedback: update.userFeedback?.trim()
|
|
329
|
+
};
|
|
330
|
+
const response = await this.makeRequest(
|
|
331
|
+
`/public/v1/feedback/${id.trim()}`,
|
|
332
|
+
{
|
|
333
|
+
method: "PATCH",
|
|
334
|
+
body: JSON.stringify(body)
|
|
335
|
+
}
|
|
336
|
+
);
|
|
151
337
|
if (!response.ok) {
|
|
152
|
-
await
|
|
338
|
+
await handleErrorResponse(response);
|
|
153
339
|
}
|
|
154
340
|
const data = await response.json();
|
|
155
341
|
return {
|
|
156
|
-
|
|
342
|
+
id: data.id,
|
|
157
343
|
message: data.message
|
|
158
344
|
};
|
|
159
345
|
} catch (error) {
|
|
@@ -161,7 +347,7 @@ var CobblClient = class {
|
|
|
161
347
|
throw error;
|
|
162
348
|
}
|
|
163
349
|
throw new CobblError(
|
|
164
|
-
`Failed to
|
|
350
|
+
`Failed to update feedback: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
165
351
|
"NETWORK_ERROR"
|
|
166
352
|
);
|
|
167
353
|
}
|
|
@@ -171,16 +357,14 @@ var CobblClient = class {
|
|
|
171
357
|
* @private
|
|
172
358
|
*/
|
|
173
359
|
async makeRequest(path, options) {
|
|
174
|
-
const
|
|
175
|
-
const url = `${baseUrl}${path}`;
|
|
360
|
+
const url = `${this.baseUrl}${path}`;
|
|
176
361
|
const controller = new AbortController();
|
|
177
|
-
const timeoutId = setTimeout(() => controller.abort(),
|
|
362
|
+
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
|
|
178
363
|
try {
|
|
179
364
|
const response = await fetch(url, {
|
|
180
365
|
...options,
|
|
181
366
|
headers: {
|
|
182
367
|
"Content-Type": "application/json",
|
|
183
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
184
368
|
...options.headers
|
|
185
369
|
},
|
|
186
370
|
signal: controller.signal
|
|
@@ -190,47 +374,10 @@ var CobblClient = class {
|
|
|
190
374
|
clearTimeout(timeoutId);
|
|
191
375
|
}
|
|
192
376
|
}
|
|
193
|
-
/**
|
|
194
|
-
* Handle error responses from the API
|
|
195
|
-
* @private
|
|
196
|
-
*/
|
|
197
|
-
async handleErrorResponse(response) {
|
|
198
|
-
let errorData;
|
|
199
|
-
try {
|
|
200
|
-
errorData = await response.json();
|
|
201
|
-
} catch {
|
|
202
|
-
throw new CobblError(
|
|
203
|
-
`HTTP ${response.status}: ${response.statusText}`,
|
|
204
|
-
"API_ERROR",
|
|
205
|
-
{ status: response.status }
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
const message = errorData.error || errorData.message || "Unknown error";
|
|
209
|
-
const details = errorData.details;
|
|
210
|
-
switch (response.status) {
|
|
211
|
-
case 400:
|
|
212
|
-
throw new CobblError(message, "INVALID_REQUEST", details);
|
|
213
|
-
case 401:
|
|
214
|
-
throw new CobblError(message, "UNAUTHORIZED", details);
|
|
215
|
-
case 404:
|
|
216
|
-
throw new CobblError(message, "NOT_FOUND", details);
|
|
217
|
-
case 429:
|
|
218
|
-
throw new CobblError(message, "RATE_LIMIT_EXCEEDED", details);
|
|
219
|
-
case 500:
|
|
220
|
-
case 502:
|
|
221
|
-
case 503:
|
|
222
|
-
case 504:
|
|
223
|
-
throw new CobblError(message, "SERVER_ERROR", details);
|
|
224
|
-
default:
|
|
225
|
-
throw new CobblError(message, "API_ERROR", {
|
|
226
|
-
status: response.status,
|
|
227
|
-
...details
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
377
|
};
|
|
232
378
|
|
|
233
|
-
exports.
|
|
379
|
+
exports.CobblAdminClient = CobblAdminClient;
|
|
234
380
|
exports.CobblError = CobblError;
|
|
381
|
+
exports.CobblPublicClient = CobblPublicClient;
|
|
235
382
|
//# sourceMappingURL=index.js.map
|
|
236
383
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Error types that can be thrown by the Cobbl SDK\n */\nexport type CobblErrorCode =\n | 'INVALID_CONFIG'\n | 'INVALID_REQUEST'\n | 'UNAUTHORIZED'\n | 'NOT_FOUND'\n | 'RATE_LIMIT_EXCEEDED'\n | 'SERVER_ERROR'\n | 'NETWORK_ERROR'\n | 'API_ERROR'\n\n/**\n * Custom error class for Cobbl SDK errors\n *\n * @example\n * ```typescript\n * try {\n * await client.runPrompt('my-prompt', { topic: 'test' })\n * } catch (error) {\n * if (error instanceof CobblError) {\n * console.error(`Error [${error.code}]: ${error.message}`)\n * console.error('Details:', error.details)\n * }\n * }\n * ```\n */\nexport class CobblError extends Error {\n /**\n * Error code indicating the type of error\n */\n public readonly code: CobblErrorCode\n\n /**\n * Additional details about the error (e.g., missing variables, validation issues)\n */\n public readonly details?: unknown\n\n constructor(message: string, code: CobblErrorCode, details?: unknown) {\n super(message)\n this.name = 'CobblError'\n this.code = code\n this.details = details\n\n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, CobblError)\n }\n }\n\n /**\n * Check if an error is a CobblError\n */\n static isCobblError(error: unknown): error is CobblError {\n return error instanceof CobblError\n }\n\n /**\n * Convert error to JSON-serializable object\n */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n details: this.details,\n }\n }\n}\n","/**\n * CobblClient - SDK for the Cobbl platform\n *\n * Provides methods to run prompts and submit feedback to the Cobbl API.\n */\n\nimport type { PromptInput, PromptVersionClient } from '@prompti/shared'\nimport type {\n RunPromptResponse,\n SubmitFeedbackResponse,\n CobblConfig,\n TokenUsage,\n FeedbackSubmission,\n} from './types'\nimport { CobblError } from './errors'\n\nconst REQUEST_TIMEOUT_MS = 30_000\n\nexport class CobblClient {\n private readonly apiKey: string\n\n /**\n * Initialize the Cobbl SDK client\n *\n * @param config - Configuration object\n * @param config.apiKey - Your Cobbl API key\n *\n * @example\n * ```typescript\n * const client = new CobblClient({\n * apiKey: process.env.COBBL_API_KEY\n * })\n * ```\n */\n constructor(config: CobblConfig) {\n if (!config.apiKey || config.apiKey.trim().length === 0) {\n throw new CobblError('API key is required', 'INVALID_CONFIG')\n }\n\n this.apiKey = config.apiKey\n }\n\n /**\n * Execute a prompt with the given input variables\n *\n * @param promptSlug - The unique slug identifier for the prompt\n * @param input - Input variables to populate the prompt template\n * @returns Promise containing the prompt execution results\n *\n * @throws {CobblError} When the request fails or API returns an error\n *\n * @example\n * ```typescript\n * const result = await client.runPrompt('sales_summary', {\n * topic: 'Q4 Results',\n * tone: 'friendly',\n * audience: 'investors'\n * })\n *\n * console.log(result.output) // AI-generated response\n * console.log(result.runId) // Save this to link feedback later\n * ```\n */\n async runPrompt(\n promptSlug: string,\n input: PromptInput\n ): Promise<RunPromptResponse> {\n if (!promptSlug || promptSlug.trim().length === 0) {\n throw new CobblError('promptSlug is required', 'INVALID_REQUEST')\n }\n\n try {\n const response = await this.makeRequest('/prompt/run', {\n method: 'POST',\n body: JSON.stringify({\n promptSlug: promptSlug.trim(),\n input,\n }),\n })\n\n if (!response.ok) {\n await this.handleErrorResponse(response)\n }\n\n const data = (await response.json()) as {\n runId: string\n output: string\n tokenUsage: TokenUsage\n renderedPrompt: string\n promptVersion: PromptVersionClient\n }\n\n return {\n runId: data.runId,\n output: data.output,\n tokenUsage: data.tokenUsage,\n renderedPrompt: data.renderedPrompt,\n promptVersion: data.promptVersion,\n }\n } catch (error) {\n if (error instanceof CobblError) {\n throw error\n }\n throw new CobblError(\n `Failed to run prompt: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'NETWORK_ERROR'\n )\n }\n }\n\n /**\n * Submit user feedback for a prompt run\n *\n * @param feedback - Feedback submission data\n * @param feedback.runId - The run ID from a previous runPrompt call\n * @param feedback.helpful - Whether the output was helpful ('helpful' or 'not_helpful')\n * @param feedback.userFeedback - Detailed feedback message from the user\n * @returns Promise containing the created feedback ID\n *\n * @throws {CobblError} When the request fails or API returns an error\n *\n * @example\n * ```typescript\n * await client.submitFeedback({\n * runId: result.runId,\n * helpful: 'not_helpful',\n * userFeedback: 'The response was too formal and lengthy'\n * })\n * ```\n */\n async submitFeedback(\n feedback: FeedbackSubmission\n ): Promise<SubmitFeedbackResponse> {\n if (!feedback.runId || feedback.runId.trim().length === 0) {\n throw new CobblError('runId is required', 'INVALID_REQUEST')\n }\n\n if (!feedback.userFeedback || feedback.userFeedback.trim().length === 0) {\n throw new CobblError('userFeedback is required', 'INVALID_REQUEST')\n }\n\n if (\n !feedback.helpful ||\n !['helpful', 'not_helpful'].includes(feedback.helpful)\n ) {\n throw new CobblError(\n 'helpful must be either \"helpful\" or \"not_helpful\"',\n 'INVALID_REQUEST'\n )\n }\n\n try {\n const response = await this.makeRequest('/feedback', {\n method: 'POST',\n body: JSON.stringify({\n runId: feedback.runId.trim(),\n helpful: feedback.helpful,\n userFeedback: feedback.userFeedback.trim(),\n }),\n })\n\n if (!response.ok) {\n await this.handleErrorResponse(response)\n }\n\n const data = (await response.json()) as {\n feedbackId: string\n message: string\n }\n\n return {\n feedbackId: data.feedbackId,\n message: data.message,\n }\n } catch (error) {\n if (error instanceof CobblError) {\n throw error\n }\n throw new CobblError(\n `Failed to submit feedback: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'NETWORK_ERROR'\n )\n }\n }\n\n /**\n * Make an HTTP request to the Cobbl API\n * @private\n */\n private async makeRequest(\n path: string,\n options: RequestInit\n ): Promise<Response> {\n const baseUrl = process.env.COBBL_API_URL || 'https://api.cobbl.ai'\n const url = `${baseUrl}${path}`\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS)\n\n try {\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n ...options.headers,\n },\n signal: controller.signal,\n })\n\n return response\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * Handle error responses from the API\n * @private\n */\n private async handleErrorResponse(response: Response): Promise<never> {\n let errorData: any\n try {\n errorData = await response.json()\n } catch {\n throw new CobblError(\n `HTTP ${response.status}: ${response.statusText}`,\n 'API_ERROR',\n { status: response.status }\n )\n }\n\n const message = errorData.error || errorData.message || 'Unknown error'\n const details = errorData.details\n\n switch (response.status) {\n case 400:\n throw new CobblError(message, 'INVALID_REQUEST', details)\n case 401:\n throw new CobblError(message, 'UNAUTHORIZED', details)\n case 404:\n throw new CobblError(message, 'NOT_FOUND', details)\n case 429:\n throw new CobblError(message, 'RATE_LIMIT_EXCEEDED', details)\n case 500:\n case 502:\n case 503:\n case 504:\n throw new CobblError(message, 'SERVER_ERROR', details)\n default:\n throw new CobblError(message, 'API_ERROR', {\n status: response.status,\n ...details,\n })\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/admin.ts","../src/validation.ts","../src/public.ts"],"names":["REQUEST_TIMEOUT_MS"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Error types that can be thrown by the Cobbl SDK\n */\nexport type CobblErrorCode =\n | 'INVALID_CONFIG'\n | 'INVALID_REQUEST'\n | 'UNAUTHORIZED'\n | 'FORBIDDEN'\n | 'NOT_FOUND'\n | 'ARCHIVED'\n | 'RATE_LIMIT_EXCEEDED'\n | 'SERVER_ERROR'\n | 'NETWORK_ERROR'\n | 'API_ERROR'\n\n/**\n * Custom error class for Cobbl SDK errors\n *\n * @example\n * ```typescript\n * try {\n * await client.runPrompt('my-prompt', { topic: 'test' })\n * } catch (error) {\n * if (error instanceof CobblError) {\n * console.error(`Error [${error.code}]: ${error.message}`)\n * console.error('Details:', error.details)\n * }\n * }\n * ```\n */\nexport class CobblError extends Error {\n /**\n * Error code indicating the type of error\n */\n public readonly code: CobblErrorCode\n\n /**\n * Additional details about the error (e.g., missing variables, validation issues)\n */\n public readonly details?: unknown\n\n constructor(message: string, code: CobblErrorCode, details?: unknown) {\n super(message)\n this.name = 'CobblError'\n this.code = code\n this.details = details\n\n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, CobblError)\n }\n }\n\n /**\n * Check if an error is a CobblError\n */\n static isCobblError(error: unknown): error is CobblError {\n return error instanceof CobblError\n }\n\n /**\n * Convert error to JSON-serializable object\n */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n details: this.details,\n }\n }\n}\n\n/**\n * Handle error responses from the API\n * @internal\n */\nexport const handleErrorResponse = async (\n response: Response\n): Promise<never> => {\n let errorData: any\n try {\n errorData = await response.json()\n } catch {\n throw new CobblError(\n `HTTP ${response.status}: ${response.statusText}`,\n 'API_ERROR',\n { status: response.status }\n )\n }\n\n const message = errorData.error || errorData.message || 'Unknown error'\n const details = errorData.details\n\n switch (response.status) {\n case 400:\n throw new CobblError(message, 'INVALID_REQUEST', details)\n case 401:\n throw new CobblError(message, 'UNAUTHORIZED', details)\n case 403:\n throw new CobblError(message, 'FORBIDDEN', details)\n case 404:\n throw new CobblError(message, 'NOT_FOUND', details)\n case 410:\n throw new CobblError(message, 'ARCHIVED', details)\n case 429:\n throw new CobblError(message, 'RATE_LIMIT_EXCEEDED', details)\n case 500:\n case 502:\n case 503:\n case 504:\n throw new CobblError(message, 'SERVER_ERROR', details)\n default:\n throw new CobblError(message, 'API_ERROR', {\n status: response.status,\n ...details,\n })\n }\n}\n","/**\n * Cobbl SDK - Admin API Client\n *\n * A client for admin/server-side operations like running prompts.\n * Use this in server-side contexts where you need to execute prompts.\n *\n * @example\n * ```typescript\n * import { CobblAdminClient } from '@cobbl-ai/sdk/admin'\n *\n * const client = new CobblAdminClient({\n * apiKey: process.env.COBBL_API_KEY\n * })\n *\n * // Run a prompt\n * const result = await client.runPrompt('sales_summary', {\n * topic: 'Q4 Results',\n * tone: 'friendly'\n * })\n *\n * console.log(result.output)\n * console.log(result.runId) // Use this to link feedback later\n * ```\n */\n\nimport type { PromptInput, PromptVersionClient } from './types'\nimport type { CobblConfig, RunPromptResponse, TokenUsage } from './types'\nimport { CobblError, handleErrorResponse } from './errors'\n\nconst REQUEST_TIMEOUT_MS = 30_000\n\n/**\n * Admin API Client for Cobbl\n *\n * Provides methods to run prompts via the admin API.\n * This client is suitable for use in server-side contexts.\n */\nexport class CobblAdminClient {\n private readonly apiKey: string\n private readonly baseUrl: string\n\n /**\n * Initialize the Cobbl Admin SDK client\n *\n * @param config - Configuration object\n * @param config.apiKey - Your Cobbl API key\n * @param config.baseUrl - Optional base URL for the API (defaults to 'https://api.cobbl.ai')\n *\n * @example Production (uses default URL)\n * ```typescript\n * const client = new CobblAdminClient({\n * apiKey: process.env.COBBL_API_KEY\n * })\n * ```\n *\n * @example Local development with Firebase emulators\n * ```typescript\n * const client = new CobblAdminClient({\n * apiKey: process.env.COBBL_API_KEY,\n * baseUrl: 'http://localhost:5001/your-project-id/us-central1/externalApi'\n * })\n * ```\n */\n constructor(config: CobblConfig) {\n if (!config.apiKey || config.apiKey.trim().length === 0) {\n throw new CobblError('API key is required', 'INVALID_CONFIG')\n }\n\n this.apiKey = config.apiKey\n this.baseUrl = config.baseUrl?.trim() || 'https://api.cobbl.ai'\n }\n\n /**\n * Execute a prompt with the given input variables\n *\n * @param promptSlug - The unique slug identifier for the prompt\n * @param input - Input variables to populate the prompt template\n * @returns Promise containing the prompt execution results\n *\n * @throws {CobblError} When the request fails or API returns an error\n *\n * @example\n * ```typescript\n * const result = await client.runPrompt('sales_summary', {\n * topic: 'Q4 Results',\n * tone: 'friendly',\n * audience: 'investors'\n * })\n *\n * console.log(result.output) // AI-generated response\n * console.log(result.runId) // Save this to link feedback later\n * ```\n */\n async runPrompt(\n promptSlug: string,\n input: PromptInput\n ): Promise<RunPromptResponse> {\n if (!promptSlug || promptSlug.trim().length === 0) {\n throw new CobblError('promptSlug is required', 'INVALID_REQUEST')\n }\n\n try {\n const response = await this.makeRequest('/admin/v1/prompt/run', {\n method: 'POST',\n body: JSON.stringify({\n promptSlug: promptSlug.trim(),\n input,\n }),\n })\n\n if (!response.ok) {\n await handleErrorResponse(response)\n }\n\n const data = (await response.json()) as {\n runId: string\n output: string\n tokenUsage: TokenUsage\n renderedPrompt: string\n promptVersion: PromptVersionClient\n }\n\n return {\n runId: data.runId,\n output: data.output,\n tokenUsage: data.tokenUsage,\n renderedPrompt: data.renderedPrompt,\n promptVersion: data.promptVersion,\n }\n } catch (error) {\n if (error instanceof CobblError) {\n throw error\n }\n throw new CobblError(\n `Failed to run prompt: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'NETWORK_ERROR'\n )\n }\n }\n\n /**\n * Make an HTTP request to the Cobbl API\n * @private\n */\n private async makeRequest(\n path: string,\n options: RequestInit\n ): Promise<Response> {\n const url = `${this.baseUrl}${path}`\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS)\n\n try {\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n ...options.headers,\n },\n signal: controller.signal,\n })\n\n return response\n } finally {\n clearTimeout(timeoutId)\n }\n }\n}\n\n// Export the client\nexport { CobblError } from './errors'\nexport type { CobblErrorCode } from './errors'\nexport type {\n CobblConfig,\n TokenUsage,\n RunPromptRequest,\n RunPromptResponse,\n PromptInput,\n PromptVersionClient,\n Provider,\n VariableConfig,\n} from './types'\n","import type {\n CreateFeedbackRequest,\n UpdateFeedbackRequest,\n Helpful,\n} from './types'\n\nconst VALID_HELPFUL_VALUES: Helpful[] = ['helpful', 'not_helpful']\n\nexport function validateCreateFeedback(\n feedback: CreateFeedbackRequest\n): string | null {\n if (!feedback.runId || feedback.runId.trim().length === 0) {\n return 'runId is required'\n }\n if (\n feedback.helpful !== undefined &&\n !VALID_HELPFUL_VALUES.includes(feedback.helpful)\n ) {\n return 'helpful must be \"helpful\" or \"not_helpful\"'\n }\n if (\n feedback.userFeedback !== undefined &&\n feedback.userFeedback.trim().length === 0\n ) {\n return 'userFeedback cannot be empty'\n }\n if (feedback.helpful === undefined && feedback.userFeedback === undefined) {\n return 'At least one of helpful or userFeedback is required'\n }\n return null\n}\n\nexport function validateUpdateFeedback(\n update: UpdateFeedbackRequest\n): string | null {\n if (\n update.helpful !== undefined &&\n !VALID_HELPFUL_VALUES.includes(update.helpful)\n ) {\n return 'helpful must be \"helpful\" or \"not_helpful\"'\n }\n if (\n update.userFeedback !== undefined &&\n update.userFeedback.trim().length === 0\n ) {\n return 'userFeedback cannot be empty'\n }\n if (update.helpful === undefined && update.userFeedback === undefined) {\n return 'At least one of helpful or userFeedback is required'\n }\n return null\n}\n","/**\n * Cobbl SDK - Public API Client\n *\n * A lightweight client for public-facing feedback operations.\n * Use this in client-side or user-facing contexts.\n * No authentication required - designed for end-user feedback submission.\n *\n * @example\n * ```typescript\n * import { CobblPublicClient } from '@cobbl-ai/sdk/public'\n *\n * const client = new CobblPublicClient({\n * baseUrl: 'https://api.cobbl.ai' // Optional, defaults to production\n * })\n *\n * // Submit feedback\n * const { id } = await client.createFeedback({\n * runId: 'run_abc123',\n * helpful: 'not_helpful'\n * })\n *\n * // Update feedback with details later\n * await client.updateFeedback(id, {\n * userFeedback: 'Too formal'\n * })\n * ```\n */\n\nimport type {\n CreateFeedbackRequest,\n CreateFeedbackResponse,\n UpdateFeedbackRequest,\n UpdateFeedbackResponse,\n} from './types'\nimport { CobblError, handleErrorResponse } from './errors'\nimport { validateCreateFeedback, validateUpdateFeedback } from './validation'\n\n/**\n * Configuration options for CobblPublicClient\n */\nexport interface CobblPublicConfig {\n /**\n * Base URL for the API\n * @optional\n * @default 'https://api.cobbl.ai'\n * @internal\n * @example 'http://localhost:5001/your-project/us-central1/externalApi' // For local development\n */\n baseUrl?: string\n}\n\nconst REQUEST_TIMEOUT_MS = 30_000\n\n/**\n * Public API Client for Cobbl\n *\n * Provides methods to submit and update feedback via the public API.\n * This client is suitable for use in client-side or user-facing contexts.\n * No authentication required - designed for end-user feedback submission.\n */\nexport class CobblPublicClient {\n private readonly baseUrl: string\n\n /**\n * Initialize the Cobbl Public SDK client\n *\n * @param config - Configuration object\n * @param config.baseUrl - Optional base URL for the API (defaults to 'https://api.cobbl.ai')\n */\n constructor(config: CobblPublicConfig = {}) {\n this.baseUrl = config.baseUrl?.trim() || 'https://api.cobbl.ai'\n }\n\n /**\n * Create user feedback for a prompt run\n * Supports segmented feedback - you can provide just helpful, just userFeedback, or both\n * Use updateFeedback to add additional data later\n *\n * @param feedback - Feedback submission data\n * @param feedback.runId - The run ID from a previous runPrompt call\n * @param feedback.helpful - Whether the output was helpful ('helpful' or 'not_helpful') - optional\n * @param feedback.userFeedback - Detailed feedback message from the user - optional\n * @returns Promise containing the created feedback ID\n *\n * @throws {CobblError} When the request fails or API returns an error\n *\n * @example Submit just thumbs down first\n * ```typescript\n * const { id } = await client.createFeedback({\n * runId: result.runId,\n * helpful: 'not_helpful'\n * })\n * // Later, add details\n * await client.updateFeedback(id, {\n * userFeedback: 'The response was too formal and lengthy'\n * })\n * ```\n *\n * @example Submit both at once\n * ```typescript\n * await client.createFeedback({\n * runId: result.runId,\n * helpful: 'not_helpful',\n * userFeedback: 'The response was too formal and lengthy'\n * })\n * ```\n */\n async createFeedback(\n feedback: CreateFeedbackRequest\n ): Promise<CreateFeedbackResponse> {\n const validationError = validateCreateFeedback(feedback)\n if (validationError) {\n throw new CobblError(validationError, 'INVALID_REQUEST')\n }\n\n try {\n // Build request body with only provided fields\n const body: CreateFeedbackRequest = {\n runId: feedback.runId.trim(),\n helpful: feedback.helpful,\n userFeedback: feedback.userFeedback?.trim(),\n }\n\n const response = await this.makeRequest('/public/v1/feedback', {\n method: 'POST',\n body: JSON.stringify(body),\n })\n\n if (!response.ok) {\n await handleErrorResponse(response)\n }\n\n const data = (await response.json()) as {\n id: string\n message: string\n }\n\n return {\n id: data.id,\n message: data.message,\n }\n } catch (error) {\n if (error instanceof CobblError) {\n throw error\n }\n throw new CobblError(\n `Failed to create feedback: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'NETWORK_ERROR'\n )\n }\n }\n\n /**\n * Update existing feedback with additional data\n * Use this to add helpful sentiment or detailed feedback after initial submission\n *\n * @param id - The ID returned from createFeedback\n * @param update - The data to update\n * @param update.helpful - Whether the output was helpful ('helpful' or 'not_helpful') - optional\n * @param update.userFeedback - Detailed feedback message from the user - optional\n * @returns Promise containing the updated feedback ID\n *\n * @throws {CobblError} When the request fails or API returns an error\n *\n * @example Add details after initial thumbs down\n * ```typescript\n * // First, submit just the rating\n * const { id } = await client.createFeedback({\n * runId: result.runId,\n * helpful: 'not_helpful'\n * })\n *\n * // Later, add detailed feedback\n * await client.updateFeedback(id, {\n * userFeedback: 'The response was too formal and lengthy'\n * })\n * ```\n */\n async updateFeedback(\n id: string,\n update: UpdateFeedbackRequest\n ): Promise<UpdateFeedbackResponse> {\n if (!id || id.trim().length === 0) {\n throw new CobblError('id is required', 'INVALID_REQUEST')\n }\n\n const validationError = validateUpdateFeedback(update)\n if (validationError) {\n throw new CobblError(validationError, 'INVALID_REQUEST')\n }\n\n try {\n // Build request body with only provided fields\n const body: UpdateFeedbackRequest = {\n helpful: update.helpful,\n userFeedback: update.userFeedback?.trim(),\n }\n\n const response = await this.makeRequest(\n `/public/v1/feedback/${id.trim()}`,\n {\n method: 'PATCH',\n body: JSON.stringify(body),\n }\n )\n\n if (!response.ok) {\n await handleErrorResponse(response)\n }\n\n const data = (await response.json()) as {\n id: string\n message: string\n }\n\n return {\n id: data.id,\n message: data.message,\n }\n } catch (error) {\n if (error instanceof CobblError) {\n throw error\n }\n throw new CobblError(\n `Failed to update feedback: ${error instanceof Error ? error.message : 'Unknown error'}`,\n 'NETWORK_ERROR'\n )\n }\n }\n\n /**\n * Make an HTTP request to the Cobbl API\n * @private\n */\n private async makeRequest(\n path: string,\n options: RequestInit\n ): Promise<Response> {\n const url = `${this.baseUrl}${path}`\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS)\n\n try {\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n signal: controller.signal,\n })\n\n return response\n } finally {\n clearTimeout(timeoutId)\n }\n }\n}\n\n// Export the client\nexport { CobblError } from './errors'\nexport type { CobblErrorCode } from './errors'\nexport type {\n CreateFeedbackRequest,\n CreateFeedbackResponse,\n UpdateFeedbackRequest,\n UpdateFeedbackResponse,\n Helpful,\n} from './types'\n"]}
|