@cognidesk/http 0.0.3-dev.3 → 0.0.3-dev.6

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.js CHANGED
@@ -1,3 +1,6 @@
1
+ // src/handler/index.ts
2
+ import { defineChannelContext as defineChannelContext3 } from "@cognidesk/core";
3
+
1
4
  // src/responses.ts
2
5
  var HttpInputError = class extends Error {
3
6
  status = 400;
@@ -25,14 +28,75 @@ function emptyResponse(status, options) {
25
28
  });
26
29
  }
27
30
  function withCors(headers, options) {
28
- if (!options.cors) return headers;
31
+ const corsHeaders = getCorsHeaders(options);
32
+ if (Object.keys(corsHeaders).length === 0) return headers;
33
+ return mergeHeaderRecords(headers, corsHeaders);
34
+ }
35
+ function responseWithCors(response, options) {
36
+ const corsHeaders = getCorsHeaders(options);
37
+ if (Object.keys(corsHeaders).length === 0) return response;
38
+ const headers = new Headers(response.headers);
39
+ for (const [key, value] of Object.entries(corsHeaders)) {
40
+ if (key === "vary") {
41
+ headers.set("vary", mergeVary(headers.get("vary"), value));
42
+ } else if (!headers.has(key)) {
43
+ headers.set(key, value);
44
+ }
45
+ }
46
+ return new Response(response.body, {
47
+ status: response.status,
48
+ statusText: response.statusText,
49
+ headers
50
+ });
51
+ }
52
+ function getCorsHeaders(options) {
53
+ const cors = options.cors;
54
+ if (!cors) return {};
55
+ if (cors === true) {
56
+ return {
57
+ "access-control-allow-origin": "*",
58
+ "access-control-allow-methods": "GET,POST,OPTIONS",
59
+ "access-control-allow-headers": "content-type,authorization"
60
+ };
61
+ }
62
+ const origin = options.request?.headers.get("origin");
63
+ if (!origin || !isAllowedOrigin(cors, origin)) return {};
29
64
  return {
30
- ...headers,
31
- "access-control-allow-origin": "*",
32
- "access-control-allow-methods": "GET,POST,OPTIONS",
33
- "access-control-allow-headers": "content-type,authorization"
65
+ "access-control-allow-origin": origin,
66
+ "access-control-allow-methods": formatHeaderList(cors.methods, "GET,POST,OPTIONS"),
67
+ "access-control-allow-headers": formatHeaderList(cors.allowedHeaders, "content-type,authorization"),
68
+ ...cors.exposedHeaders ? { "access-control-expose-headers": formatHeaderList(cors.exposedHeaders, "") } : {},
69
+ ...cors.credentials ? { "access-control-allow-credentials": "true" } : {},
70
+ ...cors.maxAgeSeconds !== void 0 ? { "access-control-max-age": String(cors.maxAgeSeconds) } : {},
71
+ vary: "Origin"
34
72
  };
35
73
  }
74
+ function isAllowedOrigin(cors, origin) {
75
+ const origins = Array.isArray(cors.origins) ? cors.origins : [cors.origins];
76
+ return origins.includes(origin);
77
+ }
78
+ function formatHeaderList(value, fallback) {
79
+ if (value === void 0) return fallback;
80
+ return typeof value === "string" ? value : value.join(",");
81
+ }
82
+ function mergeHeaderRecords(headers, corsHeaders) {
83
+ const merged = { ...headers };
84
+ for (const [key, value] of Object.entries(corsHeaders)) {
85
+ if (key === "vary") {
86
+ merged.vary = mergeVary(merged.vary, value);
87
+ } else if (merged[key] === void 0) {
88
+ merged[key] = value;
89
+ }
90
+ }
91
+ return merged;
92
+ }
93
+ function mergeVary(existing, value) {
94
+ if (!existing) return value;
95
+ const existingValues = existing.split(",").map((entry) => entry.trim()).filter(Boolean);
96
+ const normalizedValue = value.toLowerCase();
97
+ if (existingValues.some((entry) => entry.toLowerCase() === normalizedValue)) return existing;
98
+ return `${existing}, ${value}`;
99
+ }
36
100
 
37
101
  // src/path.ts
38
102
  function normalizeBasePath(basePath) {
@@ -119,36 +183,617 @@ function formatSseError(error) {
119
183
  ].join("\n");
120
184
  }
121
185
 
