@gradientlabs/client 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,1223 @@
1
+ 'use strict';
2
+
3
+ var crypto = require('crypto');
4
+
5
+ // src/errors.ts
6
+ var ErrorCode = {
7
+ NotFound: "not_found",
8
+ Unauthenticated: "unauthenticated",
9
+ PermissionDenied: "permission_denied",
10
+ InvalidArgument: "invalid_argument",
11
+ FailedPrecondition: "failed_precondition",
12
+ ResourceExhausted: "resource_exhausted",
13
+ AlreadyExists: "already_exists",
14
+ Unavailable: "unavailable",
15
+ DeadlineExceeded: "deadline_exceeded",
16
+ Internal: "internal"
17
+ };
18
+ var GradientLabsError = class extends Error {
19
+ constructor(message, options) {
20
+ super(message, options);
21
+ this.name = "GradientLabsError";
22
+ }
23
+ };
24
+ var ConfigurationError = class extends GradientLabsError {
25
+ constructor(message) {
26
+ super(message);
27
+ this.name = "ConfigurationError";
28
+ }
29
+ };
30
+ var ApiError = class extends GradientLabsError {
31
+ /** HTTP status code of the response. */
32
+ statusCode;
33
+ /** Machine-readable error code from the response envelope. */
34
+ code;
35
+ /** Arbitrary structured details returned with the error. */
36
+ details;
37
+ constructor(args) {
38
+ super(args.message || `unexpected response status: ${args.statusCode}`);
39
+ this.name = "ApiError";
40
+ this.statusCode = args.statusCode;
41
+ this.code = args.code;
42
+ this.details = args.details ?? {};
43
+ }
44
+ /**
45
+ * The identifier that can be given to Gradient Labs technical support to
46
+ * investigate an error, if present in the error details.
47
+ */
48
+ get traceId() {
49
+ const traceId = this.details["trace_id"];
50
+ return typeof traceId === "string" ? traceId : void 0;
51
+ }
52
+ };
53
+
54
+ // src/internal/version.ts
55
+ var VERSION = "0.1.0";
56
+
57
+ // src/internal/user-agent.ts
58
+ function userAgent() {
59
+ const runtimeVersion = typeof process !== "undefined" && process.version ? process.version : "unknown";
60
+ return `Gradient-Labs-Node/${VERSION} (node/${runtimeVersion})`;
61
+ }
62
+
63
+ // src/internal/http.ts
64
+ var HttpClient = class {
65
+ constructor(config) {
66
+ this.config = config;
67
+ }
68
+ config;
69
+ async request(method, path, options = {}) {
70
+ const url = this.buildUrl(path, options.query);
71
+ const headers = {
72
+ Authorization: `Bearer ${this.config.apiKey}`,
73
+ Accept: "application/json",
74
+ "User-Agent": userAgent()
75
+ };
76
+ let body;
77
+ if (options.body !== void 0) {
78
+ body = JSON.stringify(options.body);
79
+ headers["Content-Type"] = "application/json";
80
+ }
81
+ const signal = this.buildSignal(options.signal);
82
+ let response;
83
+ try {
84
+ response = await this.config.fetch(url, { method, headers, body, signal });
85
+ } catch (cause) {
86
+ throw new GradientLabsError(`request to ${method} ${path} failed: ${errorMessage(cause)}`, {
87
+ cause
88
+ });
89
+ }
90
+ const rawBody = await response.text();
91
+ if (response.status < 200 || response.status > 299) {
92
+ throw toApiError(response.status, rawBody);
93
+ }
94
+ if (!rawBody) {
95
+ return void 0;
96
+ }
97
+ try {
98
+ return JSON.parse(rawBody);
99
+ } catch (cause) {
100
+ throw new GradientLabsError(`failed to parse response body: ${errorMessage(cause)}`, {
101
+ cause
102
+ });
103
+ }
104
+ }
105
+ buildUrl(path, query) {
106
+ const base = this.config.baseUrl.replace(/\/+$/, "");
107
+ const cleanPath = path.replace(/^\/+/, "");
108
+ const url = new URL(`${base}/${cleanPath}`);
109
+ if (query) {
110
+ for (const [key, value] of Object.entries(query)) {
111
+ if (value !== void 0 && value !== null) {
112
+ url.searchParams.set(key, String(value));
113
+ }
114
+ }
115
+ }
116
+ return url.toString();
117
+ }
118
+ buildSignal(callerSignal) {
119
+ const { timeoutMs } = this.config;
120
+ if (timeoutMs === void 0) {
121
+ return callerSignal;
122
+ }
123
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
124
+ if (!callerSignal) {
125
+ return timeoutSignal;
126
+ }
127
+ if (typeof AbortSignal.any === "function") {
128
+ return AbortSignal.any([callerSignal, timeoutSignal]);
129
+ }
130
+ return callerSignal;
131
+ }
132
+ };
133
+ function toApiError(statusCode, rawBody) {
134
+ let code = "";
135
+ let message = "";
136
+ let details = {};
137
+ if (rawBody) {
138
+ try {
139
+ const parsed = JSON.parse(rawBody);
140
+ code = parsed.code ?? "";
141
+ message = parsed.message ?? "";
142
+ details = parsed.details ?? {};
143
+ } catch {
144
+ }
145
+ }
146
+ return new ApiError({ statusCode, code, message, details });
147
+ }
148
+ function errorMessage(cause) {
149
+ return cause instanceof Error ? cause.message : String(cause);
150
+ }
151
+
152
+ // src/resources/articles.ts
153
+ var Articles = class {
154
+ constructor(http) {
155
+ this.http = http;
156
+ }
157
+ http;
158
+ /** Creates or updates a help article. */
159
+ upsert(params, config = {}) {
160
+ return this.http.request("POST", "articles", { body: params, signal: config.signal });
161
+ }
162
+ /** Updates whether the AI agent can use an article or not. */
163
+ setUsageStatus(id, params, config = {}) {
164
+ return this.http.request("POST", `articles/${encodeURIComponent(id)}/usage-status`, {
165
+ body: params,
166
+ signal: config.signal
167
+ });
168
+ }
169
+ /** Marks an article as deleted. */
170
+ delete(id, config = {}) {
171
+ return this.http.request("DELETE", `articles/${encodeURIComponent(id)}`, {
172
+ signal: config.signal
173
+ });
174
+ }
175
+ };
176
+
177
+ // src/resources/back-office-tasks.ts
178
+ var BackOfficeTasks = class {
179
+ constructor(http) {
180
+ this.http = http;
181
+ }
182
+ http;
183
+ /** Creates a new back-office task. */
184
+ create(params, config = {}) {
185
+ return this.http.request("POST", "back-office-tasks", {
186
+ body: params,
187
+ signal: config.signal
188
+ });
189
+ }
190
+ /** Retrieves detailed information about a back-office task. */
191
+ get(id, config = {}) {
192
+ return this.http.request("GET", `back-office-tasks/${encodeURIComponent(id)}/read`, {
193
+ signal: config.signal
194
+ });
195
+ }
196
+ };
197
+
198
+ // src/resources/conversations.ts
199
+ var Conversations = class {
200
+ constructor(http) {
201
+ this.http = http;
202
+ }
203
+ http;
204
+ /** Begins a conversation. */
205
+ start(params, config = {}) {
206
+ return this.http.request("POST", "conversations", { body: params, signal: config.signal });
207
+ }
208
+ /** Retrieves a conversation, including the latest AI agent metadata. */
209
+ get(id, params = {}, config = {}) {
210
+ return this.http.request("GET", `conversations/${encodeURIComponent(id)}/read`, {
211
+ query: { support_platform: params.support_platform },
212
+ signal: config.signal
213
+ });
214
+ }
215
+ /**
216
+ * Retrieves a conversation.
217
+ *
218
+ * @deprecated Use {@link Conversations.get} instead, which reads from the
219
+ * canonical `/read` endpoint.
220
+ */
221
+ getDeprecated(id, config = {}) {
222
+ return this.http.request("GET", `conversations/${encodeURIComponent(id)}`, {
223
+ signal: config.signal
224
+ });
225
+ }
226
+ /** Adds a new message to an existing conversation. */
227
+ addMessage(id, params, config = {}) {
228
+ return this.http.request("POST", `conversations/${encodeURIComponent(id)}/messages`, {
229
+ body: params,
230
+ signal: config.signal
231
+ });
232
+ }
233
+ /** Transfers responsibility for handling a conversation to a participant. */
234
+ assign(id, params, config = {}) {
235
+ return this.http.request("PUT", `conversations/${encodeURIComponent(id)}/assignee`, {
236
+ body: params,
237
+ signal: config.signal
238
+ });
239
+ }
240
+ /** Logs an event against the conversation (e.g. typing, delivered, read). */
241
+ addEvent(id, params, config = {}) {
242
+ return this.http.request("POST", `conversations/${encodeURIComponent(id)}/events`, {
243
+ body: params,
244
+ signal: config.signal
245
+ });
246
+ }
247
+ /** Adds the result of a customer survey (e.g. CSAT) to a conversation. */
248
+ rate(id, params, config = {}) {
249
+ return this.http.request("PUT", `conversations/${encodeURIComponent(id)}/rate`, {
250
+ body: params,
251
+ signal: config.signal
252
+ });
253
+ }
254
+ /** Cancels a conversation (e.g. because a human has taken it over). */
255
+ cancel(id, params = {}, config = {}) {
256
+ return this.http.request("PUT", `conversations/${encodeURIComponent(id)}/cancel`, {
257
+ body: params,
258
+ signal: config.signal
259
+ });
260
+ }
261
+ /** Finishes a conversation that has reached a natural end state. */
262
+ finish(id, params = {}, config = {}) {
263
+ return this.http.request("PUT", `conversations/${encodeURIComponent(id)}/finish`, {
264
+ body: params,
265
+ signal: config.signal
266
+ });
267
+ }
268
+ /** Re-opens a conversation that was previously finished. */
269
+ resume(id, params, config = {}) {
270
+ return this.http.request("PUT", `conversations/${encodeURIComponent(id)}/resume`, {
271
+ body: params,
272
+ signal: config.signal
273
+ });
274
+ }
275
+ /** Returns the result of an async tool execution. */
276
+ returnAsyncToolResult(id, params, config = {}) {
277
+ return this.http.request(
278
+ "PUT",
279
+ `conversations/${encodeURIComponent(id)}/return-async-tool-result`,
280
+ { body: params, signal: config.signal }
281
+ );
282
+ }
283
+ };
284
+
285
+ // src/resources/hand-off-targets.ts
286
+ var HandOffTargets = class {
287
+ constructor(http) {
288
+ this.http = http;
289
+ }
290
+ http;
291
+ /** Lists the available hand-off targets. */
292
+ async list(config = {}) {
293
+ const rsp = await this.http.request("GET", "hand-off-targets", {
294
+ signal: config.signal
295
+ });
296
+ return rsp.targets;
297
+ }
298
+ /** Creates or updates a hand-off target. */
299
+ upsert(params, config = {}) {
300
+ return this.http.request("POST", "hand-off-targets", { body: params, signal: config.signal });
301
+ }
302
+ /** Deletes a hand-off target. */
303
+ delete(params, config = {}) {
304
+ return this.http.request("DELETE", "hand-off-targets", {
305
+ query: { id: params.id },
306
+ signal: config.signal
307
+ });
308
+ }
309
+ /** Gets the current default hand-off target for a channel. Returns "" if unset. */
310
+ async getDefault(params, config = {}) {
311
+ const rsp = await this.http.request("GET", "hand-off-targets/default", {
312
+ query: { channel: params.channel },
313
+ signal: config.signal
314
+ });
315
+ return rsp.id;
316
+ }
317
+ /** Sets the default hand-off target for a channel. */
318
+ setDefault(params, config = {}) {
319
+ return this.http.request("PUT", "hand-off-targets/default", {
320
+ body: params,
321
+ signal: config.signal
322
+ });
323
+ }
324
+ };
325
+
326
+ // src/resources/ip-addresses.ts
327
+ var IpAddressesResource = class {
328
+ constructor(http) {
329
+ this.http = http;
330
+ }
331
+ http;
332
+ /** Returns the list of IP addresses Gradient Labs uses, in CIDR format. */
333
+ list(config = {}) {
334
+ return this.http.request("GET", "ip-addresses", { signal: config.signal });
335
+ }
336
+ };
337
+
338
+ // src/resources/notes.ts
339
+ var Notes = class {
340
+ constructor(http) {
341
+ this.http = http;
342
+ }
343
+ http;
344
+ /** Creates a new note. */
345
+ create(params, config = {}) {
346
+ return this.http.request("POST", "notes", { body: params, signal: config.signal });
347
+ }
348
+ /** Updates an existing note's contents. */
349
+ update(id, params, config = {}) {
350
+ return this.http.request("POST", `notes/${encodeURIComponent(id)}`, {
351
+ body: params,
352
+ signal: config.signal
353
+ });
354
+ }
355
+ /** Updates a note's status. */
356
+ setStatus(id, params, config = {}) {
357
+ return this.http.request("POST", `notes/${encodeURIComponent(id)}/status`, {
358
+ body: params,
359
+ signal: config.signal
360
+ });
361
+ }
362
+ /** Marks a note as deleted. */
363
+ delete(id, config = {}) {
364
+ return this.http.request("DELETE", `notes/${encodeURIComponent(id)}`, {
365
+ signal: config.signal
366
+ });
367
+ }
368
+ };
369
+
370
+ // src/resources/outbound-conversations.ts
371
+ var OutboundConversations = class {
372
+ constructor(http) {
373
+ this.http = http;
374
+ }
375
+ http;
376
+ /** Creates and starts a new outbound conversation initiated by the AI agent. */
377
+ start(params, config = {}) {
378
+ return this.http.request("POST", "outbound/conversations", {
379
+ body: params,
380
+ signal: config.signal
381
+ });
382
+ }
383
+ };
384
+
385
+ // src/internal/pagination.ts
386
+ async function* paginate(fetchPage) {
387
+ let after;
388
+ do {
389
+ const page = await fetchPage(after);
390
+ for (const item of page.data) {
391
+ yield item;
392
+ }
393
+ after = page.pageInfo.next;
394
+ } while (after);
395
+ }
396
+
397
+ // src/resources/procedures.ts
398
+ var Procedures = class {
399
+ constructor(http) {
400
+ this.http = http;
401
+ }
402
+ http;
403
+ /** Retrieves one page of procedures. */
404
+ async list(params = {}, config = {}) {
405
+ const rsp = await this.http.request("GET", "procedures", {
406
+ query: { cursor: params.cursor, status: params.status },
407
+ signal: config.signal
408
+ });
409
+ return { data: rsp.procedures, pageInfo: rsp.pagination };
410
+ }
411
+ /** Iterates over all procedures, transparently following pagination cursors. */
412
+ listAll(params = {}, config = {}) {
413
+ return paginate((cursor) => this.list({ ...params, cursor }, config));
414
+ }
415
+ /** Retrieves a specific procedure by ID. */
416
+ get(id, config = {}) {
417
+ return this.http.request("GET", `procedure/${encodeURIComponent(id)}`, {
418
+ signal: config.signal
419
+ });
420
+ }
421
+ /** Configures daily usage limits for a procedure. Returns the updated procedure. */
422
+ async setLimit(id, params, config = {}) {
423
+ const rsp = await this.http.request(
424
+ "POST",
425
+ `procedure/${encodeURIComponent(id)}/limit`,
426
+ { body: params, signal: config.signal }
427
+ );
428
+ return rsp.procedure;
429
+ }
430
+ /** Lists the non-ephemeral versions of a procedure. */
431
+ async listVersions(id, config = {}) {
432
+ const rsp = await this.http.request(
433
+ "GET",
434
+ `procedures/${encodeURIComponent(id)}/versions`,
435
+ { signal: config.signal }
436
+ );
437
+ return rsp.Versions;
438
+ }
439
+ /** Promotes a procedure version to be the live (production) version. */
440
+ setLiveVersion(id, version, config = {}) {
441
+ return this.http.request(
442
+ "POST",
443
+ `procedures/${encodeURIComponent(id)}/versions/${version}/set-live`,
444
+ { signal: config.signal }
445
+ );
446
+ }
447
+ /** Removes a procedure version from being the live revision. */
448
+ unsetLiveVersion(id, version, config = {}) {
449
+ return this.http.request(
450
+ "POST",
451
+ `procedures/${encodeURIComponent(id)}/versions/${version}/unset-live`,
452
+ { signal: config.signal }
453
+ );
454
+ }
455
+ /** Marks a procedure version as gated for A/B testing. */
456
+ setGatedVersion(id, version, params, config = {}) {
457
+ return this.http.request(
458
+ "POST",
459
+ `procedures/${encodeURIComponent(id)}/versions/${version}/set-gated`,
460
+ { body: params, signal: config.signal }
461
+ );
462
+ }
463
+ /** Removes the gated marking from a procedure version. */
464
+ unsetGatedVersion(id, version, config = {}) {
465
+ return this.http.request(
466
+ "POST",
467
+ `procedures/${encodeURIComponent(id)}/versions/${version}/unset-gated`,
468
+ { signal: config.signal }
469
+ );
470
+ }
471
+ };
472
+
473
+ // src/resources/resource-sources.ts
474
+ var ResourceSources = class {
475
+ constructor(http) {
476
+ this.http = http;
477
+ }
478
+ http;
479
+ /** Lists all resource sources accessible to the company. */
480
+ async list(config = {}) {
481
+ const rsp = await this.http.request("GET", "resource-sources", {
482
+ signal: config.signal
483
+ });
484
+ return rsp.resource_sources;
485
+ }
486
+ /** Creates a new resource source. */
487
+ create(params, config = {}) {
488
+ return this.http.request("POST", "resource-sources", { body: params, signal: config.signal });
489
+ }
490
+ /** Retrieves a specific resource source by ID. */
491
+ get(id, config = {}) {
492
+ return this.http.request("GET", `resource-sources/${encodeURIComponent(id)}`, {
493
+ signal: config.signal
494
+ });
495
+ }
496
+ /** Updates an existing resource source. */
497
+ update(id, params, config = {}) {
498
+ return this.http.request("PUT", `resource-sources/${encodeURIComponent(id)}`, {
499
+ body: params,
500
+ signal: config.signal
501
+ });
502
+ }
503
+ /** Deletes a resource source. */
504
+ delete(id, config = {}) {
505
+ return this.http.request("DELETE", `resource-sources/${encodeURIComponent(id)}`, {
506
+ signal: config.signal
507
+ });
508
+ }
509
+ /** Modifies the source schema based on the provided payload examples. */
510
+ updateSchemaByExamples(id, params, config = {}) {
511
+ return this.http.request(
512
+ "POST",
513
+ `resource-sources/${encodeURIComponent(id)}/schema-by-examples`,
514
+ { body: params, signal: config.signal }
515
+ );
516
+ }
517
+ };
518
+
519
+ // src/resources/resource-types.ts
520
+ var ResourceTypes = class {
521
+ constructor(http) {
522
+ this.http = http;
523
+ }
524
+ http;
525
+ /** Lists all resource types accessible to the company. */
526
+ async list(config = {}) {
527
+ const rsp = await this.http.request("GET", "resource-types", {
528
+ signal: config.signal
529
+ });
530
+ return rsp.resource_types;
531
+ }
532
+ /** Creates a new resource type. */
533
+ create(params, config = {}) {
534
+ return this.http.request("POST", "resource-types", { body: params, signal: config.signal });
535
+ }
536
+ /** Retrieves a specific resource type by ID. */
537
+ get(id, config = {}) {
538
+ return this.http.request("GET", `resource-types/${encodeURIComponent(id)}`, {
539
+ signal: config.signal
540
+ });
541
+ }
542
+ /** Updates an existing resource type. */
543
+ update(id, params, config = {}) {
544
+ return this.http.request("PUT", `resource-types/${encodeURIComponent(id)}`, {
545
+ body: params,
546
+ signal: config.signal
547
+ });
548
+ }
549
+ /** Deletes a resource type. */
550
+ delete(id, config = {}) {
551
+ return this.http.request("DELETE", `resource-types/${encodeURIComponent(id)}`, {
552
+ signal: config.signal
553
+ });
554
+ }
555
+ };
556
+
557
+ // src/resources/secrets.ts
558
+ var Secrets = class {
559
+ constructor(http) {
560
+ this.http = http;
561
+ }
562
+ http;
563
+ /** Lists the company's configured secrets. */
564
+ async list(config = {}) {
565
+ const rsp = await this.http.request("GET", "secrets", {
566
+ signal: config.signal
567
+ });
568
+ return rsp.secrets;
569
+ }
570
+ /** Creates or updates a secret. */
571
+ write(name, params, config = {}) {
572
+ return this.http.request("PUT", `secrets/${encodeURIComponent(name)}`, {
573
+ body: params,
574
+ signal: config.signal
575
+ });
576
+ }
577
+ /** Revokes a secret so it can no longer be used. */
578
+ revoke(name, config = {}) {
579
+ return this.http.request("DELETE", `secrets/${encodeURIComponent(name)}`, {
580
+ signal: config.signal
581
+ });
582
+ }
583
+ };
584
+
585
+ // src/resources/terminology-substitutions.ts
586
+ var TerminologySubstitutions = class {
587
+ constructor(http) {
588
+ this.http = http;
589
+ }
590
+ http;
591
+ /** Returns all terminology substitutions configured for the organization. */
592
+ async list(config = {}) {
593
+ const rsp = await this.http.request("GET", "terminology-substitutions", {
594
+ signal: config.signal
595
+ });
596
+ return rsp.substitutions;
597
+ }
598
+ /** Creates a new terminology substitution. */
599
+ create(params, config = {}) {
600
+ return this.http.request("POST", "terminology-substitutions", {
601
+ body: params,
602
+ signal: config.signal
603
+ });
604
+ }
605
+ /** Returns a single terminology substitution by ID. */
606
+ get(id, config = {}) {
607
+ return this.http.request("GET", `terminology-substitutions/${encodeURIComponent(id)}`, {
608
+ signal: config.signal
609
+ });
610
+ }
611
+ /** Updates an existing terminology substitution. */
612
+ update(id, params, config = {}) {
613
+ return this.http.request("PUT", `terminology-substitutions/${encodeURIComponent(id)}`, {
614
+ body: params,
615
+ signal: config.signal
616
+ });
617
+ }
618
+ /** Deletes a terminology substitution by ID. */
619
+ delete(id, config = {}) {
620
+ return this.http.request("DELETE", `terminology-substitutions/${encodeURIComponent(id)}`, {
621
+ signal: config.signal
622
+ });
623
+ }
624
+ };
625
+
626
+ // src/resources/tools.ts
627
+ var Tools = class {
628
+ constructor(http) {
629
+ this.http = http;
630
+ }
631
+ http;
632
+ /** Returns all tools created by the company. */
633
+ async list(config = {}) {
634
+ const rsp = await this.http.request("GET", "tools", {
635
+ signal: config.signal
636
+ });
637
+ return rsp.tools;
638
+ }
639
+ /** Creates a new custom tool. */
640
+ create(params, config = {}) {
641
+ return this.http.request("POST", "tools", { body: params, signal: config.signal });
642
+ }
643
+ /** Reads a tool by ID and optional version. */
644
+ get(id, params = {}, config = {}) {
645
+ return this.http.request("GET", `tools/${encodeURIComponent(id)}`, {
646
+ query: { version: params.version },
647
+ signal: config.signal
648
+ });
649
+ }
650
+ /** Creates a new revision of a tool. The name and type cannot be changed. */
651
+ update(id, params, config = {}) {
652
+ return this.http.request("PUT", `tools/${encodeURIComponent(id)}`, {
653
+ body: params,
654
+ signal: config.signal
655
+ });
656
+ }
657
+ /** Deletes a tool. */
658
+ delete(id, config = {}) {
659
+ return this.http.request("DELETE", `tools/${encodeURIComponent(id)}`, {
660
+ signal: config.signal
661
+ });
662
+ }
663
+ /** Executes a tool, enabling you to test it without an actual conversation. */
664
+ execute(id, params, config = {}) {
665
+ return this.http.request("POST", `tools/${encodeURIComponent(id)}/execute`, {
666
+ body: { arguments: params.arguments, token: params.token ?? "" },
667
+ signal: config.signal
668
+ });
669
+ }
670
+ };
671
+
672
+ // src/resources/topics.ts
673
+ var Topics = class {
674
+ constructor(http) {
675
+ this.http = http;
676
+ }
677
+ http;
678
+ /** Lists the company's topics, optionally filtered by support platform. */
679
+ async list(params = {}, config = {}) {
680
+ const rsp = await this.http.request("GET", "topics", {
681
+ query: { support_platform: params.support_platform },
682
+ signal: config.signal
683
+ });
684
+ return rsp.Topics;
685
+ }
686
+ /** Reads a single article topic. */
687
+ get(id, params = {}, config = {}) {
688
+ return this.http.request("GET", `topic/${encodeURIComponent(id)}`, {
689
+ query: { support_platform: params.support_platform },
690
+ signal: config.signal
691
+ });
692
+ }
693
+ /** Creates or updates an article topic. */
694
+ upsert(params, config = {}) {
695
+ return this.http.request("POST", "topics", { body: params, signal: config.signal });
696
+ }
697
+ };
698
+
699
+ // src/resources/traffic-groups.ts
700
+ var TrafficGroups = class {
701
+ constructor(http) {
702
+ this.http = http;
703
+ }
704
+ http;
705
+ /** Lists all traffic groups for the company. */
706
+ async list(config = {}) {
707
+ const rsp = await this.http.request("GET", "traffic-groups", {
708
+ signal: config.signal
709
+ });
710
+ return rsp.traffic_groups;
711
+ }
712
+ /** Creates a new traffic group. */
713
+ create(params, config = {}) {
714
+ return this.http.request("POST", "traffic-groups", { body: params, signal: config.signal });
715
+ }
716
+ /** Updates an existing traffic group. */
717
+ update(id, params, config = {}) {
718
+ return this.http.request("PUT", `traffic-groups/${encodeURIComponent(id)}`, {
719
+ body: params,
720
+ signal: config.signal
721
+ });
722
+ }
723
+ /** Deletes a traffic group and all associated targets. */
724
+ delete(id, config = {}) {
725
+ return this.http.request("DELETE", `traffic-groups/${encodeURIComponent(id)}`, {
726
+ signal: config.signal
727
+ });
728
+ }
729
+ /** Adds a target to a traffic group. */
730
+ addTarget(id, params, config = {}) {
731
+ return this.http.request("POST", `traffic-groups/${encodeURIComponent(id)}/targets`, {
732
+ body: params,
733
+ signal: config.signal
734
+ });
735
+ }
736
+ /** Removes a target from a traffic group. */
737
+ removeTarget(id, targetId, config = {}) {
738
+ return this.http.request(
739
+ "DELETE",
740
+ `traffic-groups/${encodeURIComponent(id)}/targets/${encodeURIComponent(targetId)}`,
741
+ { signal: config.signal }
742
+ );
743
+ }
744
+ /** Excludes a target (e.g. a procedure) from a traffic group. */
745
+ addExclusion(id, params, config = {}) {
746
+ return this.http.request("POST", `traffic-groups/${encodeURIComponent(id)}/exclusions`, {
747
+ body: params,
748
+ signal: config.signal
749
+ });
750
+ }
751
+ /** Removes a target exclusion from a traffic group. */
752
+ removeExclusion(id, targetId, config = {}) {
753
+ return this.http.request(
754
+ "DELETE",
755
+ `traffic-groups/${encodeURIComponent(id)}/exclusions/${encodeURIComponent(targetId)}`,
756
+ { signal: config.signal }
757
+ );
758
+ }
759
+ };
760
+
761
+ // src/resources/voice.ts
762
+ var Voice = class {
763
+ constructor(http) {
764
+ this.http = http;
765
+ }
766
+ http;
767
+ /**
768
+ * Retrieves the most recent call context for a given phone number. Throws an
769
+ * {@link ApiError} with status 404 if there have been no recent call events.
770
+ */
771
+ getLatestCallContext(phoneNumber, params = {}, config = {}) {
772
+ return this.http.request(
773
+ "GET",
774
+ `voice/latest-call-context/${encodeURIComponent(phoneNumber)}`,
775
+ {
776
+ query: {
777
+ lookback_seconds: params.lookback_seconds,
778
+ include_large_fields: params.include_large_fields
779
+ },
780
+ signal: config.signal
781
+ }
782
+ );
783
+ }
784
+ };
785
+
786
+ // src/webhooks/events.ts
787
+ var WebhookType = {
788
+ AgentMessage: "agent.message",
789
+ ConversationHandOff: "conversation.hand_off",
790
+ ConversationFinished: "conversation.finished",
791
+ ActionExecute: "action.execute",
792
+ ResourcePull: "resource.pull",
793
+ BackOfficeTaskComplete: "back-office-task.complete",
794
+ BackOfficeTaskHandOff: "back-office-task.hand-off",
795
+ BackOfficeTaskFail: "back-office-task.fail"
796
+ };
797
+
798
+ // src/webhooks/verifier.ts
799
+ var SIGNATURE_HEADER = "x-gradientlabs-signature";
800
+ var TOKEN_HEADER = "x-gradientlabs-token";
801
+ var DEFAULT_LEEWAY_MS = 5 * 60 * 1e3;
802
+ var InvalidWebhookSignatureError = class extends GradientLabsError {
803
+ constructor(message = "webhook signature is invalid") {
804
+ super(message);
805
+ this.name = "InvalidWebhookSignatureError";
806
+ }
807
+ };
808
+ var UnknownWebhookTypeError = class extends GradientLabsError {
809
+ type;
810
+ constructor(type) {
811
+ super(`unknown webhook event type received: ${type}`);
812
+ this.name = "UnknownWebhookTypeError";
813
+ this.type = type;
814
+ }
815
+ };
816
+ var WebhookVerifier = class {
817
+ signingKey;
818
+ leewayMs;
819
+ now;
820
+ constructor(config) {
821
+ this.signingKey = config.signingKey;
822
+ this.leewayMs = config.leewayMs ?? DEFAULT_LEEWAY_MS;
823
+ this.now = config.now ?? Date.now;
824
+ }
825
+ /**
826
+ * Verifies a webhook's signature and timestamp. Throws
827
+ * {@link InvalidWebhookSignatureError} if verification fails.
828
+ */
829
+ verify(args) {
830
+ const body = toBuffer(args.body);
831
+ const { timestamp, signatures } = parseSignatureHeader(args.signature);
832
+ if (Math.abs(this.now() - timestamp * 1e3) > this.leewayMs) {
833
+ throw new InvalidWebhookSignatureError("webhook timestamp is outside the allowed leeway");
834
+ }
835
+ const expected = this.computeSignature(timestamp, body);
836
+ for (const candidate of signatures) {
837
+ if (constantTimeEqual(expected, candidate)) {
838
+ return;
839
+ }
840
+ }
841
+ throw new InvalidWebhookSignatureError();
842
+ }
843
+ /**
844
+ * Verifies a webhook request, then parses it into a typed event. Returns the
845
+ * event along with the optional `X-GradientLabs-Token` passthrough.
846
+ *
847
+ * Verification always happens before the event type is inspected.
848
+ */
849
+ parse(args) {
850
+ const signature = getHeader(args.headers, SIGNATURE_HEADER);
851
+ this.verify({ body: args.body, signature });
852
+ const text = typeof args.body === "string" ? args.body : Buffer.from(args.body).toString("utf8");
853
+ const payload = JSON.parse(text);
854
+ if (!isKnownType(payload.type)) {
855
+ throw new UnknownWebhookTypeError(payload.type);
856
+ }
857
+ const event = {
858
+ id: payload.id,
859
+ type: payload.type,
860
+ sequence_number: payload.sequence_number,
861
+ timestamp: payload.timestamp,
862
+ data: payload.data
863
+ };
864
+ const token = getHeader(args.headers, TOKEN_HEADER) ?? void 0;
865
+ return { event, token };
866
+ }
867
+ computeSignature(timestamp, body) {
868
+ return crypto.createHmac("sha256", this.signingKey).update(`${timestamp}.`).update(body).digest();
869
+ }
870
+ };
871
+ function isKnownType(type) {
872
+ return Object.values(WebhookType).includes(type);
873
+ }
874
+ function parseSignatureHeader(header) {
875
+ if (!header) {
876
+ throw new InvalidWebhookSignatureError("missing signature header");
877
+ }
878
+ let timestamp;
879
+ const signatures = [];
880
+ for (const pair of header.split(",")) {
881
+ const idx = pair.indexOf("=");
882
+ if (idx === -1) {
883
+ throw new InvalidWebhookSignatureError("malformed signature header");
884
+ }
885
+ const key = pair.slice(0, idx);
886
+ const value = pair.slice(idx + 1);
887
+ if (key === "t") {
888
+ const parsed = Number.parseInt(value, 10);
889
+ if (!Number.isFinite(parsed)) {
890
+ throw new InvalidWebhookSignatureError("invalid timestamp component");
891
+ }
892
+ timestamp = parsed;
893
+ } else if (key === "v1") {
894
+ try {
895
+ signatures.push(Buffer.from(value, "hex"));
896
+ } catch {
897
+ throw new InvalidWebhookSignatureError("invalid signature component");
898
+ }
899
+ }
900
+ }
901
+ if (timestamp === void 0) {
902
+ throw new InvalidWebhookSignatureError("signature header contains no timestamp component");
903
+ }
904
+ if (signatures.length === 0) {
905
+ throw new InvalidWebhookSignatureError("signature header contains no v1 signature");
906
+ }
907
+ return { timestamp, signatures };
908
+ }
909
+ function constantTimeEqual(a, b) {
910
+ if (a.length !== b.length) {
911
+ return false;
912
+ }
913
+ return crypto.timingSafeEqual(a, b);
914
+ }
915
+ function toBuffer(body) {
916
+ return typeof body === "string" ? Buffer.from(body, "utf8") : Buffer.from(body);
917
+ }
918
+ function getHeader(headers, name) {
919
+ if (typeof headers.get === "function") {
920
+ return headers.get(name);
921
+ }
922
+ const record = headers;
923
+ const direct = record[name];
924
+ const value = direct ?? findCaseInsensitive(record, name);
925
+ if (value === void 0) {
926
+ return null;
927
+ }
928
+ return Array.isArray(value) ? value[0] ?? null : value;
929
+ }
930
+ function findCaseInsensitive(record, name) {
931
+ const lower = name.toLowerCase();
932
+ for (const key of Object.keys(record)) {
933
+ if (key.toLowerCase() === lower) {
934
+ return record[key];
935
+ }
936
+ }
937
+ return void 0;
938
+ }
939
+
940
+ // src/client.ts
941
+ var DEFAULT_BASE_URL = "https://api.gradient-labs.ai";
942
+ var defaultFetch = (input, init) => fetch(input, init);
943
+ var GradientLabs = class {
944
+ // Integration role (publicapi)
945
+ conversations;
946
+ outboundConversations;
947
+ backOfficeTasks;
948
+ voice;
949
+ // Management role (publicmanagementapi)
950
+ tools;
951
+ articles;
952
+ topics;
953
+ procedures;
954
+ handOffTargets;
955
+ resourceSources;
956
+ resourceTypes;
957
+ secrets;
958
+ notes;
959
+ terminologySubstitutions;
960
+ trafficGroups;
961
+ ipAddresses;
962
+ webhookVerifier;
963
+ constructor(config) {
964
+ if (!config.apiKey) {
965
+ throw new ConfigurationError("apiKey is required");
966
+ }
967
+ const http = new HttpClient({
968
+ baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
969
+ apiKey: config.apiKey,
970
+ fetch: config.fetch ?? defaultFetch,
971
+ timeoutMs: config.timeoutMs
972
+ });
973
+ this.conversations = new Conversations(http);
974
+ this.outboundConversations = new OutboundConversations(http);
975
+ this.backOfficeTasks = new BackOfficeTasks(http);
976
+ this.voice = new Voice(http);
977
+ this.tools = new Tools(http);
978
+ this.articles = new Articles(http);
979
+ this.topics = new Topics(http);
980
+ this.procedures = new Procedures(http);
981
+ this.handOffTargets = new HandOffTargets(http);
982
+ this.resourceSources = new ResourceSources(http);
983
+ this.resourceTypes = new ResourceTypes(http);
984
+ this.secrets = new Secrets(http);
985
+ this.notes = new Notes(http);
986
+ this.terminologySubstitutions = new TerminologySubstitutions(http);
987
+ this.trafficGroups = new TrafficGroups(http);
988
+ this.ipAddresses = new IpAddressesResource(http);
989
+ if (config.webhookSigningKey) {
990
+ this.webhookVerifier = new WebhookVerifier({
991
+ signingKey: config.webhookSigningKey,
992
+ leewayMs: config.webhookLeewayMs
993
+ });
994
+ }
995
+ }
996
+ /**
997
+ * The webhook verifier. Throws {@link ConfigurationError} if the client was
998
+ * created without a `webhookSigningKey`.
999
+ */
1000
+ get webhooks() {
1001
+ if (!this.webhookVerifier) {
1002
+ throw new ConfigurationError(
1003
+ "webhookSigningKey is required to verify webhooks; pass it to the GradientLabs constructor"
1004
+ );
1005
+ }
1006
+ return this.webhookVerifier;
1007
+ }
1008
+ };
1009
+
1010
+ // src/models/enums.ts
1011
+ var ArticleStatus = {
1012
+ Draft: "draft",
1013
+ Published: "published",
1014
+ Deleted: "deleted",
1015
+ Excluded: "excluded",
1016
+ Unknown: "unknown"
1017
+ };
1018
+ var ArticleUsageStatus = {
1019
+ On: "on",
1020
+ Off: "off"
1021
+ };
1022
+ var ArticleVisibility = {
1023
+ Public: "public",
1024
+ Users: "users",
1025
+ Internal: "internal",
1026
+ Unknown: "unknown"
1027
+ };
1028
+ var AttachmentType = {
1029
+ Image: "image",
1030
+ File: "file"
1031
+ };
1032
+ var Channel = {
1033
+ Web: "web",
1034
+ Email: "email",
1035
+ Voice: "voice",
1036
+ Unmapped: "unmapped"
1037
+ };
1038
+ var CustomerSource = {
1039
+ Dixa: "dixa",
1040
+ Intercom: "intercom",
1041
+ Freshchat: "freshchat",
1042
+ Freshdesk: "freshdesk",
1043
+ PublicApi: "public-api",
1044
+ ChatSdk: "chat-sdk",
1045
+ Salesforce: "salesforce",
1046
+ Zendesk: "zendesk",
1047
+ Livekit: "livekit",
1048
+ Twilio: "twilio",
1049
+ Talkdesk: "talkdesk",
1050
+ IntercomVoice: "intercom-voice",
1051
+ Livechat: "livechat",
1052
+ WebApp: "web-app",
1053
+ Gmail: "gmail",
1054
+ File: "file"
1055
+ };
1056
+ var ParticipantType = {
1057
+ Customer: "Customer",
1058
+ Agent: "Agent",
1059
+ AIAgent: "AI Agent",
1060
+ Bot: "Bot"
1061
+ };
1062
+ var ConversationEventType = {
1063
+ Assigned: "assigned",
1064
+ Cancelled: "cancelled",
1065
+ Finished: "finished",
1066
+ Resumed: "resumed",
1067
+ InternalNote: "internal-note",
1068
+ Message: "message",
1069
+ Delivered: "delivered",
1070
+ Read: "read",
1071
+ Rated: "rated",
1072
+ Started: "started",
1073
+ Typing: "typing",
1074
+ AsyncToolResult: "async-tool-result"
1075
+ };
1076
+ var ProcedureStatus = {
1077
+ Unsaved: "unsaved",
1078
+ Draft: "draft",
1079
+ Live: "live",
1080
+ Archived: "archived"
1081
+ };
1082
+ var NoteStatus = {
1083
+ Draft: "draft",
1084
+ Live: "live",
1085
+ Deleted: "deleted"
1086
+ };
1087
+ var BackOfficeTaskStatus = {
1088
+ Pending: "pending",
1089
+ InProgress: "in-progress",
1090
+ Completed: "completed",
1091
+ Failed: "failed",
1092
+ HandedOff: "handed-off"
1093
+ };
1094
+ var BackOfficeTaskResultType = {
1095
+ Custom: "custom"
1096
+ };
1097
+ var AttributeCardinality = {
1098
+ One: "one",
1099
+ Many: "many"
1100
+ };
1101
+ var AttributeType = {
1102
+ String: "string",
1103
+ Date: "date",
1104
+ Timestamp: "timestamp",
1105
+ Boolean: "boolean",
1106
+ Number: "number",
1107
+ Array: "array",
1108
+ Complex: "complex"
1109
+ };
1110
+ var ResourceSourceRefreshStrategy = {
1111
+ Dynamic: "dynamic",
1112
+ Static: "static"
1113
+ };
1114
+ var ResourceSourceScope = {
1115
+ Global: "global",
1116
+ Local: "local"
1117
+ };
1118
+ var ResourceSourceType = {
1119
+ Http: "http",
1120
+ Internal: "internal",
1121
+ Webhook: "webhook"
1122
+ };
1123
+ var SchemaUpdateStrategy = {
1124
+ Replace: "replace",
1125
+ Merge: "merge"
1126
+ };
1127
+ var ResourceTypeRefreshStrategy = {
1128
+ Dynamic: "dynamic",
1129
+ Static: "static"
1130
+ };
1131
+ var ResourceTypeScope = {
1132
+ Global: "global",
1133
+ Local: "local"
1134
+ };
1135
+ var SupportPlatform = {
1136
+ Dixa: "dixa",
1137
+ Freshchat: "freshchat",
1138
+ Freshdesk: "freshdesk",
1139
+ Gmail: "gmail",
1140
+ Intercom: "intercom",
1141
+ Livechat: "livechat",
1142
+ PublicApi: "public-api",
1143
+ ChatSdk: "chat-sdk",
1144
+ Salesforce: "salesforce",
1145
+ Zendesk: "zendesk",
1146
+ Livekit: "livekit",
1147
+ Twilio: "twilio",
1148
+ Talkdesk: "talkdesk",
1149
+ IntercomVoice: "intercom-voice",
1150
+ ConversationSynthesizor: "conversation-synthesizor",
1151
+ WebApp: "web-app"
1152
+ };
1153
+ var BodyEncoding = {
1154
+ Json: "application/json",
1155
+ Form: "application/x-www-form-urlencoded"
1156
+ };
1157
+ var ParameterSource = {
1158
+ Llm: "llm",
1159
+ Literal: "literal",
1160
+ Resource: "resource"
1161
+ };
1162
+ var ParameterType = {
1163
+ String: "string",
1164
+ StringArray: "string_array",
1165
+ Integer: "integer",
1166
+ Float: "float",
1167
+ Boolean: "boolean",
1168
+ Date: "date",
1169
+ Timestamp: "timestamp",
1170
+ Duration: "duration"
1171
+ };
1172
+
1173
+ exports.ApiError = ApiError;
1174
+ exports.ArticleStatus = ArticleStatus;
1175
+ exports.ArticleUsageStatus = ArticleUsageStatus;
1176
+ exports.ArticleVisibility = ArticleVisibility;
1177
+ exports.Articles = Articles;
1178
+ exports.AttachmentType = AttachmentType;
1179
+ exports.AttributeCardinality = AttributeCardinality;
1180
+ exports.AttributeType = AttributeType;
1181
+ exports.BackOfficeTaskResultType = BackOfficeTaskResultType;
1182
+ exports.BackOfficeTaskStatus = BackOfficeTaskStatus;
1183
+ exports.BackOfficeTasks = BackOfficeTasks;
1184
+ exports.BodyEncoding = BodyEncoding;
1185
+ exports.Channel = Channel;
1186
+ exports.ConfigurationError = ConfigurationError;
1187
+ exports.ConversationEventType = ConversationEventType;
1188
+ exports.Conversations = Conversations;
1189
+ exports.CustomerSource = CustomerSource;
1190
+ exports.ErrorCode = ErrorCode;
1191
+ exports.GradientLabs = GradientLabs;
1192
+ exports.GradientLabsError = GradientLabsError;
1193
+ exports.HandOffTargets = HandOffTargets;
1194
+ exports.InvalidWebhookSignatureError = InvalidWebhookSignatureError;
1195
+ exports.IpAddressesResource = IpAddressesResource;
1196
+ exports.NoteStatus = NoteStatus;
1197
+ exports.Notes = Notes;
1198
+ exports.OutboundConversations = OutboundConversations;
1199
+ exports.ParameterSource = ParameterSource;
1200
+ exports.ParameterType = ParameterType;
1201
+ exports.ParticipantType = ParticipantType;
1202
+ exports.ProcedureStatus = ProcedureStatus;
1203
+ exports.Procedures = Procedures;
1204
+ exports.ResourceSourceRefreshStrategy = ResourceSourceRefreshStrategy;
1205
+ exports.ResourceSourceScope = ResourceSourceScope;
1206
+ exports.ResourceSourceType = ResourceSourceType;
1207
+ exports.ResourceSources = ResourceSources;
1208
+ exports.ResourceTypeRefreshStrategy = ResourceTypeRefreshStrategy;
1209
+ exports.ResourceTypeScope = ResourceTypeScope;
1210
+ exports.ResourceTypes = ResourceTypes;
1211
+ exports.SchemaUpdateStrategy = SchemaUpdateStrategy;
1212
+ exports.Secrets = Secrets;
1213
+ exports.SupportPlatform = SupportPlatform;
1214
+ exports.TerminologySubstitutions = TerminologySubstitutions;
1215
+ exports.Tools = Tools;
1216
+ exports.Topics = Topics;
1217
+ exports.TrafficGroups = TrafficGroups;
1218
+ exports.UnknownWebhookTypeError = UnknownWebhookTypeError;
1219
+ exports.Voice = Voice;
1220
+ exports.WebhookType = WebhookType;
1221
+ exports.WebhookVerifier = WebhookVerifier;
1222
+ //# sourceMappingURL=index.cjs.map
1223
+ //# sourceMappingURL=index.cjs.map