@decartai/sdk 0.1.13 → 0.1.15

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.
Files changed (53) hide show
  1. package/README.md +109 -10
  2. package/dist/create-client.d.ts +46 -0
  3. package/dist/create-client.js +208 -0
  4. package/dist/files/types.js +4 -1
  5. package/dist/index.d.ts +8 -150
  6. package/dist/index.js +6 -116
  7. package/dist/index.react-native.d.ts +36 -0
  8. package/dist/index.react-native.js +9 -0
  9. package/dist/package.js +4 -0
  10. package/dist/process/types.d.ts +2 -2
  11. package/dist/realtime/browser/frame-metadata-diagnostics.js +90 -0
  12. package/dist/realtime/browser/frame-metadata-worker.js +2 -0
  13. package/dist/realtime/browser/index.js +32 -0
  14. package/dist/realtime/{mirror-stream.js → browser/mirror-stream.js} +2 -2
  15. package/dist/realtime/{preflight.js → browser/preflight.js} +20 -115
  16. package/dist/realtime/browser/prepare-connection.js +57 -0
  17. package/dist/realtime/client.d.ts +11 -4
  18. package/dist/realtime/client.js +42 -37
  19. package/dist/realtime/config-realtime.js +51 -0
  20. package/dist/realtime/livekit.js +26 -0
  21. package/dist/realtime/media-channel.js +40 -11
  22. package/dist/realtime/methods.d.ts +1 -1
  23. package/dist/realtime/methods.js +7 -2
  24. package/dist/realtime/observability/connection-quality.d.ts +3 -3
  25. package/dist/realtime/observability/connection-quality.js +3 -1
  26. package/dist/realtime/observability/g2g.d.ts +14 -0
  27. package/dist/realtime/observability/realtime-observability.js +8 -32
  28. package/dist/realtime/observability/webrtc-stats.d.ts +4 -4
  29. package/dist/realtime/preflight-connectivity.js +102 -0
  30. package/dist/realtime/preflight-types.d.ts +30 -0
  31. package/dist/realtime/react-native/index.js +36 -0
  32. package/dist/realtime/react-native/preflight.js +10 -0
  33. package/dist/realtime/react-native/prepare-connection.js +26 -0
  34. package/dist/realtime/signaling-channel.js +3 -1
  35. package/dist/realtime/stream-session.js +5 -4
  36. package/dist/realtime/subscribe-client.js +11 -10
  37. package/dist/shared/model.d.ts +56 -37
  38. package/dist/shared/model.js +61 -18
  39. package/dist/shared/request.js +5 -4
  40. package/dist/shared/types.d.ts +2 -2
  41. package/dist/shared/types.js +9 -2
  42. package/dist/utils/errors.d.ts +3 -0
  43. package/dist/utils/errors.js +16 -1
  44. package/dist/utils/media.js +1 -1
  45. package/dist/utils/platform.js +17 -1
  46. package/dist/utils/runtime.js +13 -0
  47. package/dist/utils/user-agent.js +1 -1
  48. package/dist/version.js +9 -4
  49. package/package.json +10 -3
  50. package/dist/realtime/observability/glass-to-glass.d.ts +0 -41
  51. package/dist/realtime/observability/glass-to-glass.js +0 -229
  52. package/dist/realtime/observability/pixel-marker.js +0 -144
  53. package/dist/realtime/preflight.d.ts +0 -59
package/README.md CHANGED
@@ -164,23 +164,38 @@ realtimeClient.on("connectionQuality", (report) => { /* ... */ });
164
164
  realtimeClient.getConnectionQuality(); // latest report, or null before the first sample