122
- // src/handler.ts
186
+ // src/handler/auth.ts
187
+ async function authorizeRequest(options, input, responseOptions) {
188
+ if (!options.authorize) return void 0;
189
+ const result = await options.authorize(input);
190
+ if (result === true) return void 0;
191
+ if (result instanceof Response) return responseWithCors(result, responseOptions);
192
+ return json({ error: "Unauthorized" }, 401, responseOptions);
193
+ }
194
+
195
+ // src/handler/channel-events.ts
196
+ import {
197
+ defineChannelContext as defineChannelContext2,
198
+ defineChannelEvent
199
+ } from "@cognidesk/core";
200
+
201
+ // src/channel-events.ts
202
+ function createChannelEventInput(input) {
203
+ if (!isRecord(input)) throw new Error("Channel Event input must be an object.");
204
+ const eventRecord = isRecord(input.event) ? input.event : void 0;
205
+ const sourceRecord = eventRecord ?? input;
206
+ const kind = stringValue(sourceRecord.kind ?? sourceRecord.nature) ?? inferKind(sourceRecord, input);
207
+ if (!kind) throw new Error("Channel Event kind or nature is required.");
208
+ const direction = stringValue(sourceRecord.direction ?? input.direction) ?? inferDirection(kind);
209
+ const channel = sourceRecord.channel ?? input.channel;
210
+ if (channel === void 0) throw new Error("Channel Event channel is required.");
211
+ const text = firstText(sourceRecord, input);
212
+ const turn = firstDefined(sourceRecord.turn, input.turn);
213
+ const payload = buildPayload(sourceRecord, input, text, turn);
214
+ const source = buildSource(sourceRecord, input, inferSourceType(kind));
215
+ const identity = buildIdentity(sourceRecord, input);
216
+ const actor = normalizeActor(firstDefined(sourceRecord.actor, input.actor)) ?? inferActor(kind, direction);
217
+ const handling = buildHandling(input, text, turn);
218
+ const event = compact({
219
+ ...passthroughEventFields(eventRecord),
220
+ id: stringValue(sourceRecord.id ?? input.id),
221
+ channel,
222
+ kind,
223
+ nature: stringValue(sourceRecord.nature ?? input.nature) ?? kind,
224
+ direction,
225
+ intent: stringValue(sourceRecord.intent ?? input.intent) ?? inferIntent(kind, direction),
226
+ actor,
227
+ occurredAt: stringValue(sourceRecord.occurredAt ?? input.occurredAt),
228
+ payload,
229
+ identity,
230
+ source,
231
+ metadata: recordValue(sourceRecord.metadata ?? input.metadata)
232
+ });
233
+ return compact({
234
+ event,
235
+ conversationId: stringValue(input.conversationId ?? sourceRecord.conversationId),
236
+ agentId: stringValue(input.agentId ?? sourceRecord.agentId),
237
+ conversationContext: input.conversationContext,
238
+ createConversation: input.createConversation,
239
+ binding: input.binding,
240
+ handling,
241
+ app: input.app,
242
+ signal: input.signal,
243
+ onAssistantTextDelta: input.onAssistantTextDelta
244
+ });
245
+ }
246
+ function createChannelEventRequestBody(input) {
247
+ const { signal: _signal, onAssistantTextDelta: _onAssistantTextDelta, ...body } = createChannelEventInput(input);
248
+ return body;
249
+ }
250
+ function createMessageChannelEventInput(input) {
251
+ const direction = input.direction ?? "inbound";
252
+ return createChannelEventInput({
253
+ ...input,
254
+ kind: input.kind ?? "message",
255
+ nature: input.nature ?? input.kind ?? "message",
256
+ direction,
257
+ intent: input.intent ?? (direction === "outbound" ? "agent-message" : "customer-message"),
258
+ actor: input.actor ?? (direction === "outbound" ? "agent" : "customer")
259
+ });
260
+ }
261
+ function createProviderObjectChannelEventInput(input) {
262
+ return createChannelEventInput({
263
+ ...input,
264
+ kind: input.kind ?? "provider.object.updated",
265
+ nature: input.nature ?? input.kind ?? "provider.object.updated",
266
+ direction: input.direction ?? "internal",
267
+ intent: input.intent ?? "provider-update",
268
+ actor: input.actor ?? "provider",
269
+ sourceType: input.sourceType ?? input.source?.sourceType ?? "provider-adapter"
270
+ });
271
+ }
272
+ function createVoiceTurnChannelEventInput(input) {
273
+ const text = input.text ?? input.transcript;
274
+ return createChannelEventInput({
275
+ ...input,
276
+ channel: input.channel ?? "voice",
277
+ ...text !== void 0 ? { text } : {},
278
+ kind: input.kind ?? "voice.turn.finalized",
279
+ nature: input.nature ?? input.kind ?? "voice.turn.finalized",
280
+ direction: input.direction ?? "inbound",
281
+ intent: input.intent ?? "customer-voice-turn",
282
+ actor: input.actor ?? "customer",
283
+ sourceType: input.sourceType ?? input.source?.sourceType ?? "provider-adapter"
284
+ });
285
+ }
286
+ function createOutboundContactChannelEventInput(input) {
287
+ return createChannelEventInput({
288
+ ...input,
289
+ kind: input.kind ?? "outbound.contact.requested",
290
+ nature: input.nature ?? input.kind ?? "outbound.contact.requested",
291
+ direction: input.direction ?? "outbound",
292
+ intent: input.intent ?? "outbound-contact",
293
+ actor: input.actor ?? "application"
294
+ });
295
+ }
296
+ function createScheduledChannelEventInput(input) {
297
+ return createChannelEventInput({
298
+ ...input,
299
+ kind: input.kind ?? "schedule.due",
300
+ nature: input.nature ?? input.kind ?? "schedule.due",
301
+ direction: input.direction ?? "internal",
302
+ intent: input.intent ?? "scheduled-support-action",
303
+ actor: input.actor ?? "scheduler",
304
+ sourceType: input.sourceType ?? input.source?.sourceType ?? "schedule-adapter"
305
+ });
306
+ }
307
+ function createChannelOutputResolutionEventInput(input) {
308
+ return createChannelEventInput({
309
+ ...input,
310
+ kind: input.kind ?? "output.resolution",
311
+ nature: input.nature ?? input.kind ?? "output.resolution",
312
+ direction: input.direction ?? "outbound",
313
+ intent: input.intent ?? "output-resolution",
314
+ actor: input.actor ?? "application",
315
+ handling: {
316
+ ...input.handling,
317
+ disposition: input.handling?.disposition ?? "output-resolution"
318
+ }
319
+ });
320
+ }
321
+ function createChannelHandoffEventInput(input) {
322
+ const payload = buildPayload(input, input, void 0, input.turn);
323
+ return createChannelEventInput({
324
+ ...input,
325
+ payload: {
326
+ ...isRecord(payload) ? payload : {},
327
+ ...input.fromChannel ? { fromChannel: input.fromChannel } : {},
328
+ toChannel: input.channel,
329
+ ...input.reason ? { reason: input.reason } : {},
330
+ ...input.reasonCode ? { reasonCode: input.reasonCode } : {},
331
+ ...input.reasonLabel ? { reasonLabel: input.reasonLabel } : {}
332
+ },
333
+ kind: input.kind ?? "channel.handoff.requested",
334
+ nature: input.nature ?? input.kind ?? "channel.handoff.requested",
335
+ direction: input.direction ?? "internal",
336
+ intent: input.intent ?? "channel-handoff",
337
+ actor: input.actor ?? "application",
338
+ handling: {
339
+ ...input.handling,
340
+ disposition: input.handling?.disposition ?? "handoff-review"
341
+ }
342
+ });
343
+ }
344
+ function createChannelHandoffReviewEventInput(input) {
345
+ return createChannelEventInput({
346
+ ...input,
347
+ kind: input.kind ?? "custom",
348
+ nature: input.nature ?? input.kind ?? "custom",
349
+ direction: input.direction ?? "internal",
350
+ intent: input.intent ?? "handoff-review",
351
+ actor: input.actor ?? "operator",
352
+ handling: {
353
+ ...input.handling,
354
+ disposition: input.handling?.disposition ?? "handoff-review"
355
+ }
356
+ });
357
+ }
358
+ function buildHandling(input, _text, turn) {
359
+ if (!input.handling && turn === void 0) return void 0;
360
+ return compact({
361
+ ...input.handling ?? {},
362
+ text: input.handling?.text ?? void 0,
363
+ turn: input.handling?.turn ?? turn
364
+ });
365
+ }
366
+ function buildPayload(sourceRecord, input, text, turn) {
367
+ const seed = firstDefined(sourceRecord.payload, input.payload);
368
+ const fields = compact({
369
+ text,
370
+ subject: stringValue(sourceRecord.subject ?? input.subject),
371
+ body: stringValue(sourceRecord.body ?? input.body),
372
+ summary: stringValue(sourceRecord.summary ?? input.summary),
373
+ attachments: firstDefined(sourceRecord.attachments, input.attachments),
374
+ providerObject: firstDefined(sourceRecord.providerObject, input.providerObject),
375
+ status: stringValue(sourceRecord.status ?? input.status),
376
+ turn
377
+ });
378
+ if (seed === void 0) return Object.keys(fields).length > 0 ? fields : void 0;
379
+ if (typeof seed === "string") return Object.keys(fields).length > 0 ? { ...fields, text: fields.text ?? seed } : { text: seed };
380
+ if (!isRecord(seed)) return Object.keys(fields).length > 0 ? { value: seed, ...fields } : seed;
381
+ return { ...fields, ...seed };
382
+ }
383
+ function buildSource(sourceRecord, input, defaultSourceType) {
384
+ const seed = recordValue(sourceRecord.source ?? input.source) ?? {};
385
+ const hasEvidence = hasSourceEvidence(sourceRecord, input, seed);
386
+ const source = compact({
387
+ ...seed,
388
+ sourceType: stringValue(sourceRecord.sourceType ?? input.sourceType) ?? seed.sourceType ?? (hasEvidence ? defaultSourceType : void 0),
389
+ sourceId: stringValue(sourceRecord.sourceId ?? input.sourceId) ?? seed.sourceId,
390
+ provider: stringValue(sourceRecord.provider ?? input.provider) ?? seed.provider,
391
+ providerPackageId: stringValue(sourceRecord.providerPackageId ?? input.providerPackageId) ?? seed.providerPackageId,
392
+ eventId: stringValue(sourceRecord.eventId ?? input.eventId) ?? seed.eventId,
393
+ streamId: stringValue(sourceRecord.streamId ?? input.streamId) ?? seed.streamId,
394
+ deliveryId: stringValue(sourceRecord.deliveryId ?? input.deliveryId) ?? seed.deliveryId,
395
+ receivedAt: stringValue(sourceRecord.receivedAt ?? input.receivedAt) ?? seed.receivedAt,
396
+ verified: booleanValue(sourceRecord.verified ?? input.verified) ?? seed.verified,
397
+ externalObjectIds: recordValue(sourceRecord.externalObjectIds ?? input.externalObjectIds) ?? seed.externalObjectIds,
398
+ raw: firstDefined(sourceRecord.raw, input.raw, seed.raw)
399
+ });
400
+ return Object.keys(source).length > 0 ? source : void 0;
401
+ }
402
+ function buildIdentity(sourceRecord, input) {
403
+ const seed = recordValue(sourceRecord.identity ?? input.identity) ?? {};
404
+ const identity = compact({
405
+ ...seed,
406
+ key: stringValue(sourceRecord.identityKey ?? input.identityKey) ?? seed.key,
407
+ dedupeKey: stringValue(sourceRecord.dedupeKey ?? input.dedupeKey) ?? seed.dedupeKey,
408
+ streamId: stringValue(sourceRecord.identityStreamId ?? input.identityStreamId) ?? seed.streamId,
409
+ sequence: sequenceValue(sourceRecord.sequence ?? input.sequence) ?? seed.sequence,
410
+ idempotencyKey: stringValue(sourceRecord.idempotencyKey ?? input.idempotencyKey) ?? seed.idempotencyKey,
411
+ metadata: recordValue(sourceRecord.identityMetadata ?? input.identityMetadata) ?? seed.metadata
412
+ });
413
+ return Object.keys(identity).length > 0 ? identity : void 0;
414
+ }
415
+ function passthroughEventFields(eventRecord) {
416
+ if (!eventRecord) return {};
417
+ const output = { ...eventRecord };
418
+ for (const key of [
419
+ "conversationId",
420
+ "agentId",
421
+ "text",
422
+ "message",
423
+ "subject",
424
+ "body",
425
+ "summary",
426
+ "attachments",
427
+ "providerObject",
428
+ "status",
429
+ "turn",
430
+ "raw",
431
+ "sourceType",
432
+ "sourceId",
433
+ "provider",
434
+ "providerPackageId",
435
+ "eventId",
436
+ "streamId",
437
+ "deliveryId",
438
+ "receivedAt",
439
+ "verified",
440
+ "externalObjectIds",
441
+ "identity",
442
+ "identityKey",
443
+ "dedupeKey",
444
+ "idempotencyKey",
445
+ "identityStreamId",
446
+ "sequence",
447
+ "identityMetadata"
448
+ ]) {
449
+ delete output[key];
450
+ }
451
+ return output;
452
+ }
453
+ function firstText(sourceRecord, input) {
454
+ const explicit = stringValue(sourceRecord.text ?? sourceRecord.message ?? input.text ?? input.message);
455
+ if (explicit) return explicit;
456
+ const payload = firstDefined(sourceRecord.payload, input.payload);
457
+ if (typeof payload === "string") return payload.trim() || void 0;
458
+ if (isRecord(payload)) return stringValue(payload.text ?? payload.message);
459
+ return void 0;
460
+ }
461
+ function inferKind(sourceRecord, input) {
462
+ if (firstText(sourceRecord, input)) return "message";
463
+ if (sourceRecord.providerObject !== void 0 || input.providerObject !== void 0 || sourceRecord.status !== void 0 || input.status !== void 0) return "provider.object.updated";
464
+ return void 0;
465
+ }
466
+ function inferDirection(kind) {
467
+ if (kind === "provider.object.updated" || kind === "schedule.due" || kind === "custom") return "internal";
468
+ if (kind === "outbound.contact.requested" || kind === "output.resolution") return "outbound";
469
+ return "inbound";
470
+ }
471
+ function inferIntent(kind, direction) {
472
+ if (kind === "message") return direction === "outbound" ? "agent-message" : "customer-message";
473
+ if (kind === "voice.turn.finalized") return "customer-voice-turn";
474
+ if (kind === "provider.object.updated") return "provider-update";
475
+ if (kind === "operator.resume") return "operator-resume";
476
+ if (kind === "outbound.contact.requested") return "outbound-contact";
477
+ if (kind === "channel.handoff.requested") return "channel-handoff";
478
+ if (kind === "schedule.due") return "scheduled-support-action";
479
+ if (kind === "output.resolution") return "output-resolution";
480
+ if (kind === "delivery.updated") return "delivery-update";
481
+ return void 0;
482
+ }
483
+ function inferActor(kind, direction) {
484
+ if (kind === "message") return { type: direction === "outbound" ? "agent" : "customer" };
485
+ if (kind === "voice.turn.finalized") return { type: "customer" };
486
+ if (kind === "provider.object.updated" || kind === "delivery.updated") return { type: "provider" };
487
+ if (kind === "schedule.due") return { type: "scheduler" };
488
+ if (kind === "channel.handoff.requested") return { type: "application" };
489
+ if (kind === "outbound.contact.requested" || kind === "output.resolution") return { type: "application" };
490
+ if (kind === "operator.resume") return { type: "operator" };
491
+ return void 0;
492
+ }
493
+ function inferSourceType(kind) {
494
+ if (kind === "schedule.due") return "schedule-adapter";
495
+ if (kind === "message" || kind === "voice.session.started" || kind === "voice.turn.finalized" || kind === "provider.object.updated" || kind === "delivery.updated") return "provider-adapter";
496
+ return void 0;
497
+ }
498
+ function hasSourceEvidence(sourceRecord, input, seed) {
499
+ return Object.keys(seed).length > 0 || sourceRecord.provider !== void 0 || input.provider !== void 0 || sourceRecord.providerPackageId !== void 0 || input.providerPackageId !== void 0 || sourceRecord.eventId !== void 0 || input.eventId !== void 0 || sourceRecord.streamId !== void 0 || input.streamId !== void 0 || sourceRecord.deliveryId !== void 0 || input.deliveryId !== void 0 || sourceRecord.raw !== void 0 || input.raw !== void 0;
500
+ }
501
+ function normalizeActor(value) {
502
+ if (value === void 0 || value === null) return void 0;
503
+ if (typeof value === "string") return { type: value };
504
+ if (isRecord(value)) return value;
505
+ return void 0;
506
+ }
507
+ function compact(record) {
508
+ const output = {};
509
+ for (const [key, value] of Object.entries(record)) {
510
+ if (value !== void 0) output[key] = value;
511
+ }
512
+ return output;
513
+ }
514
+ function firstDefined(...values) {
515
+ for (const value of values) {
516
+ if (value !== void 0) return value;
517
+ }
518
+ return void 0;
519
+ }
520
+ function stringValue(value) {
521
+ if (typeof value !== "string") return void 0;
522
+ const trimmed = value.trim();
523
+ return trimmed.length > 0 ? trimmed : void 0;
524
+ }
525
+ function booleanValue(value) {
526
+ return typeof value === "boolean" ? value : void 0;
527
+ }
528
+ function sequenceValue(value) {
529
+ return typeof value === "string" || typeof value === "number" ? value : void 0;
530
+ }
531
+ function recordValue(value) {
532
+ return isRecord(value) ? value : void 0;
533
+ }
534
+ function isRecord(value) {
535
+ return typeof value === "object" && value !== null && !Array.isArray(value);
536
+ }
537
+
538
+ // src/handler/body.ts
539
+ async function readObject(request) {
540
+ const body = await readJson(request);
541
+ if (!isRecord2(body)) throw new HttpInputError("Request body must be a JSON object.");
542
+ return body;
543
+ }
544
+ function isRecord2(value) {
545
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
546
+ }
547
+
548
+ // src/handler/optional.ts
549
+ import { defineChannelContext } from "@cognidesk/core";
550
+ function optionalString(body, key) {
551
+ const value = body[key];
552
+ if (value === void 0 || value === null) return void 0;
553
+ if (typeof value !== "string") throw new HttpInputError(`${key} must be a string.`);
554
+ const trimmed = value.trim();
555
+ return trimmed.length > 0 ? trimmed : void 0;
556
+ }
557
+ function optionalStringProperty(body, key) {
558
+ const value = optionalString(body, key);
559
+ return value ? { [key]: value } : {};
560
+ }
561
+ function optionalChannel(body, key) {
562
+ const value = body[key];
563
+ if (value === void 0 || value === null) return void 0;
564
+ try {
565
+ return defineChannelContext(value);
566
+ } catch {
567
+ throw new HttpInputError(`${key} must be a valid conversation channel.`);
568
+ }
569
+ }
570
+ function optionalChannelProperty(body) {
571
+ const channel = optionalChannel(body, "channel");
572
+ return channel ? { channel } : {};
573
+ }
574
+ function optionalNonNegativeNumber(body, key) {
575
+ const value = body[key];
576
+ if (value === void 0 || value === null) return void 0;
577
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
578
+ throw new HttpInputError(`${key} must be a non-negative integer.`);
579
+ }
580
+ return value;
581
+ }
582
+ function optionalRouting(body, key) {
583
+ const value = optionalString(body, key);
584
+ if (!value) return void 0;
585
+ if (value !== "none" && value !== "activeJourneyOnly" && value !== "full" && value !== "targeted") {
586
+ throw new HttpInputError(`${key} must be a valid routing mode.`);
587
+ }
588
+ return value;
589
+ }
590
+ function optionalTarget(body, key) {
591
+ const value = body[key];
592
+ if (value === void 0 || value === null) return void 0;
593
+ if (!isRecord2(value)) throw new HttpInputError(`${key} must be an object.`);
594
+ const journeyId = optionalString(value, "journeyId");
595
+ const stateId = optionalString(value, "stateId");
596
+ return {
597
+ ...journeyId ? { journeyId } : {},
598
+ ...stateId ? { stateId } : {}
599
+ };
600
+ }
601
+ function optionalVoiceClient(body) {
602
+ const value = body.client;
603
+ if (value === void 0 || value === null) return {};
604
+ if (!isRecord2(value)) throw new HttpInputError("client must be an object.");
605
+ const userAgent = optionalString(value, "userAgent");
606
+ const locale = optionalString(value, "locale");
607
+ const metadata = value.metadata;
608
+ if (metadata !== void 0 && metadata !== null && !isRecord2(metadata)) {
609
+ throw new HttpInputError("client.metadata must be an object.");
610
+ }
611
+ return {
612
+ client: {
613
+ ...userAgent ? { userAgent } : {},
614
+ ...locale ? { locale } : {},
615
+ ...isRecord2(metadata) ? { metadata } : {}
616
+ }
617
+ };
618
+ }
619
+
620
+ // src/handler/channel-events.ts
621
+ async function handleChannelEvent(options, input, responseOptions) {
622
+ if (hasHandleChannelEvent(options.runtime)) {
623
+ return options.runtime.handleChannelEvent(input);
624
+ }
625
+ const userMessageInput = channelEventToUserMessageInput(input);
626
+ if (!userMessageInput) {
627
+ return json({ error: "Channel events are not supported by this runtime" }, 501, responseOptions);
628
+ }
629
+ const result = await options.runtime.handleUserMessage(userMessageInput);
630
+ return channelEventResultFromUserMessageResult(input, result);
631
+ }
632
+ function hasHandleChannelEvent(runtime) {
633
+ return typeof runtime.handleChannelEvent === "function";
634
+ }
635
+ function readChannelEventInput(body, signal) {
636
+ try {
637
+ return createChannelEventInput({ ...body, signal });
638
+ } catch (error) {
639
+ throw new HttpInputError(error instanceof Error ? error.message : "Invalid Channel Event input.");
640
+ }
641
+ }
642
+ function channelEventToUserMessageInput(input) {
643
+ const event = input.event;
644
+ if (!isInboundMessageEvent(event)) return null;
645
+ const conversationId = input.conversationId ?? input.binding?.conversationId;
646
+ if (!conversationId) return null;
647
+ const text = input.handling?.text ?? textFromChannelEventPayload(event.payload);
648
+ if (!text) return null;
649
+ const turn = turnFromChannelEventPayload(event.payload);
650
+ return {
651
+ conversationId,
652
+ text,
653
+ channel: defineChannelContext2(event.channel),
654
+ ...input.handling?.turn !== void 0 ? { turn: input.handling.turn } : turn !== void 0 ? { turn } : {},
655
+ ...input.app !== void 0 ? { app: input.app } : {},
656
+ ...input.signal ? { signal: input.signal } : {}
657
+ };
658
+ }
659
+ function isInboundMessageEvent(event) {
660
+ const inbound = event.direction === void 0 || event.direction === "inbound";
661
+ return inbound && (event.nature === "message" || event.kind === "message" || event.intent === "customer-message");
662
+ }
663
+ function textFromChannelEventPayload(payload) {
664
+ if (typeof payload === "string") return payload.trim() || void 0;
665
+ if (!isRecord2(payload)) return void 0;
666
+ return optionalString(payload, "text") ?? optionalString(payload, "message");
667
+ }
668
+ function turnFromChannelEventPayload(payload) {
669
+ if (!isRecord2(payload)) return void 0;
670
+ return payload.turn;
671
+ }
672
+ function channelEventResultFromUserMessageResult(input, result) {
673
+ const channelEvent = defineChannelEvent(input.event);
674
+ return {
675
+ channelEvent,
676
+ intake: {
677
+ outcome: "accepted",
678
+ bindingOutcome: input.binding?.outcome ?? "resume-existing",
679
+ conversationId: result.conversation.id,
680
+ handling: "started"
681
+ },
682
+ conversation: result.conversation,
683
+ turn: result,
684
+ snapshot: result.snapshot,
685
+ events: result.events,
686
+ text: result.text,
687
+ ...result.activeJourneyId ? { activeJourneyId: result.activeJourneyId } : {},
688
+ disposition: "model-turn"
689
+ };
690
+ }
691
+ function sendMessageResultFromChannelEvent(result) {
692
+ return {
693
+ text: result.turn?.text ?? result.text ?? textFromEvents(result.events) ?? "",
694
+ events: result.events,
695
+ ...result.turn?.activeJourneyId ?? result.activeJourneyId ? { activeJourneyId: result.turn?.activeJourneyId ?? result.activeJourneyId } : {}
696
+ };
697
+ }
698
+ function textFromEvents(events) {
699
+ for (const event of [...events].reverse()) {
700
+ if (event.type === "message.completed" && typeof event.data.text === "string") {
701
+ return event.data.text;
702
+ }
703
+ }
704
+ return void 0;
705
+ }
706
+
707
+ // src/handler/channel-output.ts
708
+ function hasResolveChannelOutput(runtime) {
709
+ return typeof runtime.resolveChannelOutput === "function";
710
+ }
711
+ function readChannelOutputResolutionInput(body, signal) {
712
+ const record = body;
713
+ const conversationId = optionalString(record, "conversationId");
714
+ if (!conversationId) throw new HttpInputError("conversationId is required");
715
+ if (!isRecord2(record.intent)) throw new HttpInputError("intent is required");
716
+ const input = {
717
+ conversationId,
718
+ intent: record.intent,
719
+ signal
720
+ };
721
+ if (record.resolution !== void 0) {
722
+ input.resolution = record.resolution;
723
+ }
724
+ if (record.app !== void 0) {
725
+ input.app = record.app;
726
+ }
727
+ return input;
728
+ }
729
+
730
+ // src/handler/errors.ts
731
+ function internalErrorMessage(error, options) {
732
+ if (!options.exposeInternalErrors) return "Internal server error";
733
+ return error instanceof Error ? error.message : "Unknown error";
734
+ }
735
+
736
+ // src/handler/voice.ts
737
+ function withVoiceEventsUrl(result, basePath) {
738
+ return {
739
+ ...result,
740
+ eventsUrl: `${basePath}/conversations/${encodeURIComponent(result.conversation.id)}/events/stream`
741
+ };
742
+ }
743
+
744
+ // src/handler/index.ts
123
745
  function createCognideskHttpHandler(options) {
124
746
  const basePath = normalizeBasePath(options.basePath ?? "");
125
747
  const pollIntervalMs = options.ssePollIntervalMs ?? 500;
126
748
  return {
127
749
  async handle(request) {
128
- if (request.method === "OPTIONS" && options.cors) {
129
- return emptyResponse(204, options);
130
- }
750
+ const responseOptions = {
751
+ request,
752
+ ...options.cors !== void 0 ? { cors: options.cors } : {}
753
+ };
131
754
  try {
132
755
  const url = new URL(request.url);
133
756
  const path = stripBasePath(url.pathname, basePath);
134
- if (path === null) return json({ error: "Not found" }, 404, options);
757
+ if (path === null) return json({ error: "Not found" }, 404, responseOptions);
758
+ if (request.method === "OPTIONS" && options.cors) {
759
+ return emptyResponse(204, responseOptions);
760
+ }
761
+ const authorizationResponse = await authorizeRequest(options, { request, url, path }, responseOptions);
762
+ if (authorizationResponse) return authorizationResponse;
135
763
  if (request.method === "POST" && path === "/conversations") {
136
764
  const body = await readObject(request);
137
765
  const agentId = optionalString(body, "agentId") ?? options.agentId;
138
- if (!agentId) return json({ error: "agentId is required" }, 400, options);
766
+ if (!agentId) return json({ error: "agentId is required" }, 400, responseOptions);
139
767
  const conversation = await options.runtime.createConversation({
140
768
  ...optionalStringProperty(body, "id"),
141
769
  agentId,
770
+ ...optionalChannelProperty(body),
142
771
  context: body.context ?? {}
143
772
  });
144
- return json({ conversation }, 201, options);
773
+ return json({ conversation }, 201, responseOptions);
774
+ }
775
+ if (request.method === "POST" && path === "/channel-events") {
776
+ const body = await readObject(request);
777
+ const input = readChannelEventInput(body, request.signal);
778
+ const result = await handleChannelEvent(options, input, responseOptions);
779
+ if (result instanceof Response) return result;
780
+ return json(result, 200, responseOptions);
781
+ }
782
+ if (request.method === "POST" && path === "/channel-outputs/resolve") {
783
+ if (!hasResolveChannelOutput(options.runtime)) {
784
+ return json({ error: "Channel Output resolution is not supported by this runtime" }, 501, responseOptions);
785
+ }
786
+ const body = await readObject(request);
787
+ const input = readChannelOutputResolutionInput(body, request.signal);
788
+ const result = await options.runtime.resolveChannelOutput(input);
789
+ return json(result, 200, responseOptions);
145
790
  }
146
791
  if (request.method === "POST" && path === "/voice/conversations") {
147
- if (!options.runtime.startVoiceConversation) return json({ error: "Voice conversations are not supported by this runtime" }, 501, options);
148
- if (!options.voice?.createSocket) return json({ error: "Voice socket handshakes are not configured" }, 501, options);
792
+ if (!options.runtime.startVoiceConversation) return json({ error: "Voice conversations are not supported by this runtime" }, 501, responseOptions);
793
+ if (!options.voice?.createSocket) return json({ error: "Voice socket handshakes are not configured" }, 501, responseOptions);
149
794
  const body = await readObject(request);
150
795
  const agentId = optionalString(body, "agentId") ?? options.agentId;
151
- if (!agentId) return json({ error: "agentId is required" }, 400, options);
796
+ if (!agentId) return json({ error: "agentId is required" }, 400, responseOptions);
152
797
  const result = await options.runtime.startVoiceConversation({
153
798
  ...optionalStringProperty(body, "id"),
154
799
  agentId,
@@ -157,12 +802,12 @@ function createCognideskHttpHandler(options) {
157
802
  ...body.app !== void 0 ? { app: body.app } : {}
158
803
  });
159
804
  const socket = await options.voice.createSocket({ result, request, basePath });
160
- return json(withVoiceEventsUrl({ ...result, socket }, basePath), 201, options);
805
+ return json(withVoiceEventsUrl({ ...result, socket }, basePath), 201, responseOptions);
161
806
  }
162
807
  const voiceSegmentMatch = path.match(/^\/conversations\/([^/]+)\/voice-segments$/);
163
808
  if (request.method === "POST" && voiceSegmentMatch) {
164
- if (!options.runtime.startVoiceSegment) return json({ error: "Voice segments are not supported by this runtime" }, 501, options);
165
- if (!options.voice?.createSocket) return json({ error: "Voice socket handshakes are not configured" }, 501, options);
809
+ if (!options.runtime.startVoiceSegment) return json({ error: "Voice segments are not supported by this runtime" }, 501, responseOptions);
810
+ if (!options.voice?.createSocket) return json({ error: "Voice socket handshakes are not configured" }, 501, responseOptions);
166
811
  const conversationId = decodeURIComponent(voiceSegmentMatch[1] ?? "");
167
812
  const body = await readObject(request);
168
813
  const result = await options.runtime.startVoiceSegment({
@@ -171,45 +816,68 @@ function createCognideskHttpHandler(options) {
171
816
  ...body.app !== void 0 ? { app: body.app } : {}
172
817
  });
173
818
  const socket = await options.voice.createSocket({ result, request, basePath });
174
- return json(withVoiceEventsUrl({ ...result, socket }, basePath), 200, options);
819
+ return json(withVoiceEventsUrl({ ...result, socket }, basePath), 200, responseOptions);
175
820
  }
176
821
  const messageMatch = path.match(/^\/conversations\/([^/]+)\/messages$/);
177
822
  if (request.method === "POST" && messageMatch) {
178
823
  const conversationId = decodeURIComponent(messageMatch[1] ?? "");
179
824
  const body = await readObject(request);
180
825
  const text = optionalString(body, "text") ?? optionalString(body, "message");
181
- if (!text) return json({ error: "message is required" }, 400, options);
826
+ if (!text) return json({ error: "message is required" }, 400, responseOptions);
827
+ const channel = optionalChannel(body, "channel") ?? defineChannelContext3("chat");
828
+ if (hasHandleChannelEvent(options.runtime)) {
829
+ const result2 = await options.runtime.handleChannelEvent({
830
+ conversationId,
831
+ event: {
832
+ channel,
833
+ kind: "message",
834
+ nature: "message",
835
+ direction: "inbound",
836
+ intent: "customer-message",
837
+ actor: { type: "customer" },
838
+ payload: {
839
+ text,
840
+ ...body.turn !== void 0 ? { turn: body.turn } : {}
841
+ }
842
+ },
843
+ ...body.turn !== void 0 ? { handling: { turn: body.turn } } : {},
844
+ ...body.app !== void 0 ? { app: body.app } : {},
845
+ signal: request.signal
846
+ });
847
+ return json(sendMessageResultFromChannelEvent(result2), 200, responseOptions);
848
+ }
182
849
  const result = await options.runtime.handleUserMessage({
183
850
  conversationId,
184
851
  text,
852
+ channel,
185
853
  ...body.turn !== void 0 ? { turn: body.turn } : {},
186
854
  ...body.app !== void 0 ? { app: body.app } : {},
187
855
  signal: request.signal
188
856
  });
189
- return json(result, 200, options);
857
+ return json(result, 200, responseOptions);
190
858
  }
191
859
  const customEventMatch = path.match(/^\/conversations\/([^/]+)\/custom-events\/([^/]+)$/);
192
860
  if (request.method === "POST" && customEventMatch) {
193
- if (!options.runtime.emitCustomEvent) return json({ error: "Custom events are not supported by this runtime" }, 501, options);
861
+ if (!options.runtime.emitCustomEvent) return json({ error: "Custom events are not supported by this runtime" }, 501, responseOptions);
194
862
  const conversationId = decodeURIComponent(customEventMatch[1] ?? "");
195
863
  const eventName = decodeURIComponent(customEventMatch[2] ?? "");
196
864
  const event = options.customEvents?.find((candidate) => candidate.name === eventName);
197
- if (!event) return json({ error: `Custom event '${eventName}' is not registered with the HTTP handler` }, 404, options);
865
+ if (!event) return json({ error: `Custom event '${eventName}' is not registered with the HTTP handler` }, 404, responseOptions);
198
866
  const body = await readObject(request);
199
867
  const emitted = await options.runtime.emitCustomEvent({
200
868
  conversationId,
201
869
  event,
202
870
  payload: body.payload
203
871
  });
204
- return json({ event: emitted }, 200, options);
872
+ return json({ event: emitted }, 200, responseOptions);
205
873
  }
206
874
  const journeyEventMatch = path.match(/^\/conversations\/([^/]+)\/journey-events\/([^/]+)$/);
207
875
  if (request.method === "POST" && journeyEventMatch) {
208
- if (!options.runtime.emitJourneyEvent) return json({ error: "Journey events are not supported by this runtime" }, 501, options);
876
+ if (!options.runtime.emitJourneyEvent) return json({ error: "Journey events are not supported by this runtime" }, 501, responseOptions);
209
877
  const conversationId = decodeURIComponent(journeyEventMatch[1] ?? "");
210
878
  const eventName = decodeURIComponent(journeyEventMatch[2] ?? "");
211
879
  const event = options.journeyEvents?.find((candidate) => candidate.name === eventName);
212
- if (!event) return json({ error: `Journey event '${eventName}' is not registered with the HTTP handler` }, 404, options);
880
+ if (!event) return json({ error: `Journey event '${eventName}' is not registered with the HTTP handler` }, 404, responseOptions);
213
881
  const body = await readObject(request);
214
882
  const routing = optionalRouting(body, "routing");
215
883
  const target = optionalTarget(body, "target");
@@ -222,37 +890,37 @@ function createCognideskHttpHandler(options) {
222
890
  ...body.app !== void 0 ? { app: body.app } : {},
223
891
  signal: request.signal
224
892
  });
225
- return json(result, 200, options);
893
+ return json(result, 200, responseOptions);
226
894
  }
227
895
  const handoffMatch = path.match(/^\/conversations\/([^/]+)\/handoff$/);
228
896
  if (request.method === "POST" && handoffMatch) {
229
- if (!options.runtime.requestHandoff) return json({ error: "Handoff is not supported by this runtime" }, 501, options);
897
+ if (!options.runtime.requestHandoff) return json({ error: "Handoff is not supported by this runtime" }, 501, responseOptions);
230
898
  const conversationId = decodeURIComponent(handoffMatch[1] ?? "");
231
899
  const body = await readObject(request);
232
900
  const reason = optionalString(body, "reason");
233
- if (!reason) return json({ error: "reason is required" }, 400, options);
901
+ if (!reason) return json({ error: "reason is required" }, 400, responseOptions);
234
902
  const result = await options.runtime.requestHandoff({
235
903
  conversationId,
236
904
  reason,
237
905
  ...optionalStringProperty(body, "summary"),
238
906
  ...body.payload !== void 0 ? { payload: body.payload } : {}
239
907
  });
240
- return json(result, 200, options);
908
+ return json(result, 200, responseOptions);
241
909
  }
242
910
  const closeMatch = path.match(/^\/conversations\/([^/]+)\/close$/);
243
911
  if (request.method === "POST" && closeMatch) {
244
- if (!options.runtime.closeConversation) return json({ error: "Conversation closure is not supported by this runtime" }, 501, options);
912
+ if (!options.runtime.closeConversation) return json({ error: "Conversation closure is not supported by this runtime" }, 501, responseOptions);
245
913
  const conversationId = decodeURIComponent(closeMatch[1] ?? "");
246
914
  const body = await readObject(request);
247
915
  const conversation = await options.runtime.closeConversation(
248
916
  conversationId,
249
917
  optionalString(body, "reason")
250
918
  );
251
- return json({ conversation }, 200, options);
919
+ return json({ conversation }, 200, responseOptions);
252
920
  }
253
921
  const resumeMatch = path.match(/^\/conversations\/([^/]+)\/resume$/);
254
922
  if (request.method === "POST" && resumeMatch) {
255
- if (!options.runtime.resumeConversation) return json({ error: "Conversation resume is not supported by this runtime" }, 501, options);
923
+ if (!options.runtime.resumeConversation) return json({ error: "Conversation resume is not supported by this runtime" }, 501, responseOptions);
256
924
  const conversationId = decodeURIComponent(resumeMatch[1] ?? "");
257
925
  const body = await readObject(request);
258
926
  const result = await options.runtime.resumeConversation({
@@ -260,25 +928,25 @@ function createCognideskHttpHandler(options) {
260
928
  ...optionalStringProperty(body, "reason"),
261
929
  ...body.payload !== void 0 ? { payload: body.payload } : {}
262
930
  });
263
- return json(result, 200, options);
931
+ return json(result, 200, responseOptions);
264
932
  }
265
933
  const intermediateMessageMatch = path.match(/^\/conversations\/([^/]+)\/intermediate-messages$/);
266
934
  if (request.method === "POST" && intermediateMessageMatch) {
267
- if (!options.runtime.emitIntermediateMessage) return json({ error: "Intermediate messages are not supported by this runtime" }, 501, options);
935
+ if (!options.runtime.emitIntermediateMessage) return json({ error: "Intermediate messages are not supported by this runtime" }, 501, responseOptions);
268
936
  const conversationId = decodeURIComponent(intermediateMessageMatch[1] ?? "");
269
937
  const body = await readObject(request);
270
938
  const text = optionalString(body, "text");
271
- if (!text) return json({ error: "text is required" }, 400, options);
939
+ if (!text) return json({ error: "text is required" }, 400, responseOptions);
272
940
  const result = await options.runtime.emitIntermediateMessage({
273
941
  conversationId,
274
942
  text,
275
943
  ...body.visibleToModel === true ? { visibleToModel: true } : {}
276
944
  });
277
- return json(result, 200, options);
945
+ return json(result, 200, responseOptions);
278
946
  }
279
947
  const preambleMatch = path.match(/^\/conversations\/([^/]+)\/preambles$/);
280
948
  if (request.method === "POST" && preambleMatch) {
281
- if (!options.runtime.emitGeneratedPreamble) return json({ error: "Generated preambles are not supported by this runtime" }, 501, options);
949
+ if (!options.runtime.emitGeneratedPreamble) return json({ error: "Generated preambles are not supported by this runtime" }, 501, responseOptions);
282
950
  const conversationId = decodeURIComponent(preambleMatch[1] ?? "");
283
951
  const body = await readObject(request);
284
952
  const maxWords = optionalNonNegativeNumber(body, "maxWords");
@@ -288,11 +956,11 @@ function createCognideskHttpHandler(options) {
288
956
  ...maxWords !== void 0 ? { maxWords } : {},
289
957
  signal: request.signal
290
958
  });
291
- return json(result, 200, options);
959
+ return json(result, 200, responseOptions);
292
960
  }
293
961
  const compactionMatch = path.match(/^\/conversations\/([^/]+)\/compact$/);
294
962
  if (request.method === "POST" && compactionMatch) {
295
- if (!options.runtime.compactConversation) return json({ error: "Conversation compaction is not supported by this runtime" }, 501, options);
963
+ if (!options.runtime.compactConversation) return json({ error: "Conversation compaction is not supported by this runtime" }, 501, responseOptions);
296
964
  const conversationId = decodeURIComponent(compactionMatch[1] ?? "");
297
965
  const body = await readObject(request);
298
966
  const fromOffset = optionalNonNegativeNumber(body, "fromOffset");
@@ -304,48 +972,48 @@ function createCognideskHttpHandler(options) {
304
972
  ...optionalStringProperty(body, "schemaVersion"),
305
973
  signal: request.signal
306
974
  });
307
- return json(result, 200, options);
975
+ return json(result, 200, responseOptions);
308
976
  }
309
977
  const widgetSubmissionMatch = path.match(/^\/conversations\/([^/]+)\/widgets\/([^/]+)\/submissions$/);
310
978
  if (request.method === "POST" && widgetSubmissionMatch) {
311
- if (!options.runtime.submitWidget) return json({ error: "Widget submissions are not supported by this runtime" }, 501, options);
979
+ if (!options.runtime.submitWidget) return json({ error: "Widget submissions are not supported by this runtime" }, 501, responseOptions);
312
980
  const conversationId = decodeURIComponent(widgetSubmissionMatch[1] ?? "");
313
981
  const promptId = decodeURIComponent(widgetSubmissionMatch[2] ?? "");
314
982
  const body = await readObject(request);
315
983
  const widgetKind = optionalString(body, "widgetKind");
316
- if (!widgetKind) return json({ error: "widgetKind is required" }, 400, options);
984
+ if (!widgetKind) return json({ error: "widgetKind is required" }, 400, responseOptions);
317
985
  const event = await options.runtime.submitWidget({
318
986
  conversationId,
319
987
  promptId,
320
988
  widgetKind,
321
989
  output: body.output
322
990
  });
323
- return json({ event }, 200, options);
991
+ return json({ event }, 200, responseOptions);
324
992
  }
325
993
  const snapshotMatch = path.match(/^\/conversations\/([^/]+)\/snapshot$/);
326
994
  if (request.method === "GET" && snapshotMatch) {
327
- if (!options.runtime.getSnapshot) return json({ error: "Snapshots are not supported by this runtime" }, 501, options);
995
+ if (!options.runtime.getSnapshot) return json({ error: "Snapshots are not supported by this runtime" }, 501, responseOptions);
328
996
  const conversationId = decodeURIComponent(snapshotMatch[1] ?? "");
329
997
  const snapshot = await options.runtime.getSnapshot(conversationId);
330
- return json({ snapshot }, 200, options);
998
+ return json({ snapshot }, 200, responseOptions);
331
999
  }
332
1000
  const replayMatch = path.match(/^\/conversations\/([^/]+)\/replay$/);
333
1001
  if (request.method === "GET" && replayMatch) {
334
- if (!options.runtime.replayConversation) return json({ error: "Event replay is not supported by this runtime" }, 501, options);
1002
+ if (!options.runtime.replayConversation) return json({ error: "Event replay is not supported by this runtime" }, 501, responseOptions);
335
1003
  const conversationId = decodeURIComponent(replayMatch[1] ?? "");
336
1004
  const afterOffset = parseOptionalInteger(url.searchParams.get("after"));
337
1005
  const replay = await options.runtime.replayConversation({
338
1006
  conversationId,
339
1007
  ...afterOffset !== void 0 ? { afterOffset } : {}
340
1008
  });
341
- return json(replay, 200, options);
1009
+ return json(replay, 200, responseOptions);
342
1010
  }
343
1011
  const eventsMatch = path.match(/^\/conversations\/([^/]+)\/events$/);
344
1012
  if (request.method === "GET" && eventsMatch) {
345
1013
  const conversationId = decodeURIComponent(eventsMatch[1] ?? "");
346
1014
  const afterOffset = parseOptionalInteger(url.searchParams.get("after"));
347
1015
  const events = await options.runtime.listEvents(conversationId, afterOffset);
348
- return json({ events }, 200, options);
1016
+ return json({ events }, 200, responseOptions);
349
1017
  }
350
1018
  const streamMatch = path.match(/^\/conversations\/([^/]+)\/events\/stream$/);
351
1019
  if (request.method === "GET" && streamMatch) {
@@ -357,92 +1025,31 @@ function createCognideskHttpHandler(options) {
357
1025
  afterOffset,
358
1026
  pollIntervalMs,
359
1027
  signal: request.signal,
360
- responseOptions: options
1028
+ responseOptions
361
1029
  });
362
1030
  }
363
- return json({ error: "Not found" }, 404, options);
1031
+ return json({ error: "Not found" }, 404, responseOptions);
364
1032
  } catch (error) {
365
1033
  if (error instanceof HttpInputError) {
366
- return json({ error: error.message }, error.status, options);
1034
+ return json({ error: error.message }, error.status, responseOptions);
367
1035
  }
368
1036
  return json({
369
- error: error instanceof Error ? error.message : "Unknown error"
370
- }, 500, options);
1037
+ error: internalErrorMessage(error, options)
1038
+ }, 500, responseOptions);
371
1039
  }
