@dialgem/sdk 0.1.0-beta.0 → 0.1.0-beta.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.
- package/CHANGELOG.md +20 -0
- package/README.md +96 -16
- package/dist/index.cjs +246 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +581 -77
- package/dist/index.d.ts +581 -77
- package/dist/index.js +244 -53
- package/dist/index.js.map +1 -1
- package/examples/export-calls.ts +11 -14
- package/examples/webhook-express.ts +13 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -104,7 +104,7 @@ function isErrorBody(body) {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
// src/version.ts
|
|
107
|
-
var VERSION = "0.1.0-beta.
|
|
107
|
+
var VERSION = "0.1.0-beta.1";
|
|
108
108
|
|
|
109
109
|
// src/core/http.ts
|
|
110
110
|
var RETRYABLE_METHODS = /* @__PURE__ */ new Set(["GET", "PATCH", "DELETE"]);
|
|
@@ -130,6 +130,16 @@ var HttpClient = class {
|
|
|
130
130
|
post(path2, body, options) {
|
|
131
131
|
return this.request("POST", path2, { body, options });
|
|
132
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* POST a `FormData` body — file uploads.
|
|
135
|
+
*
|
|
136
|
+
* The body is sent as-is and `Content-Type` is left unset, because only
|
|
137
|
+
* `fetch` knows the multipart boundary it is about to generate. Setting the
|
|
138
|
+
* header ourselves produces a request no server can parse.
|
|
139
|
+
*/
|
|
140
|
+
postForm(path2, form, options) {
|
|
141
|
+
return this.request("POST", path2, { body: form, options });
|
|
142
|
+
}
|
|
133
143
|
patch(path2, body, options) {
|
|
134
144
|
return this.request("PATCH", path2, { body, options });
|
|
135
145
|
}
|
|
@@ -138,10 +148,11 @@ var HttpClient = class {
|
|
|
138
148
|
}
|
|
139
149
|
async request(method, path2, { query, body, options = {} }) {
|
|
140
150
|
const url = this.buildURL(path2, query);
|
|
141
|
-
const
|
|
142
|
-
const
|
|
151
|
+
const isForm = isFormData(body);
|
|
152
|
+
const headers = this.buildHeaders(body !== void 0 && !isForm, options.headers);
|
|
153
|
+
const payload = body === void 0 ? void 0 : isForm ? body : JSON.stringify(body);
|
|
143
154
|
const timeout = options.timeout ?? this.#timeout;
|
|
144
|
-
const maxRetries = options.maxRetries ?? (RETRYABLE_METHODS.has(method) ? this.#maxRetries : 0);
|
|
155
|
+
const maxRetries = isForm ? 0 : options.maxRetries ?? (RETRYABLE_METHODS.has(method) ? this.#maxRetries : 0);
|
|
145
156
|
assertTimeout(timeout);
|
|
146
157
|
assertMaxRetries(maxRetries);
|
|
147
158
|
for (let attempt = 0; ; attempt++) {
|
|
@@ -195,7 +206,7 @@ var HttpClient = class {
|
|
|
195
206
|
const params = new URLSearchParams();
|
|
196
207
|
for (const [key, value] of Object.entries(query)) {
|
|
197
208
|
if (value === void 0 || value === null) continue;
|
|
198
|
-
params.append(key, String(
|
|
209
|
+
for (const item of Array.isArray(value) ? value : [value]) params.append(key, String(item));
|
|
199
210
|
}
|
|
200
211
|
const qs = params.toString();
|
|
201
212
|
return qs ? `${url}?${qs}` : url;
|
|
@@ -218,6 +229,9 @@ var HttpClient = class {
|
|
|
218
229
|
return Object.fromEntries(merged.values());
|
|
219
230
|
}
|
|
220
231
|
};
|
|
232
|
+
function isFormData(value) {
|
|
233
|
+
return typeof FormData !== "undefined" && value instanceof FormData;
|
|
234
|
+
}
|
|
221
235
|
function assertTimeout(value) {
|
|
222
236
|
if (!Number.isInteger(value) || value <= 0) {
|
|
223
237
|
throw new DialgemError(`\`timeout\` must be a positive integer of milliseconds, got ${String(value)}.`);
|
|
@@ -314,11 +328,14 @@ var Agents = class extends APIResource {
|
|
|
314
328
|
knowledge;
|
|
315
329
|
/** Remote MCP servers whose tools are exposed to the agent. */
|
|
316
330
|
mcpServers;
|
|
331
|
+
/** Frozen snapshots of the agent that a number or a call can pin. */
|
|
332
|
+
versions;
|
|
317
333
|
constructor(client) {
|
|
318
334
|
super(client);
|
|
319
335
|
this.functions = new AgentFunctions(client);
|
|
320
336
|
this.knowledge = new AgentKnowledge(client);
|
|
321
337
|
this.mcpServers = new AgentMCPServers(client);
|
|
338
|
+
this.versions = new AgentVersions(client);
|
|
322
339
|
}
|
|
323
340
|
/** Create an agent. Only `name` is required; everything else has a server default. */
|
|
324
341
|
create(body, options) {
|
|
@@ -339,6 +356,48 @@ var Agents = class extends APIResource {
|
|
|
339
356
|
return this._client.delete(path`/v1/agents/${agentId}`, options);
|
|
340
357
|
}
|
|
341
358
|
};
|
|
359
|
+
var AgentVersions = class extends APIResource {
|
|
360
|
+
/** Freeze the agent as it is now. Returns the new version, snapshot included. */
|
|
361
|
+
publish(agentId, body = {}, options) {
|
|
362
|
+
return this._client.post(path`/v1/agents/${agentId}/versions`, body, options);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* One page of published versions, newest first, without their snapshots.
|
|
366
|
+
*
|
|
367
|
+
* Returns the array. When you need to page — an agent published on every
|
|
368
|
+
* deploy accumulates versions, and nothing prunes them — read `has_more` from
|
|
369
|
+
* {@link listPage} instead and pass the last `version` as `before_version`.
|
|
370
|
+
*/
|
|
371
|
+
async list(agentId, params, options) {
|
|
372
|
+
return (await this.listPage(agentId, params, options)).versions;
|
|
373
|
+
}
|
|
374
|
+
/** {@link list} with the `has_more` flag, for paging. */
|
|
375
|
+
listPage(agentId, params, options) {
|
|
376
|
+
return this._client.get(
|
|
377
|
+
path`/v1/agents/${agentId}/versions`,
|
|
378
|
+
// Spread into a plain query record: an `interface` has no index
|
|
379
|
+
// signature, so it does not structurally satisfy `Query`.
|
|
380
|
+
{ ...params },
|
|
381
|
+
options
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
/** One version with its full snapshot. Version 0 is the draft: use `agents.retrieve`. */
|
|
385
|
+
retrieve(agentId, version, options) {
|
|
386
|
+
return this._client.get(
|
|
387
|
+
path`/v1/agents/${agentId}/versions/${versionSegment(version)}`,
|
|
388
|
+
void 0,
|
|
389
|
+
options
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
function versionSegment(version) {
|
|
394
|
+
if (!Number.isInteger(version) || version < 1) {
|
|
395
|
+
throw new DialgemError(
|
|
396
|
+
`Expected a published version number (a positive integer), got ${JSON.stringify(version)}. Version 0 is the draft \u2014 read it with agents.retrieve().`
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
return String(version);
|
|
400
|
+
}
|
|
342
401
|
var AgentFunctions = class extends APIResource {
|
|
343
402
|
list(agentId, options) {
|
|
344
403
|
return this._client.get(path`/v1/agents/${agentId}/functions`, void 0, options);
|
|
@@ -391,35 +450,33 @@ var AgentMCPServers = class extends APIResource {
|
|
|
391
450
|
// src/core/pagination.ts
|
|
392
451
|
var Page = class _Page {
|
|
393
452
|
data;
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
page_size;
|
|
453
|
+
has_more;
|
|
454
|
+
pagination_key;
|
|
397
455
|
#fetchPage;
|
|
398
456
|
constructor(data, fetchPage) {
|
|
399
457
|
this.data = data.data;
|
|
400
|
-
this.
|
|
401
|
-
this.
|
|
402
|
-
this.page_size = data.page_size;
|
|
458
|
+
this.has_more = data.has_more;
|
|
459
|
+
this.pagination_key = data.pagination_key;
|
|
403
460
|
this.#fetchPage = fetchPage;
|
|
404
461
|
}
|
|
405
462
|
hasNextPage() {
|
|
406
|
-
return this.
|
|
463
|
+
return this.has_more && this.pagination_key !== null;
|
|
407
464
|
}
|
|
408
465
|
async getNextPage() {
|
|
409
466
|
if (!this.hasNextPage()) throw new DialgemError("No next page; check hasNextPage() first.");
|
|
410
|
-
return new _Page(await this.#fetchPage(this.
|
|
467
|
+
return new _Page(await this.#fetchPage(this.pagination_key), this.#fetchPage);
|
|
411
468
|
}
|
|
412
469
|
};
|
|
413
470
|
var PagePromise = class {
|
|
414
471
|
#fetchPage;
|
|
415
|
-
#
|
|
472
|
+
#startKey;
|
|
416
473
|
#first;
|
|
417
|
-
constructor(fetchPage,
|
|
474
|
+
constructor(fetchPage, startKey = null) {
|
|
418
475
|
this.#fetchPage = fetchPage;
|
|
419
|
-
this.#
|
|
476
|
+
this.#startKey = startKey;
|
|
420
477
|
}
|
|
421
478
|
#firstPage() {
|
|
422
|
-
this.#first ??= this.#fetchPage(this.#
|
|
479
|
+
this.#first ??= this.#fetchPage(this.#startKey).then((data) => new Page(data, this.#fetchPage));
|
|
423
480
|
return this.#first;
|
|
424
481
|
}
|
|
425
482
|
then(onfulfilled, onrejected) {
|
|
@@ -444,24 +501,50 @@ var PagePromise = class {
|
|
|
444
501
|
// src/resources/calls.ts
|
|
445
502
|
var Calls = class extends APIResource {
|
|
446
503
|
/**
|
|
447
|
-
* Calls, newest first. Await for one page, or iterate for every call:
|
|
504
|
+
* Calls, newest first by default. Await for one page, or iterate for every call:
|
|
448
505
|
*
|
|
449
|
-
* const page = await dialgem.calls.list({
|
|
450
|
-
* for await (const call of dialgem.calls.list({ status: "completed" })) {
|
|
451
|
-
* if (call.started_at < cutoff) break // newest first: everything after is older
|
|
452
|
-
* }
|
|
506
|
+
* const page = await dialgem.calls.list({ limit: 50 })
|
|
507
|
+
* for await (const call of dialgem.calls.list({ status: "completed", start_after: since })) { ... }
|
|
453
508
|
*/
|
|
454
509
|
list(params = {}, options) {
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
510
|
+
const query = toQuery(params);
|
|
511
|
+
const fetchPage = async (paginationKey) => {
|
|
512
|
+
const res = await this._client.get(
|
|
513
|
+
"/v1/calls",
|
|
514
|
+
{ ...query, pagination_key: paginationKey ?? void 0 },
|
|
515
|
+
options
|
|
516
|
+
);
|
|
517
|
+
return { data: res.calls, has_more: res.has_more, pagination_key: res.pagination_key };
|
|
458
518
|
};
|
|
459
|
-
return new PagePromise(fetchPage
|
|
519
|
+
return new PagePromise(fetchPage);
|
|
460
520
|
}
|
|
461
|
-
/** One call, including its transcript, analysis and recording URL. */
|
|
521
|
+
/** One call, including its transcript, analysis, latency and recording URL. */
|
|
462
522
|
retrieve(callId, options) {
|
|
463
523
|
return this._client.get(path`/v1/calls/${callId}`, void 0, options);
|
|
464
524
|
}
|
|
525
|
+
/** Replace the call's `metadata`. */
|
|
526
|
+
update(callId, body, options) {
|
|
527
|
+
return this._client.patch(path`/v1/calls/${callId}`, body, options);
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Permanently delete a finished call: its record, transcript, analysis and
|
|
531
|
+
* recording. A call still in progress is refused with `ConflictError`; stop it first.
|
|
532
|
+
*/
|
|
533
|
+
delete(callId, options) {
|
|
534
|
+
return this._client.delete(path`/v1/calls/${callId}`, options);
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* End an ongoing call now, as if the agent had hung up. The call becomes
|
|
538
|
+
* `completed` with `disconnection_reason: "manual_stopped"` a moment later, and
|
|
539
|
+
* the usual `call_ended` webhook follows.
|
|
540
|
+
*
|
|
541
|
+
* `ConflictError` with `errCode` `call_not_ongoing` if it already ended, or
|
|
542
|
+
* `call_not_connected` if no agent is on the call yet (e.g. still ringing).
|
|
543
|
+
* Not retried by default.
|
|
544
|
+
*/
|
|
545
|
+
stop(callId, options) {
|
|
546
|
+
return this._client.post(path`/v1/calls/${callId}/stop`, void 0, options);
|
|
547
|
+
}
|
|
465
548
|
/**
|
|
466
549
|
* Dial `to` from one of your organization's numbers, with `agent_id` (or the
|
|
467
550
|
* number's outbound agent) on the line.
|
|
@@ -481,13 +564,70 @@ var Calls = class extends APIResource {
|
|
|
481
564
|
return this._client.post("/v1/calls/register", body, options);
|
|
482
565
|
}
|
|
483
566
|
};
|
|
567
|
+
function toQuery(params) {
|
|
568
|
+
const { metadata, ...rest } = params;
|
|
569
|
+
const query = { ...rest };
|
|
570
|
+
query["limit"] = params.limit ?? 10;
|
|
571
|
+
for (const [key, value] of Object.entries(metadata ?? {})) {
|
|
572
|
+
query[`metadata.${key}`] = String(value);
|
|
573
|
+
}
|
|
574
|
+
return query;
|
|
575
|
+
}
|
|
484
576
|
|
|
485
577
|
// src/resources/catalog.ts
|
|
486
578
|
var Voices = class extends APIResource {
|
|
487
|
-
/**
|
|
579
|
+
/**
|
|
580
|
+
* Voices available to agents: the shared catalog plus the ones your
|
|
581
|
+
* organization cloned, yours first. Put a voice's `provider_voice_id` in an
|
|
582
|
+
* agent's `voice_id`.
|
|
583
|
+
*/
|
|
488
584
|
list(params = {}, options) {
|
|
489
585
|
return this._client.get("/v1/voices", params, options);
|
|
490
586
|
}
|
|
587
|
+
/**
|
|
588
|
+
* Clone a voice from audio you upload. The new voice is private to your
|
|
589
|
+
* organization and never appears in another one's catalog.
|
|
590
|
+
*
|
|
591
|
+
* Consent is required: you are asserting that you hold the rights to the
|
|
592
|
+
* audio and have the speaker's consent, and that assertion is recorded
|
|
593
|
+
* against your API identity.
|
|
594
|
+
*
|
|
595
|
+
* The upload is never retried, whatever `maxRetries` says — a retried
|
|
596
|
+
* multipart body can send truncated audio, and a clone built from half the
|
|
597
|
+
* recording succeeds and sounds wrong.
|
|
598
|
+
*/
|
|
599
|
+
clone(params, options) {
|
|
600
|
+
const { name, files, consent_confirmed, engine, description, language, filenames } = params;
|
|
601
|
+
if (!consent_confirmed) {
|
|
602
|
+
throw new DialgemError(
|
|
603
|
+
"consent_confirmed must be true: you are asserting that you hold the rights to this audio and have the speaker's consent to clone their voice."
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
if (!files?.length) {
|
|
607
|
+
throw new DialgemError("At least one audio file is required to clone a voice.");
|
|
608
|
+
}
|
|
609
|
+
const form = new FormData();
|
|
610
|
+
form.append("name", name);
|
|
611
|
+
form.append("consent_confirmed", "true");
|
|
612
|
+
if (engine) form.append("engine", engine);
|
|
613
|
+
if (description) form.append("description", description);
|
|
614
|
+
if (language) form.append("language", language);
|
|
615
|
+
files.forEach((file, i) => {
|
|
616
|
+
const fallback = file.name || `clip-${i + 1}.wav`;
|
|
617
|
+
form.append("files", file, filenames?.[i] ?? fallback);
|
|
618
|
+
});
|
|
619
|
+
return this._client.postForm("/v1/voices/clone", form, options);
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Delete a voice your organization cloned, at the provider and here.
|
|
623
|
+
*
|
|
624
|
+
* Only your own cloned voices: the shared catalog is not deletable, and a
|
|
625
|
+
* voice an agent still uses is refused with a 409 rather than leaving that
|
|
626
|
+
* agent without one.
|
|
627
|
+
*/
|
|
628
|
+
delete(voiceId, options) {
|
|
629
|
+
return this._client.delete(path`/v1/voices/${voiceId}`, options);
|
|
630
|
+
}
|
|
491
631
|
};
|
|
492
632
|
var FlowTemplates = class extends APIResource {
|
|
493
633
|
/** Built-in conversation-flow templates (summaries, without `flow_config`). */
|
|
@@ -518,6 +658,20 @@ var PhoneNumbers = class extends APIResource {
|
|
|
518
658
|
list(options) {
|
|
519
659
|
return this._client.get("/v1/phone-numbers", void 0, options);
|
|
520
660
|
}
|
|
661
|
+
/**
|
|
662
|
+
* One number by its E.164 value, e.g. `+14155550123`.
|
|
663
|
+
*
|
|
664
|
+
* Keyed on the number rather than on `id`, because the number is what you
|
|
665
|
+
* have when you are asking whether it is registered at all. Throws
|
|
666
|
+
* `NotFoundError` when it is not.
|
|
667
|
+
*/
|
|
668
|
+
retrieve(phoneNumber, options) {
|
|
669
|
+
return this._client.get(
|
|
670
|
+
path`/v1/phone-numbers/by-number/${phoneNumber}`,
|
|
671
|
+
void 0,
|
|
672
|
+
options
|
|
673
|
+
);
|
|
674
|
+
}
|
|
521
675
|
/**
|
|
522
676
|
* Partial update.
|
|
523
677
|
*
|
|
@@ -542,52 +696,84 @@ var PhoneNumbers = class extends APIResource {
|
|
|
542
696
|
// src/webhooks.ts
|
|
543
697
|
var WEBHOOK_SIGNATURE_HEADER = "x-dialgem-signature";
|
|
544
698
|
var WEBHOOK_EVENT_HEADER = "x-dialgem-event";
|
|
699
|
+
var WEBHOOK_DELIVERY_HEADER = "x-dialgem-delivery";
|
|
700
|
+
var DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1e3;
|
|
545
701
|
var encoder = new TextEncoder();
|
|
546
702
|
var decoder = new TextDecoder();
|
|
703
|
+
var SIGNATURE_RE = /^v=(\d{10,16}),d=([0-9a-f]{64})$/;
|
|
547
704
|
var Webhooks = class {
|
|
548
705
|
/**
|
|
549
|
-
* Returns whether `signature` is
|
|
550
|
-
* Constant-time. Returns `false` for a missing
|
|
551
|
-
* if `secret` is empty, which is a configuration
|
|
706
|
+
* Returns whether `signature` is a current, valid signature of `payload` under
|
|
707
|
+
* `secret`. Constant-time. Returns `false` for a missing, malformed, tampered or
|
|
708
|
+
* stale signature; throws only if `secret` is empty, which is a configuration
|
|
709
|
+
* error rather than a bad request.
|
|
552
710
|
*/
|
|
553
|
-
async verify(payload, signature, secret) {
|
|
711
|
+
async verify(payload, signature, secret, options = {}) {
|
|
554
712
|
if (!secret) {
|
|
555
713
|
throw new DialgemError(
|
|
556
714
|
"Webhook secret is empty. Set the agent's `webhook_signing_secret` and pass the same value here."
|
|
557
715
|
);
|
|
558
716
|
}
|
|
559
|
-
const
|
|
560
|
-
if (!
|
|
561
|
-
const
|
|
717
|
+
const match = SIGNATURE_RE.exec(firstHeader(signature)?.trim().toLowerCase() ?? "");
|
|
718
|
+
if (!match) return false;
|
|
719
|
+
const [, timestamp, received] = match;
|
|
720
|
+
const now = options.now ?? Date.now();
|
|
721
|
+
if (Math.abs(now - Number(timestamp)) > (options.toleranceMs ?? DEFAULT_SIGNATURE_TOLERANCE_MS)) {
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
const body = toBytes(payload);
|
|
725
|
+
const message = new Uint8Array(body.length + timestamp.length);
|
|
726
|
+
message.set(body, 0);
|
|
727
|
+
message.set(encoder.encode(timestamp), body.length);
|
|
728
|
+
const expected = await hmacSha256Hex(secret, message);
|
|
562
729
|
return timingSafeEqual(expected, received);
|
|
563
730
|
}
|
|
564
731
|
/**
|
|
565
|
-
* Verifies
|
|
732
|
+
* Verifies a webhook's signature, then parses its body.
|
|
566
733
|
*
|
|
567
|
-
* @throws WebhookVerificationError if the signature is missing or
|
|
734
|
+
* @throws WebhookVerificationError if the signature is missing, invalid or stale.
|
|
568
735
|
*/
|
|
569
|
-
async constructEvent(payload, signature, secret) {
|
|
736
|
+
async constructEvent(payload, signature, secret, options = {}) {
|
|
737
|
+
const parsed = await this.#verifiedJson(payload, signature, secret, options);
|
|
738
|
+
if (typeof parsed !== "object" || parsed === null || typeof parsed.event !== "string") {
|
|
739
|
+
throw new WebhookVerificationError("Webhook body has no `event` field.");
|
|
740
|
+
}
|
|
741
|
+
return parsed;
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Verifies a request Dialgem made to one of your custom functions, then parses
|
|
745
|
+
* its body. For functions with `args_at_root`, the body is the arguments object
|
|
746
|
+
* alone; use `verify` and parse it yourself.
|
|
747
|
+
*
|
|
748
|
+
* @throws WebhookVerificationError if the signature is missing, invalid or stale.
|
|
749
|
+
*/
|
|
750
|
+
async constructFunctionCall(payload, signature, secret, options = {}) {
|
|
751
|
+
const parsed = await this.#verifiedJson(payload, signature, secret, options);
|
|
752
|
+
const body = parsed;
|
|
753
|
+
if (!body || typeof body.name !== "string" || typeof body.call !== "object" || body.call === null) {
|
|
754
|
+
throw new WebhookVerificationError(
|
|
755
|
+
"Function request body has no `name` and `call`. Does this function have args_at_root set?"
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
return body;
|
|
759
|
+
}
|
|
760
|
+
async #verifiedJson(payload, signature, secret, options) {
|
|
570
761
|
if (!firstHeader(signature)) {
|
|
571
762
|
throw new WebhookVerificationError(
|
|
572
763
|
`Missing ${WEBHOOK_SIGNATURE_HEADER} header. Is a webhook_signing_secret set on the agent?`
|
|
573
764
|
);
|
|
574
765
|
}
|
|
575
|
-
if (!await this.verify(payload, signature, secret)) {
|
|
766
|
+
if (!await this.verify(payload, signature, secret, options)) {
|
|
576
767
|
throw new WebhookVerificationError(
|
|
577
|
-
"
|
|
768
|
+
"Signature is invalid or older than the allowed tolerance. Check the secret, the server clock, and that the body was not re-serialized before verification."
|
|
578
769
|
);
|
|
579
770
|
}
|
|
580
771
|
const text = typeof payload === "string" ? payload : decoder.decode(toBytes(payload));
|
|
581
|
-
let parsed;
|
|
582
772
|
try {
|
|
583
|
-
|
|
773
|
+
return JSON.parse(text);
|
|
584
774
|
} catch {
|
|
585
|
-
throw new WebhookVerificationError("
|
|
775
|
+
throw new WebhookVerificationError("Body is signed but is not valid JSON.");
|
|
586
776
|
}
|
|
587
|
-
if (typeof parsed !== "object" || parsed === null || typeof parsed.event !== "string") {
|
|
588
|
-
throw new WebhookVerificationError("Webhook body has no `event` field.");
|
|
589
|
-
}
|
|
590
|
-
return parsed;
|
|
591
777
|
}
|
|
592
778
|
};
|
|
593
779
|
var webhooks = new Webhooks();
|
|
@@ -617,11 +803,11 @@ function timingSafeEqual(a, b) {
|
|
|
617
803
|
}
|
|
618
804
|
|
|
619
805
|
// src/client.ts
|
|
620
|
-
var
|
|
806
|
+
var BASE_URL = "https://api.dialgem.com";
|
|
621
807
|
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
622
808
|
var DEFAULT_MAX_RETRIES = 2;
|
|
623
809
|
var Dialgem = class {
|
|
624
|
-
static
|
|
810
|
+
static BASE_URL = BASE_URL;
|
|
625
811
|
/** Webhook verification without a client instance: `Dialgem.webhooks.constructEvent(...)`. */
|
|
626
812
|
static webhooks = webhooks;
|
|
627
813
|
agents;
|
|
@@ -631,8 +817,14 @@ var Dialgem = class {
|
|
|
631
817
|
flowTemplates;
|
|
632
818
|
promptTemplates;
|
|
633
819
|
webhooks = webhooks;
|
|
634
|
-
|
|
820
|
+
/** Always `https://api.dialgem.com`. */
|
|
821
|
+
baseURL = BASE_URL;
|
|
635
822
|
constructor(options = {}) {
|
|
823
|
+
if ("baseURL" in options) {
|
|
824
|
+
throw new DialgemError(
|
|
825
|
+
"`baseURL` is not an option: the SDK always talks to https://api.dialgem.com. Remove it."
|
|
826
|
+
);
|
|
827
|
+
}
|
|
636
828
|
if (isBrowser() && !options.dangerouslyAllowBrowser) {
|
|
637
829
|
throw new DialgemError(
|
|
638
830
|
"The Dialgem SDK is for server-side use: running it in a browser exposes your API key to every visitor. Call Dialgem from your backend instead, or pass `dangerouslyAllowBrowser: true` if you understand the risk."
|
|
@@ -649,10 +841,9 @@ var Dialgem = class {
|
|
|
649
841
|
assertTimeout(timeout);
|
|
650
842
|
assertMaxRetries(maxRetries);
|
|
651
843
|
const fetchImpl = options.fetch ?? defaultFetch();
|
|
652
|
-
this.baseURL = (options.baseURL ?? readEnv("DIALGEM_BASE_URL") ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
653
844
|
const http = new HttpClient({
|
|
654
845
|
apiKey,
|
|
655
|
-
baseURL:
|
|
846
|
+
baseURL: BASE_URL,
|
|
656
847
|
timeout,
|
|
657
848
|
maxRetries,
|
|
658
849
|
fetch: fetchImpl,
|
|
@@ -683,6 +874,6 @@ function defaultFetch() {
|
|
|
683
874
|
return (url, init) => f.call(globalThis, url, init);
|
|
684
875
|
}
|
|
685
876
|
|
|
686
|
-
export { APIConnectionError, APIConnectionTimeoutError, APIError, APIUserAbortError, AuthenticationError, BadRequestError, ConflictError,
|
|
877
|
+
export { APIConnectionError, APIConnectionTimeoutError, APIError, APIUserAbortError, AuthenticationError, BASE_URL, BadRequestError, ConflictError, DEFAULT_SIGNATURE_TOLERANCE_MS, Dialgem, DialgemError, InternalServerError, NotFoundError, Page, PagePromise, PermissionDeniedError, RateLimitError, UnprocessableEntityError, VERSION, WEBHOOK_DELIVERY_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_SIGNATURE_HEADER, WebhookVerificationError, Webhooks, webhooks };
|
|
687
878
|
//# sourceMappingURL=index.js.map
|
|
688
879
|
//# sourceMappingURL=index.js.map
|