165
165
  ```
166
166
 
167
+ > `onConnectionQuality` and the `connectionQuality` event are **debounced** — they only re-fire
168
+ > when the verdict (`quality`/`limitingFactor`) changes, so they're not a live metrics feed. For a
169
+ > continuous read of the raw numbers, updated every stats tick (~1/s), use the `stats` event or
170
+ > poll `getConnectionQuality()?.metrics`:
171
+ >
172
+ > ```typescript
173
+ > realtimeClient.on("stats", (s) => updateLatencyHud(s.glassToGlass?.medianMs, s.video?.framesPerSecond));
174
+ > // or, on your own interval:
175
+ > setInterval(() => console.log(realtimeClient.getConnectionQuality()?.metrics.g2gMs), 1000);
176
+ > ```
177
+
167
178
  **Glass-to-glass latency (opt-in, diagnostic).** Network RTT hides the dominant cost in
168
179
  real-time video — model inference — so a session can read "good" while actually feeling laggy.
169
- Set `debugQuality: true` to measure the *real* camera→display latency: the SDK stamps a pixel
170
- marker into each outgoing frame and reads it back off the rendered output, surfacing **startup**
171
- (`ttffMs`) and **steady-state** (`g2gMs`) latency plus end-to-end frame drops (`g2gDropRatio`).
172
- When present, glass-to-glass drives the latency verdict instead of RTT.
180
+ Set `debugQuality: true` to measure the *real* camera→display latency. The SDK attaches a capture
181
+ timestamp using LiveKit frame metadata; the server propagates it through inference and the SDK
182
+ matches it to output playout. This surfaces **startup** (`ttffMs`) and **steady-state**
183
+ (`g2gMs`) latency. When present, glass-to-glass drives the latency verdict instead of RTT.
173
184
 
174
- > ⚠️ Diagnostic only. The marker is **visible** (bottom-left of the published and rendered video)
175
- > and adds per-frame pixel work — don't enable it for production / end-user sessions.
185
+ > Frame metadata is currently experimental in LiveKit and requires encoded-transform support.
186
+ > It does not alter visible pixels. `g2gDropRatio` remains `null` until frame IDs are propagated
187
+ > through the server pipeline as well as timestamps.
176
188
 
177
189
  ```typescript
178
190
  const realtimeClient = await client.realtime.connect(stream, {
179
191
  model,
180
192
  debugQuality: true,
181
- onConnectionQuality: ({ quality, metrics }) => {
182
- console.log(metrics.ttffMs, metrics.g2gMs, metrics.g2gDropRatio);
183
- },
193
+ });
194
+
195
+ // g2g updates every stats tick — read it from the `stats` event (the
196
+ // `connectionQuality` verdict is debounced and would go stale between changes):
197
+ realtimeClient.on("stats", ({ glassToGlass }) => {
198
+ console.log(glassToGlass?.ttffMs, glassToGlass?.medianMs);
184
199
  });
185
200
  ```
186
201
 
@@ -243,6 +258,90 @@ if (status.status === "completed") {
243
258
  }
244
259
  ```
245
260
 