372
1040
  }
373
1041
  };
374
1042
  }
375
- async function readObject(request) {
376
- const body = await readJson(request);
377
- if (!isRecord(body)) throw new HttpInputError("Request body must be a JSON object.");
378
- return body;
379
- }
380
- function optionalString(body, key) {
381
- const value = body[key];
382
- if (value === void 0 || value === null) return void 0;
383
- if (typeof value !== "string") throw new HttpInputError(`${key} must be a string.`);
384
- const trimmed = value.trim();
385
- return trimmed.length > 0 ? trimmed : void 0;
386
- }
387
- function optionalStringProperty(body, key) {
388
- const value = optionalString(body, key);
389
- return value ? { [key]: value } : {};
390
- }
391
- function optionalNonNegativeNumber(body, key) {
392
- const value = body[key];
393
- if (value === void 0 || value === null) return void 0;
394
- if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
395
- throw new HttpInputError(`${key} must be a non-negative integer.`);
396
- }
397
- return value;
398
- }
399
- function optionalRouting(body, key) {
400
- const value = optionalString(body, key);
401
- if (!value) return void 0;
402
- if (value !== "none" && value !== "activeJourneyOnly" && value !== "full" && value !== "targeted") {
403
- throw new HttpInputError(`${key} must be a valid routing mode.`);
404
- }
405
- return value;
406
- }
407
- function optionalTarget(body, key) {
408
- const value = body[key];
409
- if (value === void 0 || value === null) return void 0;
410
- if (!isRecord(value)) throw new HttpInputError(`${key} must be an object.`);
411
- const journeyId = optionalString(value, "journeyId");
412
- const stateId = optionalString(value, "stateId");
413
- return {
414
- ...journeyId ? { journeyId } : {},
415
- ...stateId ? { stateId } : {}
416
- };
417
- }
418
- function optionalVoiceClient(body) {
419
- const value = body.client;
420
- if (value === void 0 || value === null) return {};
421
- if (!isRecord(value)) throw new HttpInputError("client must be an object.");
422
- const userAgent = optionalString(value, "userAgent");
423
- const locale = optionalString(value, "locale");
424
- const metadata = value.metadata;
425
- if (metadata !== void 0 && metadata !== null && !isRecord(metadata)) {
426
- throw new HttpInputError("client.metadata must be an object.");
427
- }
428
- return {
429
- client: {
430
- ...userAgent ? { userAgent } : {},
431
- ...locale ? { locale } : {},
432
- ...isRecord(metadata) ? { metadata } : {}
433
- }
434
- };
435
- }
436
- function withVoiceEventsUrl(result, basePath) {
437
- return {
438
- ...result,
439
- eventsUrl: `${basePath}/conversations/${encodeURIComponent(result.conversation.id)}/events/stream`
440
- };
441
- }
442
- function isRecord(value) {
443
- return Boolean(value && typeof value === "object" && !Array.isArray(value));
444
- }
445
1043
  export {
446
- createCognideskHttpHandler
1044
+ createChannelEventInput,
1045
+ createChannelEventRequestBody,
1046
+ createChannelHandoffEventInput,
1047
+ createChannelHandoffReviewEventInput,
1048
+ createChannelOutputResolutionEventInput,
1049
+ createCognideskHttpHandler,
1050
+ createMessageChannelEventInput,
1051
+ createOutboundContactChannelEventInput,
1052
+ createProviderObjectChannelEventInput,
1053
+ createScheduledChannelEventInput,
1054
+ createVoiceTurnChannelEventInput
447
1055
  };
448
- //# sourceMappingURL=index.js.map