@craftedxp/sdk-node 0.12.0 → 0.15.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.d.ts CHANGED
@@ -31,6 +31,16 @@ type TtsProvider = 'pockettts' | 'cartesia' | 'fish-audio' | 'gemini' | 'kokoro'
31
31
  type SttProvider = 'deepgram';
32
32
  type LlmProvider = 'gemini' | 'openai' | 'anthropic';
33
33
  type EndpointingMode = 'smart' | 'simple';
34
+ /**
35
+ * Agent kind. Set at creation and immutable thereafter — changing what an
36
+ * agent does means creating a new one. Gates which routes accept the agent:
37
+ * - `assistant` — 1:1 voice + text chat + learning mode (LLM + STT + TTS)
38
+ * - `room` — hosts LiveKit rooms; per-speaker transcription + analysis
39
+ * - `transcribe` — 1:1 dictation, STT-only (the agent never speaks)
40
+ *
41
+ * Replaces the legacy `canHostRooms` / `transcribeOnly` boolean flags.
42
+ */
43
+ type AgentType = 'assistant' | 'room' | 'transcribe';
34
44
  interface AgentVoice {
35
45
  provider: TtsProvider;
36
46
  voiceId?: string;
@@ -109,6 +119,8 @@ interface AgentRecording {
109
119
  interface Agent {
110
120
  agentId: string;
111
121
  orgId: string;
122
+ /** Agent kind — see {@link AgentType}. Immutable after creation. */
123
+ type: AgentType;
112
124
  name: string;
113
125
  systemPrompt: string;
114
126
  /**
@@ -119,6 +131,8 @@ interface Agent {
119
131
  * caller speaks first.
120
132
  */
121
133
  agentSpeaksFirst?: boolean;
134
+ /** Personal assistant (`assistant` agents only) — the learning tools are live on every `ct_`-token call, not just `mode=learning`. */
135
+ isPersonal?: boolean;
122
136
  voice: AgentVoice;
123
137
  transcriber: AgentTranscriber;
124
138
  model: AgentModel;
@@ -151,19 +165,22 @@ interface Agent {
151
165
  * right gateway.
152
166
  */
153
167
  transport?: 'ws' | 'webrtc';
154
- /** Whether this agent may host multi-party video rooms. */
155
- canHostRooms?: boolean;
156
- /** Room operating mode (`'notes-only'` today). */
168
+ /** Room operating mode (`'notes-only'` today). Only set on `type: 'room'` agents. */
157
169
  roomMode?: 'notes-only';
158
- /** Transcribe-only mode — the agent listens but never speaks. */
159
- transcribeOnly?: boolean;
160
170
  createdAt: number;
161
171
  updatedAt: number;
162
172
  }
163
173
  interface AgentCreateInput {
174
+ /**
175
+ * Agent kind — see {@link AgentType}. Required and immutable: it cannot be
176
+ * changed via {@link AgentUpdateInput} (it is omitted from that type).
177
+ */
178
+ type: AgentType;
164
179
  name: string;
165
180
  systemPrompt: string;
166
181
  agentSpeaksFirst?: boolean;
182
+ /** Personal assistant (`assistant` agents only) — the learning tools are live on every `ct_`-token call, not just `mode=learning`. */
183
+ isPersonal?: boolean;
167
184
  voice?: AgentVoice;
168
185
  transcriber?: AgentTranscriber;
169
186
  model?: AgentModel;
@@ -185,26 +202,18 @@ interface AgentCreateInput {
185
202
  */
186
203
  avatarUrl?: string;
187
204
  /**
188
- * Let this agent host multi-party video rooms. Off by default. Required
189
- * (`true`) before `client.rooms.create({ agentId })` will accept the agent.
190
- */
191
- canHostRooms?: boolean;
192
- /**
193
- * Room operating mode. Today only `'notes-only'` exists — the agent listens
194
- * and takes structured notes without speaking. A literal union so future
195
- * modes can be added without breaking the wire.
205
+ * Room operating mode. Only valid on `type: 'room'` agents. Today only
206
+ * `'notes-only'` exists the agent listens and takes structured notes
207
+ * without speaking. A literal union so future modes can be added without
208
+ * breaking the wire.
196
209
  */
197
210
  roomMode?: 'notes-only';
198
- /**
199
- * Transcribe-only mode. When `true`, the agent listens but never speaks: no
200
- * TTS/LLM, no greeting, idle nudges suppressed, user turns are not routed
201
- * through the LLM — an STT-only loop that streams `transcript` data-messages
202
- * back to the caller. `voice` stays required by the schema (defaults apply)
203
- * but is never read at runtime.
204
- */
205
- transcribeOnly?: boolean;
206
211
  }
207
- type AgentUpdateInput = Partial<AgentCreateInput>;
212
+ /**
213
+ * Patch shape for `agents.update`. `type` is immutable, so it is omitted
214
+ * here — to change an agent's kind, create a new agent.
215
+ */
216
+ type AgentUpdateInput = Partial<Omit<AgentCreateInput, 'type'>>;
208
217
  /**
209
218
  * Trimmed agent shape returned by the consumer catalog
210
219
  * (`GET /v1/orgs/:orgId/agents`). Operator-only fields like
@@ -390,9 +399,9 @@ interface CallTokenMintInput {
390
399
  initiatedBy?: 'user' | 'agent';
391
400
  /**
392
401
  * Session channel selector. `voice` (default) routes to WS/WebRTC audio;
393
- * `text` routes to HTTP+SSE chat via the `chats` resource. Rejected at
394
- * mint when the agent has `transcribeOnly: true` or when `mode: 'learning'`
395
- * is supplied.
402
+ * `text` routes to HTTP+SSE chat via the `chats` resource. `text` requires
403
+ * a `type: 'assistant'` agent; non-assistant agents are rejected at mint
404
+ * (`wrong_agent_type`), as is `mode: 'learning'` on a non-assistant agent.
396
405
  */
397
406
  channel?: 'voice' | 'text';
398
407
  /**
@@ -437,7 +446,7 @@ interface CallTokenSummary {
437
446
  revoked: boolean;
438
447
  allowedOrigins?: string[];
439
448
  }
440
- type PlatformEventName = 'call.started' | 'call.ended' | 'transcript.updated' | 'call.summary.ready' | 'tool.call.requested' | 'tool.call.completed' | 'tool.call.failed' | 'credits.low';
449
+ type PlatformEventName = 'call.started' | 'call.ended' | 'transcript.updated' | 'call.summary.ready' | 'tool.call.requested' | 'tool.call.completed' | 'tool.call.failed' | 'credits.low' | 'speech.ready' | 'speech.failed';
441
450
  interface WebhookConfig {
442
451
  webhookId: string;
443
452
  orgId: string;
@@ -491,6 +500,17 @@ interface CreateRoomInput {
491
500
  agentId: string;
492
501
  /** 1..240 — enforced by the server. */
493
502
  durationMin: number;
503
+ /**
504
+ * Document references forwarded to the room analyzer. Each `docId` is an
505
+ * analysis document (`adoc_…`) uploaded via `POST /v1/analysis-docs` (NOT a
506
+ * knowledge-base file), tagged with an optional semantic role (e.g. `'jd'`,
507
+ * `'cv'`); the worker loads the full text and injects it into the analyzer.
508
+ * Omit when the room agent uses its default analysis behaviour.
509
+ */
510
+ analysisContext?: Array<{
511
+ docId: string;
512
+ role?: string;
513
+ }>;
494
514
  }
495
515
  interface CreateRoomResponse {
496
516
  roomId: string;
@@ -553,6 +573,24 @@ interface ListUtterancesResponse {
553
573
  utterances: UtteranceWire[];
554
574
  nextCursor: string | null;
555
575
  }
576
+ interface AnalysisWire {
577
+ analysisId: string;
578
+ participantId: string;
579
+ label: string;
580
+ score?: number;
581
+ note?: string;
582
+ createdAt: string;
583
+ /**
584
+ * Which producer emitted this result: `'summary'` | `'rated_dimensions'` |
585
+ * `'suggested_questions'`. Set by the worker on every result it produces;
586
+ * absent only on legacy analysis entries written before producers existed.
587
+ */
588
+ producer?: string;
589
+ }
590
+ interface ListAnalysisResponse {
591
+ analysis: AnalysisWire[];
592
+ nextCursor: string | null;
593
+ }
556
594
  /** Returned by host-action endpoints (`/end` and friends) — 202 + eventId so
557
595
  * callers can correlate the async system-message broadcast that follows. */
558
596
  interface RoomEventAck {
@@ -589,6 +627,105 @@ type ChatEvent = {
589
627
  code: string;
590
628
  message: string;
591
629
  };
630
+ type SpaceKind = 'audio' | 'video';
631
+ type RecordingMode = 'off' | 'host-source' | 'composite';
632
+ interface RecordingConfig {
633
+ mode: RecordingMode;
634
+ maxMinutesPerSession?: number;
635
+ audioOnly?: boolean;
636
+ }
637
+ /** The redacted space shape the server returns (`toSpaceView`). */
638
+ interface SpaceView {
639
+ spaceId: string;
640
+ agentId: string;
641
+ /** Stable human-friendly join code, e.g. `abc-defg-hij`. */
642
+ code: string;
643
+ kind: SpaceKind;
644
+ notesEnabled: boolean;
645
+ lobbyEnabled: boolean;
646
+ recording: RecordingConfig;
647
+ active: boolean;
648
+ currentSessionId: string | null;
649
+ sessionCount: number;
650
+ createdAt: string;
651
+ updatedAt: string;
652
+ }
653
+ interface CreateSpaceInput {
654
+ agentId: string;
655
+ /** Defaults to `video` server-side. */
656
+ kind?: SpaceKind;
657
+ /** Defaults to `true` server-side. */
658
+ notesEnabled?: boolean;
659
+ /** Defaults to `false` server-side. */
660
+ lobbyEnabled?: boolean;
661
+ recording?: RecordingConfig;
662
+ }
663
+ /** At least one field is required — the server rejects an empty patch. */
664
+ interface SpacePatch {
665
+ notesEnabled?: boolean;
666
+ lobbyEnabled?: boolean;
667
+ active?: boolean;
668
+ recording?: RecordingConfig;
669
+ }
670
+ interface ListSpacesResponse {
671
+ data: SpaceView[];
672
+ }
673
+ interface SpeechSynthesizeInput {
674
+ agentId: string;
675
+ text?: string;
676
+ context?: Record<string, unknown>;
677
+ instructions?: string;
678
+ format?: 'mp3' | 'wav' | 'ogg';
679
+ sampleRate?: 16000 | 24000 | 48000;
680
+ idempotencyKey?: string;
681
+ userTags?: string[];
682
+ ttlSeconds?: number;
683
+ metadata?: Record<string, string>;
684
+ }
685
+ interface SpeechAsset {
686
+ id: string;
687
+ status: 'ready';
688
+ url: string;
689
+ expiresAt: string;
690
+ durationMs: number;
691
+ bytes: number;
692
+ format: 'mp3' | 'wav' | 'ogg';
693
+ sampleRate: number;
694
+ text: string;
695
+ agentId: string;
696
+ idempotencyKey?: string;
697
+ metadata?: Record<string, string>;
698
+ createdAt: string;
699
+ }
700
+ interface SpeechJob {
701
+ id: string;
702
+ status: 'queued' | 'processing' | 'failed';
703
+ error?: {
704
+ code: string;
705
+ message: string;
706
+ };
707
+ idempotencyKey?: string;
708
+ metadata?: Record<string, string>;
709
+ createdAt: string;
710
+ }
711
+ interface SpeechListInput {
712
+ idempotencyKeyPrefix?: string;
713
+ status?: 'queued' | 'processing' | 'ready' | 'failed';
714
+ limit?: number;
715
+ cursor?: string;
716
+ }
717
+ interface SpeechReadyEvent {
718
+ event: 'speech.ready';
719
+ timestamp: string;
720
+ orgId: string;
721
+ data: SpeechAsset;
722
+ }
723
+ interface SpeechFailedEvent {
724
+ event: 'speech.failed';
725
+ timestamp: string;
726
+ orgId: string;
727
+ data: SpeechJob;
728
+ }
592
729
 
593
730
  declare const createMeResource: (http: HttpClient) => {
594
731
  get: () => Promise<MeResponse>;
@@ -730,10 +867,38 @@ declare const createRoomsResource: (http: HttpClient) => {
730
867
  list: (filters?: RoomListFilters) => Promise<ListRoomsResponse>;
731
868
  get: (roomId: string) => Promise<RoomDoc>;
732
869
  transcript: (roomId: string, opts?: RoomTranscriptOptions) => Promise<ListUtterancesResponse>;
870
+ analysis: (roomId: string, opts?: RoomTranscriptOptions) => Promise<ListAnalysisResponse>;
733
871
  end: (roomId: string) => Promise<RoomEventAck>;
734
872
  };
735
873
  type RoomsResource = ReturnType<typeof createRoomsResource>;
736
874
 
875
+ type JoinUrlStyle = 'query' | 'path';
876
+ interface BuildJoinUrlOptions {
877
+ /** Required — the developer's own page that renders <VoiceRoom/>. Absolute URL. */
878
+ baseUrl: string;
879
+ /** 'query' (default) → ?code=… · 'path' → /… */
880
+ style?: JoinUrlStyle;
881
+ }
882
+ /**
883
+ * Build a participant join URL on the DEVELOPER's domain from a space (or a
884
+ * raw code). White-label: the returned URL never points at a voissia origin —
885
+ * `baseUrl` is required and supplied by the caller.
886
+ *
887
+ * The default `query` style appends `?code=<code>`, matching how
888
+ * `<VoiceRoom/>` (and the example app) read the code from the URL.
889
+ */
890
+ declare const buildJoinUrl: (spaceOrCode: SpaceView | string, opts: BuildJoinUrlOptions) => string;
891
+
892
+ declare const createSpacesResource: (http: HttpClient) => {
893
+ create: (input: CreateSpaceInput) => Promise<SpaceView>;
894
+ get: (spaceId: string) => Promise<SpaceView>;
895
+ list: () => Promise<ListSpacesResponse>;
896
+ update: (spaceId: string, patch: SpacePatch) => Promise<SpaceView>;
897
+ delete: (spaceId: string) => Promise<void>;
898
+ joinUrl: (spaceOrCode: SpaceView | string, opts: BuildJoinUrlOptions) => string;
899
+ };
900
+ type SpacesResource = ReturnType<typeof createSpacesResource>;
901
+
737
902
  interface StartChatInput {
738
903
  agentId: string;
739
904
  text?: string;
@@ -759,6 +924,32 @@ declare const createChatsResource: (http: HttpClient, callToken: string) => {
759
924
  };
760
925
  type ChatsResource = ReturnType<typeof createChatsResource>;
761
926
 
927
+ declare const createSpeechResource: (http: HttpClient) => {
928
+ /**
929
+ * Synchronous. Resolves with the ready asset. Throws PlatformError
930
+ * code 'accepted' (status 202, `body` = SpeechJob) when the server hands
931
+ * the job to the queue instead — poll `get(job.id)` or wait for the
932
+ * `speech.ready` webhook.
933
+ */
934
+ synthesize: (input: SpeechSynthesizeInput) => Promise<SpeechAsset>;
935
+ /**
936
+ * Asynchronous. Normally returns a queued/processing SpeechJob —
937
+ * completion arrives via the `speech.ready` / `speech.failed` webhook or
938
+ * a later `get(job.id)`. Exception: when `idempotencyKey` matches an
939
+ * existing *ready* asset, the server short-circuits the queue hop and
940
+ * responds 200 with that SpeechAsset directly instead of 202.
941
+ */
942
+ enqueue: (input: SpeechSynthesizeInput) => Promise<SpeechJob | SpeechAsset>;
943
+ get: (id: string) => Promise<SpeechAsset | SpeechJob>;
944
+ list: (input?: SpeechListInput) => Promise<{
945
+ items: Array<SpeechAsset | SpeechJob>;
946
+ cursor?: string;
947
+ }>;
948
+ /** Idempotent. Deleting a ready asset invalidates its URL immediately. */
949
+ delete: (id: string) => Promise<void>;
950
+ };
951
+ type SpeechResource = ReturnType<typeof createSpeechResource>;
952
+
762
953
  interface PlatformClientOptions {
763
954
  apiKey: string;
764
955
  baseUrl?: string;
@@ -777,6 +968,8 @@ declare class PlatformClient {
777
968
  readonly webhooks: WebhooksResource;
778
969
  readonly orgs: OrgsResource;
779
970
  readonly rooms: RoomsResource;
971
+ readonly spaces: SpacesResource;
972
+ readonly speech: SpeechResource;
780
973
  private readonly _http;
781
974
  constructor(options: PlatformClientOptions);
782
975
  /**
@@ -791,7 +984,7 @@ declare class PlatformClient {
791
984
  chatsFor(callToken: string): ChatsResource;
792
985
  }
793
986
 
794
- type ApiErrorCode = 'unauthorized' | 'forbidden' | 'not_found' | 'bad_request' | 'conflict' | 'rate_limited' | 'payment_required' | 'internal_error' | 'unknown';
987
+ type ApiErrorCode = 'unauthorized' | 'forbidden' | 'not_found' | 'bad_request' | 'conflict' | 'rate_limited' | 'payment_required' | 'internal_error' | 'accepted' | 'service_unavailable' | 'unknown';
795
988
  declare class PlatformError extends Error {
796
989
  readonly code: ApiErrorCode;
797
990
  readonly status: number;
@@ -811,4 +1004,4 @@ declare class PlatformError extends Error {
811
1004
 
812
1005
  declare const verifyWebhookSignature: (rawBody: Buffer | string, signatureHeader: string, secret: string) => boolean;
813
1006
 
814
- export { type Agent, type AgentCreateInput, type AgentEndpointing, type AgentHttpTool, type AgentModel, type AgentRecording, type AgentTool, type AgentTranscriber, type AgentUpdateInput, type AgentVoice, type AgentWebhooksResource, type AgentsResource, type ApiErrorCode, type CallListFilters, type CallRecord, type CallRecordingUrlResponse, type CallStatus, type CallSummary, type CallTokenMintInput, type CallTokenMintResult, type CallTokenSummary, type CallTokensResource, type CallsResource, type CatalogAgent, type CatalogListInput, type Chat, type ChatEvent, type ChatsResource, type CostBreakdown, type CreateRoomInput, type CreateRoomResponse, type CreditsResource, type EndReason, type EndpointingMode, type GuestRole, type KnowledgeBase, type KnowledgeBaseFile, type KnowledgeBasesResource, type LedgerEntry, type ListRoomsResponse, type ListUtterancesResponse, type LlmProvider, type MeResource, type MeResponse, type OrgsResource, PlatformClient, type PlatformClientOptions, PlatformError, type PlatformEventName, type RecordingMeta, type RoomDoc, type RoomEndReason, type RoomEventAck, type RoomListFilters, type RoomMetricsWire, type RoomStatus, type RoomTranscriptOptions, type RoomsResource, type StartChatInput, type SttProvider, type TranscriptTurn, type TtsProvider, type UtteranceWire, type WebhookConfig, type WebhookCreateInput, type WebhookDelivery, type WebhookUpdateInput, type WebhooksResource, type WorkerStatus, verifyWebhookSignature };
1007
+ export { type Agent, type AgentCreateInput, type AgentEndpointing, type AgentHttpTool, type AgentModel, type AgentRecording, type AgentTool, type AgentTranscriber, type AgentType, type AgentUpdateInput, type AgentVoice, type AgentWebhooksResource, type AgentsResource, type AnalysisWire, type ApiErrorCode, type BuildJoinUrlOptions, type CallListFilters, type CallRecord, type CallRecordingUrlResponse, type CallStatus, type CallSummary, type CallTokenMintInput, type CallTokenMintResult, type CallTokenSummary, type CallTokensResource, type CallsResource, type CatalogAgent, type CatalogListInput, type Chat, type ChatEvent, type ChatsResource, type CostBreakdown, type CreateRoomInput, type CreateRoomResponse, type CreateSpaceInput, type CreditsResource, type EndReason, type EndpointingMode, type GuestRole, type JoinUrlStyle, type KnowledgeBase, type KnowledgeBaseFile, type KnowledgeBasesResource, type LedgerEntry, type ListAnalysisResponse, type ListRoomsResponse, type ListSpacesResponse, type ListUtterancesResponse, type LlmProvider, type MeResource, type MeResponse, type OrgsResource, PlatformClient, type PlatformClientOptions, PlatformError, type PlatformEventName, type RecordingConfig, type RecordingMeta, type RecordingMode, type RoomDoc, type RoomEndReason, type RoomEventAck, type RoomListFilters, type RoomMetricsWire, type RoomStatus, type RoomTranscriptOptions, type RoomsResource, type SpaceKind, type SpacePatch, type SpaceView, type SpacesResource, type SpeechAsset, type SpeechFailedEvent, type SpeechJob, type SpeechListInput, type SpeechReadyEvent, type SpeechResource, type SpeechSynthesizeInput, type StartChatInput, type SttProvider, type TranscriptTurn, type TtsProvider, type UtteranceWire, type WebhookConfig, type WebhookCreateInput, type WebhookDelivery, type WebhookUpdateInput, type WebhooksResource, type WorkerStatus, buildJoinUrl, verifyWebhookSignature };
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  PlatformClient: () => PlatformClient,
34
34
  PlatformError: () => PlatformError,
35
+ buildJoinUrl: () => buildJoinUrl,
35
36
  verifyWebhookSignature: () => verifyWebhookSignature
36
37
  });
37
38
  module.exports = __toCommonJS(index_exports);
@@ -599,6 +600,19 @@ var createRoomsResource = (http) => ({
599
600
  query
600
601
  });
601
602
  },
603
+ // Analysis pages — analyzer results ordered by createdAt asc. Auth-only
604
+ // (org-scoped); there is no public token-gated variant. Cursor is an ISO
605
+ // timestamp the server enforces — don't construct it yourself.
606
+ analysis: async (roomId, opts = {}) => {
607
+ const query = {};
608
+ if (opts.cursor) query.cursor = opts.cursor;
609
+ if (opts.limit !== void 0) query.limit = opts.limit;
610
+ return http.request({
611
+ method: "GET",
612
+ path: `/v1/rooms/${roomId}/analysis`,
613
+ query
614
+ });
615
+ },
602
616
  // End a room — async on the server: returns 202 + eventId once the
603
617
  // controlEvents entry is written. The room-worker observes the entry,
604
618
  // broadcasts the system message, and tears down LiveKit shortly after.
@@ -608,6 +622,63 @@ var createRoomsResource = (http) => ({
608
622
  })
609
623
  });
610
624
 
625
+ // src/joinUrl.ts
626
+ var buildJoinUrl = (spaceOrCode, opts) => {
627
+ const code = typeof spaceOrCode === "string" ? spaceOrCode : spaceOrCode.code;
628
+ if (!code) throw new Error("a space code is required");
629
+ const base = opts.baseUrl?.trim();
630
+ if (!base) throw new Error("baseUrl is required");
631
+ let url;
632
+ try {
633
+ url = new URL(base);
634
+ } catch {
635
+ throw new Error("baseUrl must be an absolute URL (e.g. https://app.example.com/room)");
636
+ }
637
+ if ((opts.style ?? "query") === "path") {
638
+ url.pathname = `${url.pathname.replace(/\/+$/, "")}/${encodeURIComponent(code)}`;
639
+ } else {
640
+ url.searchParams.set("code", code);
641
+ }
642
+ return url.toString();
643
+ };
644
+
645
+ // src/resources/spaces.ts
646
+ var createSpacesResource = (http) => ({
647
+ // Create a durable space. Server returns 201 with the SpaceView, including a
648
+ // stable `code` participants join with. Pass it to `joinUrl` (or the
649
+ // standalone `buildJoinUrl`) to make a link on YOUR domain.
650
+ create: async (input) => http.request({
651
+ method: "POST",
652
+ path: "/v1/spaces",
653
+ body: input
654
+ }),
655
+ get: async (spaceId) => http.request({
656
+ method: "GET",
657
+ path: `/v1/spaces/${spaceId}`
658
+ }),
659
+ // List every space for the org. Plain `{ data: [...] }` — no cursor.
660
+ list: async () => http.request({
661
+ method: "GET",
662
+ path: "/v1/spaces"
663
+ }),
664
+ // Patch a space. The server rejects an empty patch — pass at least one field.
665
+ update: async (spaceId, patch) => http.request({
666
+ method: "PATCH",
667
+ path: `/v1/spaces/${spaceId}`,
668
+ body: patch
669
+ }),
670
+ // Delete a space. Resolves once the server returns 204.
671
+ delete: async (spaceId) => {
672
+ await http.request({
673
+ method: "DELETE",
674
+ path: `/v1/spaces/${spaceId}`
675
+ });
676
+ },
677
+ // Convenience: build a participant join URL on your domain from a space (or
678
+ // raw code). Delegates to the standalone `buildJoinUrl` export.
679
+ joinUrl: (spaceOrCode, opts) => buildJoinUrl(spaceOrCode, opts)
680
+ });
681
+
611
682
  // src/resources/chats.ts
612
683
  var createChatsResource = (http, callToken) => ({
613
684
  async start(input) {
@@ -653,6 +724,70 @@ async function* replayThen(buffered, rest) {
653
724
  for await (const x of rest) yield x;
654
725
  }
655
726
 
727
+ // src/resources/speech.ts
728
+ var SYNTHESIZE_TIMEOUT_MS = 9e4;
729
+ var createSpeechResource = (http) => {
730
+ const speech = {
731
+ /**
732
+ * Synchronous. Resolves with the ready asset. Throws PlatformError
733
+ * code 'accepted' (status 202, `body` = SpeechJob) when the server hands
734
+ * the job to the queue instead — poll `get(job.id)` or wait for the
735
+ * `speech.ready` webhook.
736
+ */
737
+ synthesize: async (input) => {
738
+ const res = await http.request({
739
+ method: "POST",
740
+ path: "/v1/speech",
741
+ body: input,
742
+ // The server's own sync budget is 60s, after which it hands the job
743
+ // to the queue and answers 202. The default 30s client timeout would
744
+ // abort first — turning a perfectly good handoff into a network
745
+ // error — so give the server room to answer.
746
+ timeoutMs: SYNTHESIZE_TIMEOUT_MS
747
+ });
748
+ if (res.status === "ready") return res;
749
+ if (res.status === "failed") {
750
+ throw new PlatformError({
751
+ code: "internal_error",
752
+ message: res.error?.message ?? "Speech synthesis failed",
753
+ status: 200,
754
+ body: res
755
+ });
756
+ }
757
+ throw new PlatformError({
758
+ code: "accepted",
759
+ message: `Speech job ${res.id} accepted; poll speech.get() or await the speech.ready webhook`,
760
+ status: 202,
761
+ body: res
762
+ });
763
+ },
764
+ /**
765
+ * Asynchronous. Normally returns a queued/processing SpeechJob —
766
+ * completion arrives via the `speech.ready` / `speech.failed` webhook or
767
+ * a later `get(job.id)`. Exception: when `idempotencyKey` matches an
768
+ * existing *ready* asset, the server short-circuits the queue hop and
769
+ * responds 200 with that SpeechAsset directly instead of 202.
770
+ */
771
+ enqueue: async (input) => http.request({
772
+ method: "POST",
773
+ path: "/v1/speech",
774
+ query: { async: 1 },
775
+ body: input
776
+ }),
777
+ get: async (id) => http.request({ method: "GET", path: `/v1/speech/${id}` }),
778
+ list: async (input = {}) => http.request({
779
+ method: "GET",
780
+ path: "/v1/speech",
781
+ query: input
782
+ }),
783
+ /** Idempotent. Deleting a ready asset invalidates its URL immediately. */
784
+ delete: async (id) => {
785
+ await http.request({ method: "DELETE", path: `/v1/speech/${id}` });
786
+ }
787
+ };
788
+ return speech;
789
+ };
790
+
656
791
  // src/PlatformClient.ts
657
792
  var PlatformClient = class {
658
793
  me;
@@ -664,6 +799,8 @@ var PlatformClient = class {
664
799
  webhooks;
665
800
  orgs;
666
801
  rooms;
802
+ spaces;
803
+ speech;
667
804
  _http;
668
805
  constructor(options) {
669
806
  if (!options.apiKey) {
@@ -686,6 +823,8 @@ var PlatformClient = class {
686
823
  this.webhooks = createWebhooksResource(http);
687
824
  this.orgs = createOrgsResource(http);
688
825
  this.rooms = createRoomsResource(http);
826
+ this.spaces = createSpacesResource(http);
827
+ this.speech = createSpeechResource(http);
689
828
  this._http = http;
690
829
  }
691
830
  /**
@@ -718,6 +857,7 @@ var verifyWebhookSignature = (rawBody, signatureHeader, secret) => {
718
857
  0 && (module.exports = {
719
858
  PlatformClient,
720
859
  PlatformError,
860
+ buildJoinUrl,
721
861
  verifyWebhookSignature
722
862
  });
723
863
  //# sourceMappingURL=index.js.map