261
+ ### React Native / Expo
262
+
263
+ React Native realtime requires [LiveKit's React Native packages](https://github.com/livekit/client-sdk-react-native)
264
+ and an early `registerGlobals()` call. Plain `react-native-webrtc` is not
265
+ supported. SDK imports and `createDecartClient(...)` usage stay the same.
266
+
267
+ ```sh
268
+ npm install @decartai/sdk livekit-client@2.20.1 \
269
+ @livekit/react-native@2.11.1 \
270
+ @livekit/react-native-webrtc@144.1.1
271
+ ```
272
+
273
+ Call LiveKit setup from a side-effect module that runs before your router or app
274
+ entrypoint:
275
+
276
+ ```ts
277
+ // livekit-bootstrap.ts
278
+ import { registerGlobals } from "@livekit/react-native";
279
+
280
+ registerGlobals();
281
+ ```
282
+
283
+ ```ts
284
+ // index.ts
285
+ import "./livekit-bootstrap";
286
+ import "expo-router/entry"; // or import your root App component
287
+ ```
288
+
289
+ With the globals registered, realtime usage is the same as on the web. Use the
290
+ model's numeric FPS when configuring native camera capture, then pass that
291
+ `MediaStream` to the SDK:
292
+
293
+ ```ts
294
+ import { createDecartClient, models, resolveFpsNumber } from "@decartai/sdk";
295
+ import { mediaDevices } from "@livekit/react-native-webrtc";
296
+
297
+ const client = createDecartClient({ apiKey: "your-api-key-here" });
298
+ const model = models.realtime("lucy-2.5");
299
+ const captureFps = resolveFpsNumber(model.fps);
300
+
301
+ const cameraStream = await mediaDevices.getUserMedia({
302
+ audio: false,
303
+ video: {
304
+ facingMode: "user",
305
+ frameRate: captureFps,
306
+ width: model.width,
307
+ height: model.height,
308
+ },
309
+ });
310
+
311
+ const realtimeClient = await client.realtime.connect(cameraStream, {
312
+ model,
313
+ preferredVideoCodec: "vp8",
314
+ onRemoteStream,
315
+ });
316
+ ```
317
+
318
+ For Expo, install the config plugins:
319
+
320
+ ```sh
321
+ npm install @livekit/react-native-expo-plugin@1.0.2 \
322
+ @config-plugins/react-native-webrtc
323
+ ```
324
+
325
+ Add them to `app.json`:
326
+
327
+ ```json
328
+ {
329
+ "expo": {
330
+ "plugins": [
331
+ "@livekit/react-native-expo-plugin",
332
+ "@config-plugins/react-native-webrtc"
333
+ ]
334
+ }
335
+ }
336
+ ```
337
+
338
+ Run `npx expo prebuild` and rebuild the native app. LiveKit does not run in Expo
339
+ Go. Bare React Native apps must follow LiveKit's native setup instructions.
340
+
341
+ Outgoing `mirror`, `debugQuality`, and deep connectivity preflight are browser-only
342
+ and fail with `UNSUPPORTED_PLATFORM_FEATURE` on React Native. Mirror the local
343
+ preview with your native video view instead.
344
+
246
345
  ## Development
247
346
 
248
347
  ### Setup
@@ -273,4 +372,4 @@ The package is published to npm as `@decartai/sdk`.
273
372
 
274
373
  ## License
275
374
 
276
- MIT
375
+ MIT
@@ -0,0 +1,46 @@
1
+ import { Logger } from "./utils/logger.js";
2
+
3
+ //#region src/create-client.d.ts
4
+ type DecartClientOptions = {
5
+ proxy: string;
6
+ apiKey?: never;
7
+ baseUrl?: string;
8
+ realtimeBaseUrl?: string;
9
+ integration?: string;
10
+ logger?: Logger;
11
+ telemetry?: boolean;
12
+ } | {
13
+ proxy?: never;
14
+ apiKey?: string;
15
+ baseUrl?: string;
16
+ realtimeBaseUrl?: string;
17
+ integration?: string;
18
+ logger?: Logger;
19
+ telemetry?: boolean;
20
+ };
21
+ /**
22
+ * Create a Decart API client.
23
+ *
24
+ * @param options - Configuration options
25
+ * @param options.proxy - URL of the proxy server. When set, the client will use the proxy instead of direct API access and apiKey is not required.
26
+ * @param options.apiKey - API key for authentication.
27
+ * @param options.baseUrl - Override the default API base URL.
28
+ * @param options.realtimeBaseUrl - Override the default WebSocket base URL for realtime connections.
29
+ * @param options.integration - Optional integration identifier.
30
+ *
31
+ * Realtime media uses LiveKit only (inference must enable it in `TRANSPORTS_ENABLED`).
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * // Option 1: Explicit API key (direct API access)
36
+ * const client = createDecartClient({ apiKey: "your-api-key" });
37
+ *
38
+ * // Option 2: Using DECART_API_KEY environment variable
39
+ * const client = createDecartClient();
40
+ *
41
+ * // Option 3: Using proxy (client-side, no API key needed)
42
+ * const client = createDecartClient({ proxy: "https://your-server.com/api/decart" });
43
+ * ```
44
+ */
45
+ //#endregion
46
+ export { DecartClientOptions };
@@ -0,0 +1,208 @@
1
+ import { createInvalidApiKeyError, createInvalidBaseUrlError } from "./utils/errors.js";
2
+ import { createFilesClient } from "./files/client.js";
3
+ import { createProcessClient } from "./process/client.js";
4
+ import { createQueueClient } from "./queue/client.js";
5
+ import { createTokensClient } from "./tokens/client.js";
6
+ import { readEnv } from "./utils/env.js";
7
+ import { createConsoleLogger } from "./utils/logger.js";
8
+ import { z } from "zod";
9
+ //#region src/create-client.ts
10
+ const proxySchema = z.union([z.string().url(), z.string().startsWith("/")]);
11
+ const decartClientOptionsSchema = z.object({
12
+ apiKey: z.string().min(1).optional(),
13
+ baseUrl: z.url().optional(),
14
+ proxy: proxySchema.optional(),
15
+ integration: z.string().optional(),
16
+ realtimeBaseUrl: z.url().optional()
17
+ }).refine((data) => {
18
+ const hasProxy = !!data.proxy;
19
+ const hasApiKey = !!data.apiKey;
20
+ return !(hasProxy && hasApiKey);
21
+ }, { message: "Cannot provide both 'proxy' and 'apiKey'. Use 'proxy' for proxy mode or 'apiKey' for direct API access." });
22
+ /**
23
+ * Create a Decart API client.
24
+ *
25
+ * @param options - Configuration options
26
+ * @param options.proxy - URL of the proxy server. When set, the client will use the proxy instead of direct API access and apiKey is not required.
27
+ * @param options.apiKey - API key for authentication.
28
+ * @param options.baseUrl - Override the default API base URL.
29
+ * @param options.realtimeBaseUrl - Override the default WebSocket base URL for realtime connections.
30
+ * @param options.integration - Optional integration identifier.
31
+ *
32
+ * Realtime media uses LiveKit only (inference must enable it in `TRANSPORTS_ENABLED`).
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * // Option 1: Explicit API key (direct API access)
37
+ * const client = createDecartClient({ apiKey: "your-api-key" });
38
+ *
39
+ * // Option 2: Using DECART_API_KEY environment variable
40
+ * const client = createDecartClient();
41
+ *
42
+ * // Option 3: Using proxy (client-side, no API key needed)
43
+ * const client = createDecartClient({ proxy: "https://your-server.com/api/decart" });
44
+ * ```
45
+ */
46
+ const createDecartClientForPlatform = (createRealtime, options = {}) => {
47
+ const parsedOptions = decartClientOptionsSchema.safeParse(options);
48
+ if (!parsedOptions.success) {
49
+ const issue = parsedOptions.error.issues[0];
50
+ if (issue.path.includes("apiKey")) throw createInvalidApiKeyError();
51
+ if (issue.path.includes("baseUrl") || issue.path.includes("realtimeBaseUrl")) throw createInvalidBaseUrlError(options[issue.path.includes("realtimeBaseUrl") ? "realtimeBaseUrl" : "baseUrl"]);
52
+ if (issue.path.includes("proxy")) throw createInvalidBaseUrlError(issue.path.includes("proxy") ? options.proxy : void 0);
53
+ throw parsedOptions.error;
54
+ }
55
+ const isProxyMode = "proxy" in parsedOptions.data && !!parsedOptions.data.proxy;
56
+ const apiKey = isProxyMode ? void 0 : ("apiKey" in parsedOptions.data ? parsedOptions.data.apiKey : void 0) ?? readEnv("DECART_API_KEY");
57
+ if (!isProxyMode && !apiKey) throw createInvalidApiKeyError();
58
+ let baseUrl;
59
+ if (isProxyMode && "proxy" in parsedOptions.data && parsedOptions.data.proxy) baseUrl = parsedOptions.data.proxy;
60
+ else baseUrl = parsedOptions.data.baseUrl || "https://api.decart.ai";
61
+ const { integration } = parsedOptions.data;
62
+ const logger = "logger" in options && options.logger ? options.logger : createConsoleLogger("info");
63
+ const telemetryEnabled = !("telemetry" in options && options.telemetry === false);
64
+ const wsBaseUrl = parsedOptions.data.realtimeBaseUrl || "wss://api3.decart.ai";
65
+ const realtime = createRealtime({
66
+ publishBaseUrl: wsBaseUrl,
67
+ subscribeBaseUrl: isProxyMode || parsedOptions.data.baseUrl !== void 0 ? baseUrl : wsBaseUrl.replace(/^wss?:\/\//i, "https://"),
68
+ apiKey: apiKey || "",
69
+ integration,
70
+ logger,
71
+ telemetryEnabled
72
+ });
73
+ const process = createProcessClient({
74
+ baseUrl,
75
+ apiKey: apiKey || "",
76
+ integration
77
+ });
78
+ const queue = createQueueClient({
79
+ baseUrl,
80
+ apiKey: apiKey || "",
81
+ integration
82
+ });
83
+ const tokens = createTokensClient({
84
+ baseUrl,
85
+ apiKey: apiKey || "",
86
+ integration
87
+ });
88
+ const files = createFilesClient({
89
+ baseUrl,
90
+ apiKey: apiKey || "",
91
+ integration
92
+ });
93
+ return {
94
+ realtime: {
95
+ connect: realtime.connect,
96
+ subscribe: realtime.subscribe,
97
+ /**
98
+ * Check whether the user's network can support a real-time session
99
+ * *before* connecting — so you can gate showing the integration.
100
+ *
101
+ * Default (STUN-only): validates WebRTC reachability (UDP egress / TURN
102
+ * need) and approximate latency via a throwaway peer connection — no
103
+ * session, instant. Opt-in deep probe (`{ deep: true, model }`): briefly
104
+ * opens a real session with a synthetic source and measures *true*
105
+ * glass-to-glass latency (plus upstream loss/jitter),
106
+ * then tears it down — accurate, but costs a short GPU session.
107
+ *
108
+ * @example
109
+ * ```ts
110
+ * // Fast, pre-session reachability check
111
+ * const { quality, reasons } = await client.realtime.checkConnectivity();
112
+ * if (quality === "critical") showFallbackUI(reasons);
113
+ *
114
+ * // Accurate, measured glass-to-glass verdict
115
+ * const probe = await client.realtime.checkConnectivity({ deep: true, model: models.realtime("lucy-restyle-2") });
116
+ * console.log(probe.metrics.g2gMs);
117
+ * ```
118
+ */
119
+ checkConnectivity: realtime.checkConnectivity
120
+ },
121
+ /**
122
+ * Client for synchronous image generation.
123
+ * Only image models support the sync/process API.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * const client = createDecartClient({ apiKey: "your-api-key" });
128
+ * const result = await client.process({
129
+ * model: models.image("lucy-pro-i2i"),
130
+ * prompt: "Transform into anime style",
131
+ * data: imageBlob
132
+ * });
133
+ * ```
134
+ */
135
+ process,
136
+ /**
137
+ * Client for queue-based async video generation.
138
+ * Only video models support the queue API.
139
+ * Jobs are submitted and processed asynchronously.
140
+ *
141
+ * @example
142
+ * ```ts
143
+ * const client = createDecartClient({ apiKey: "your-api-key" });
144
+ *
145
+ * // Option 1: Submit and poll automatically
146
+ * const result = await client.queue.submitAndPoll({
147
+ * model: models.video("lucy-pro-v2v"),
148
+ * prompt: "Transform into anime style",
149
+ * data: videoBlob,
150
+ * onStatusChange: (job) => console.log(`Job ${job.job_id}: ${job.status}`)
151
+ * });
152
+ *
153
+ * // Option 2: Submit and poll manually
154
+ * const job = await client.queue.submit({
155
+ * model: models.video("lucy-pro-v2v"),
156
+ * prompt: "Transform into anime style",
157
+ * data: videoBlob
158
+ * });
159
+ *
160
+ * // Poll until completion
161
+ * while (true) {
162
+ * const status = await client.queue.status(job.job_id);
163
+ * console.log(`Job ${status.job_id}: ${status.status}`);
164
+ *
165
+ * if (status.status === "completed") {
166
+ * const blob = await client.queue.result(job.job_id);
167
+ * break;
168
+ * }
169
+ * if (status.status === "failed") {
170
+ * throw new Error("Job failed");
171
+ * }
172
+ * await new Promise(resolve => setTimeout(resolve, 1500));
173
+ * }
174
+ * ```
175
+ */
176
+ queue,
177
+ /**
178
+ * Client for creating client tokens.
179
+ * Client tokens are short-lived API keys safe for client-side use.
180
+ *
181
+ * @example
182
+ * ```ts
183
+ * // Server-side: Create a client token
184
+ * const serverClient = createDecartClient({ apiKey: process.env.DECART_API_KEY });
185
+ * const token = await serverClient.tokens.create();
186
+ * // Returns: { apiKey: "ek_...", expiresAt: "2024-12-15T12:10:00Z" }
187
+ *
188
+ * // Client-side: Use the client token
189
+ * const client = createDecartClient({ apiKey: token.apiKey });
190
+ * const realtimeClient = await client.realtime.connect(stream, options);
191
+ * ```
192
+ */
193
+ tokens,
194
+ /**
195
+ * Upload files once and reuse them across generations.
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * const ref = await client.files.upload(blob);
200
+ * await rt.set({ image: ref.id, prompt: "make it cinematic" });
201
+ * await rt.set({ image: ref.id, prompt: "now in noir" });
202
+ * ```
203
+ */
204
+ files
205
+ };
206
+ };
207
+ //#endregion
208
+ export { createDecartClientForPlatform };
@@ -1,4 +1,7 @@
1
+ //#region src/files/types.ts
2
+ /** Prefix on every uploaded-file id; disambiguates a ref string from base64. */
3
+ const FILE_REF_PREFIX = "file_";
1
4
  /** True if `value` is a `"file_..."` reference id from `client.files.upload(...)`. */
2
5
  const isFileRefId = (value) => typeof value === "string" && value.startsWith("file_");
3
6
  //#endregion
4
- export { isFileRefId };
7
+ export { FILE_REF_PREFIX, isFileRefId };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import { LogLevel, Logger, createConsoleLogger, noopLogger } from "./utils/logger.js";
2
- import { CanonicalModel, CustomModelDefinition, ImageModelDefinition, ImageModels, ListedModelDefinition, Model, ModelDefinition, ModelKind, RealTimeModels, VideoModelDefinition, VideoModels, isCanonicalModel, isImageModel, isModel, isRealtimeModel, isVideoModel, listModels, modelAliases, models, resolveCanonicalModelAlias, resolveModelAlias } from "./shared/model.js";
1
+ import { CanonicalModel, CustomModelDefinition, ImageModelDefinition, ImageModels, ListedModelDefinition, Model, ModelDefinition, ModelFps, ModelKind, RealTimeModels, VideoModelDefinition, VideoModels, isCanonicalModel, isImageModel, isModel, isRealtimeModel, isVideoModel, listModels, modelAliases, models, resolveCanonicalModelAlias, resolveFpsNumber, resolveModelAlias } from "./shared/model.js";
3
2
  import { FileInput, ProcessOptions, ReactNativeFile } from "./process/types.js";
4
3
  import { FileReference, FileUploadInput } from "./files/types.js";
5
4
  import { FilesClient, UploadFileOptions } from "./files/client.js";
@@ -7,172 +6,31 @@ import { ProcessClient } from "./process/client.js";
7
6
  import { JobStatus, JobStatusResponse, JobSubmitResponse, QueueJobResult, QueueSubmitAndPollOptions, QueueSubmitOptions } from "./queue/types.js";
8
7
  import { QueueClient } from "./queue/client.js";
9
8
  import { DecartSDKError, ERROR_CODES } from "./utils/errors.js";
10
- import { G2GMetrics } from "./realtime/observability/glass-to-glass.js";
9
+ import { LogLevel, Logger, createConsoleLogger, noopLogger } from "./utils/logger.js";
10
+ import { G2GMetrics } from "./realtime/observability/g2g.js";
11
11
  import { WebRTCStats } from "./realtime/observability/webrtc-stats.js";
12
12
  import { ConnectionQuality, ConnectionQualityLimitingFactor, ConnectionQualityMetrics, ConnectionQualityReport } from "./realtime/observability/connection-quality.js";
13
13
  import { ClientSessionConnectionBreakdownEvent, ClientSessionConnectionBreakdownPhase, DiagnosticEvent, DiagnosticEventName, DiagnosticEvents, ReconnectEvent, VideoStallEvent } from "./realtime/observability/diagnostics.js";
14
14
  import { ConnectionState, GenerationEndedMessage, QueuePosition, QueuePositionMessage } from "./realtime/types.js";
15
15
  import { SetInput } from "./realtime/methods.js";
16
- import { Events, RealTimeClient, RealTimeClientConnectOptions, RealTimeClientInitialState } from "./realtime/client.js";
17
- import { CheckConnectivityOptions, ConnectivityMetrics, ConnectivityReport, ConnectivityTransport } from "./realtime/preflight.js";
16
+ import { Events, RealTimeClient, RealTimeClientConnectOptions, RealTimeClientInitialState, RealtimeMediaStream } from "./realtime/client.js";
17
+ import { CheckConnectivityOptions, ConnectivityMetrics, ConnectivityReport, ConnectivityTransport } from "./realtime/preflight-types.js";
18
18
  import { RealTimeSubscribeClient, SubscribeEvents, SubscribeOptions } from "./realtime/subscribe-client.js";
19
19
  import { ModelState } from "./shared/types.js";
20
20
  import { CreateTokenOptions, CreateTokenResponse, TokensClient } from "./tokens/client.js";
21
+ import { DecartClientOptions } from "./create-client.js";
21
22
 
22
23
  //#region src/index.d.ts
23
- type DecartClientOptions = {
24
- proxy: string;
25
- apiKey?: never;
26
- baseUrl?: string;
27
- realtimeBaseUrl?: string;
28
- integration?: string;
29
- logger?: Logger;
30
- telemetry?: boolean;
31
- } | {
32
- proxy?: never;
33
- apiKey?: string;
34
- baseUrl?: string;
35
- realtimeBaseUrl?: string;
36
- integration?: string;
37
- logger?: Logger;
38
- telemetry?: boolean;
39
- };
40
- /**
41
- * Create a Decart API client.
42
- *
43
- * @param options - Configuration options
44
- * @param options.proxy - URL of the proxy server. When set, the client will use the proxy instead of direct API access and apiKey is not required.
45
- * @param options.apiKey - API key for authentication.
46
- * @param options.baseUrl - Override the default API base URL.
47
- * @param options.realtimeBaseUrl - Override the default WebSocket base URL for realtime connections.
48
- * @param options.integration - Optional integration identifier.
49
- *
50
- * Realtime media uses LiveKit only (inference must enable it in `TRANSPORTS_ENABLED`).
51
- *
52
- * @example
53
- * ```ts
54
- * // (direct API access)Option 1: Explicit API key
55
- * const client = createDecartClient({ apiKey: "your-api-key" });
56
- *
57
- * // Option 2: Using DECART_API_KEY environment variable
58
- * const client = createDecartClient();
59
- *
60
- * // Option 3: Using proxy (client-side, no API key needed)
61
- * const client = createDecartClient({ proxy: "https://your-server.com/api/decart" });
62
- * ```
63
- */
64
24
  declare const createDecartClient: (options?: DecartClientOptions) => {
65
25
  realtime: {
66
- connect: (stream: MediaStream | null, options: RealTimeClientConnectOptions) => Promise<RealTimeClient>;
26
+ connect: <TStream extends RealtimeMediaStream = MediaStream>(stream: TStream | null, options: RealTimeClientConnectOptions<TStream>) => Promise<RealTimeClient>;
67
27
  subscribe: (options: SubscribeOptions) => Promise<RealTimeSubscribeClient>;
68
- /**
69
- * Check whether the user's network can support a real-time session
70
- * *before* connecting — so you can gate showing the integration.
71
- *
72
- * Default (STUN-only): validates WebRTC reachability (UDP egress / TURN
73
- * need) and approximate latency via a throwaway peer connection — no
74
- * session, instant. Opt-in deep probe (`{ deep: true, model }`): briefly
75
- * opens a real session with a synthetic source and measures *true*
76
- * glass-to-glass latency (and end-to-end drops / upstream loss+jitter),
77
- * then tears it down — accurate, but costs a short GPU session.
78
- *
79
- * @example
80
- * ```ts
81
- * // Fast, pre-session reachability check
82
- * const { quality, reasons } = await client.realtime.checkConnectivity();
83
- * if (quality === "critical") showFallbackUI(reasons);
84
- *
85
- * // Accurate, measured glass-to-glass verdict
86
- * const probe = await client.realtime.checkConnectivity({ deep: true, model: models.realtime("mirage") });
87
- * console.log(probe.metrics.g2gMs);
88
- * ```
89
- */
90
28
  checkConnectivity: (options?: CheckConnectivityOptions) => Promise<ConnectivityReport>;
91
29
  };
92
- /**
93
- * Client for synchronous image generation.
94
- * Only image models support the sync/process API.
95
- *
96
- * @example
97
- * ```ts
98
- * const client = createDecartClient({ apiKey: "your-api-key" });
99
- * const result = await client.process({
100
- * model: models.image("lucy-pro-i2i"),
101
- * prompt: "Transform into anime style",
102
- * data: imageBlob
103
- * });
104
- * ```
105
- */
106
30
  process: ProcessClient;
107
- /**
108
- * Client for queue-based async video generation.
109
- * Only video models support the queue API.
110
- * Jobs are submitted and processed asynchronously.
111
- *
112
- * @example
113
- * ```ts
114
- * const client = createDecartClient({ apiKey: "your-api-key" });
115
- *
116
- * // Option 1: Submit and poll automatically
117
- * const result = await client.queue.submitAndPoll({
118
- * model: models.video("lucy-pro-v2v"),
119
- * prompt: "Transform into anime style",
120
- * data: videoBlob,
121
- * onStatusChange: (job) => console.log(`Job ${job.job_id}: ${job.status}`)
122
- * });
123
- *
124
- * // Option 2: Submit and poll manually
125
- * const job = await client.queue.submit({
126
- * model: models.video("lucy-pro-v2v"),
127
- * prompt: "Transform into anime style",
128
- * data: videoBlob
129
- * });
130
- *
131
- * // Poll until completion
132
- * while (true) {
133
- * const status = await client.queue.status(job.job_id);
134
- * console.log(`Job ${status.job_id}: ${status.status}`);
135
- *
136
- * if (status.status === "completed") {
137
- * const blob = await client.queue.result(job.job_id);
138
- * break;
139
- * }
140
- * if (status.status === "failed") {
141
- * throw new Error("Job failed");
142
- * }
143
- * await new Promise(resolve => setTimeout(resolve, 1500));
144
- * }
145
- * ```
146
- */
147
31
  queue: QueueClient;
148
- /**
149
- * Client for creating client tokens.
150
- * Client tokens are short-lived API keys safe for client-side use.
151
- *
152
- * @example
153
- * ```ts
154
- * // Server-side: Create a client token
155
- * const serverClient = createDecartClient({ apiKey: process.env.DECART_API_KEY });
156
- * const token = await serverClient.tokens.create();
157
- * // Returns: { apiKey: "ek_...", expiresAt: "2024-12-15T12:10:00Z" }
158
- *
159
- * // Client-side: Use the client token
160
- * const client = createDecartClient({ apiKey: token.apiKey });
161
- * const realtimeClient = await client.realtime.connect(stream, options);
162
- * ```
163
- */
164
32
  tokens: TokensClient;
165
- /**
166
- * Upload files once and reuse them across generations.
167
- *
168
- * @example
169
- * ```ts
170
- * const ref = await client.files.upload(blob);
171
- * await rt.set({ image: ref.id, prompt: "make it cinematic" });
172
- * await rt.set({ image: ref.id, prompt: "now in noir" });
173
- * ```
174
- */
175
33
  files: FilesClient;
176
34
  };
177
35
  //#endregion
178
- export { type CanonicalModel, type CheckConnectivityOptions, type ClientSessionConnectionBreakdownEvent, type ClientSessionConnectionBreakdownPhase, type ConnectionQuality, type ConnectionQualityLimitingFactor, type ConnectionQualityMetrics, type ConnectionQualityReport, type ConnectionState, type ConnectivityMetrics, type ConnectivityReport, type ConnectivityTransport, type CreateTokenOptions, type CreateTokenResponse, type CustomModelDefinition, DecartClientOptions, type DecartSDKError, type DiagnosticEvent, type DiagnosticEventName, type DiagnosticEvents, ERROR_CODES, type FileInput, type FileReference, type FileUploadInput, type FilesClient, type G2GMetrics, type GenerationEndedMessage, type ImageModelDefinition, type ImageModels, type JobStatus, type JobStatusResponse, type JobSubmitResponse, type ListedModelDefinition, type LogLevel, type Logger, type Model, type ModelDefinition, type ModelKind, type ModelState, type ProcessClient, type ProcessOptions, type QueueClient, type QueueJobResult, type QueuePosition, type QueuePositionMessage, type QueueSubmitAndPollOptions, type QueueSubmitOptions, type ReactNativeFile, type RealTimeClient, type RealTimeClientConnectOptions, type RealTimeClientInitialState, type Events as RealTimeEvents, type RealTimeModels, type RealTimeSubscribeClient, type ReconnectEvent, type SetInput, type SubscribeEvents, type SubscribeOptions, type TokensClient, type UploadFileOptions, type VideoModelDefinition, type VideoModels, type VideoStallEvent, type WebRTCStats, createConsoleLogger, createDecartClient, isCanonicalModel, isImageModel, isModel, isRealtimeModel, isVideoModel, listModels, modelAliases, models, noopLogger, resolveCanonicalModelAlias, resolveModelAlias };
36
+ export { CanonicalModel, CheckConnectivityOptions, ClientSessionConnectionBreakdownEvent, ClientSessionConnectionBreakdownPhase, ConnectionQuality, ConnectionQualityLimitingFactor, ConnectionQualityMetrics, ConnectionQualityReport, ConnectionState, ConnectivityMetrics, ConnectivityReport, ConnectivityTransport, CreateTokenOptions, CreateTokenResponse, CustomModelDefinition, type DecartClientOptions, DecartSDKError, DiagnosticEvent, DiagnosticEventName, DiagnosticEvents, ERROR_CODES, FileInput, FileReference, FileUploadInput, FilesClient, G2GMetrics, GenerationEndedMessage, ImageModelDefinition, ImageModels, JobStatus, JobStatusResponse, JobSubmitResponse, ListedModelDefinition, LogLevel, Logger, Model, ModelDefinition, ModelFps, ModelKind, ModelState, ProcessClient, ProcessOptions, QueueClient, QueueJobResult, QueuePosition, QueuePositionMessage, QueueSubmitAndPollOptions, QueueSubmitOptions, ReactNativeFile, RealTimeClient, RealTimeClientConnectOptions, RealTimeClientInitialState, Events as RealTimeEvents, RealTimeModels, RealTimeSubscribeClient, RealtimeMediaStream, ReconnectEvent, SetInput, SubscribeEvents, SubscribeOptions, TokensClient, UploadFileOptions, VideoModelDefinition, VideoModels, VideoStallEvent, WebRTCStats, createConsoleLogger, createDecartClient, isCanonicalModel, isImageModel, isModel, isRealtimeModel, isVideoModel, listModels, modelAliases, models, noopLogger, resolveCanonicalModelAlias, resolveFpsNumber, resolveModelAlias };