@decartai/sdk 0.0.47 → 0.0.48

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
@@ -7,7 +7,7 @@ import { DecartSDKError, ERROR_CODES } from "./utils/errors.js";
7
7
  import { ConnectionState } from "./realtime/types.js";
8
8
  import { SetInput } from "./realtime/methods.js";
9
9
  import { RealTimeSubscribeClient, SubscribeEvents, SubscribeOptions } from "./realtime/subscribe-client.js";
10
- import { AvatarOptions, Events, RealTimeClient, RealTimeClientConnectOptions, RealTimeClientInitialState } from "./realtime/client.js";
10
+ import { Events, RealTimeClient, RealTimeClientConnectOptions, RealTimeClientInitialState } from "./realtime/client.js";
11
11
  import { ModelState } from "./shared/types.js";
12
12
  import { CreateTokenResponse, TokensClient } from "./tokens/client.js";
13
13
 
@@ -121,4 +121,4 @@ declare const createDecartClient: (options?: DecartClientOptions) => {
121
121
  tokens: TokensClient;
122
122
  };
123
123
  //#endregion
124
- export { type AvatarOptions, type ConnectionState, type CreateTokenResponse, DecartClientOptions, type DecartSDKError, ERROR_CODES, type FileInput, type ImageModelDefinition, type ImageModels, type JobStatus, type JobStatusResponse, type JobSubmitResponse, type Model, type ModelDefinition, type ModelState, type ProcessClient, type ProcessOptions, type QueueClient, type QueueJobResult, type QueueSubmitAndPollOptions, type QueueSubmitOptions, type ReactNativeFile, type RealTimeClient, type RealTimeClientConnectOptions, type RealTimeClientInitialState, type Events as RealTimeEvents, type RealTimeModels, type RealTimeSubscribeClient, type SetInput, type SubscribeEvents, type SubscribeOptions, type TokensClient, type VideoModelDefinition, type VideoModels, createDecartClient, isImageModel, isRealtimeModel, isVideoModel, models };
124
+ export { type ConnectionState, type CreateTokenResponse, DecartClientOptions, type DecartSDKError, ERROR_CODES, type FileInput, type ImageModelDefinition, type ImageModels, type JobStatus, type JobStatusResponse, type JobSubmitResponse, type Model, type ModelDefinition, type ModelState, type ProcessClient, type ProcessOptions, type QueueClient, type QueueJobResult, type QueueSubmitAndPollOptions, type QueueSubmitOptions, type ReactNativeFile, type RealTimeClient, type RealTimeClientConnectOptions, type RealTimeClientInitialState, type Events as RealTimeEvents, type RealTimeModels, type RealTimeSubscribeClient, type SetInput, type SubscribeEvents, type SubscribeOptions, type TokensClient, type VideoModelDefinition, type VideoModels, createDecartClient, isImageModel, isRealtimeModel, isVideoModel, models };
@@ -19,12 +19,17 @@ async function pollUntilComplete({ checkStatus, getContent, onStatusChange, sign
19
19
  if (signal?.aborted) throw new Error("Polling aborted");
20
20
  const status = await checkStatus();
21
21
  if (onStatusChange) onStatusChange(status);
22
- if (status.status === "completed") return {
23
- status: "completed",
24
- data: await getContent()
25
- };
22
+ if (status.status === "completed") {
23
+ const data = await getContent();
24
+ return {
25
+ status: "completed",
26
+ job_id: status.job_id,
27
+ data
28
+ };
29
+ }
26
30
  if (status.status === "failed") return {
27
31
  status: "failed",
32
+ job_id: status.job_id,
28
33
  error: "Job failed"
29
34
  };
30
35
  await sleep(POLLING_DEFAULTS.interval);
@@ -26,9 +26,11 @@ type JobStatusResponse = {
26
26
  */
27
27
  type QueueJobResult = {
28
28
  status: "completed";
29
+ job_id: string;
29
30
  data: Blob;
30
31
  } | {
31
32
  status: "failed";
33
+ job_id: string;
32
34
  error: string;
33
35
  };
34
36
  /**
@@ -10,13 +10,10 @@ declare const realTimeClientInitialStateSchema: z.ZodObject<{
10
10
  text: z.ZodString;
11
11
  enhance: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
12
12
  }, z.core.$strip>>;
13
+ image: z.ZodOptional<z.ZodUnion<readonly [z.ZodCustom<Blob, Blob>, z.ZodCustom<File, File>, z.ZodString]>>;
13
14
  }, z.core.$strip>;
14
15
  type OnRemoteStreamFn = (stream: MediaStream) => void;
15
16
  type RealTimeClientInitialState = z.infer<typeof realTimeClientInitialStateSchema>;
16
- declare const avatarOptionsSchema: z.ZodObject<{
17
- avatarImage: z.ZodUnion<readonly [z.ZodCustom<Blob, Blob>, z.ZodCustom<File, File>, z.ZodString]>;
18
- }, z.core.$strip>;
19
- type AvatarOptions = z.infer<typeof avatarOptionsSchema>;
20
17
  declare const realTimeClientConnectOptionsSchema: z.ZodObject<{
21
18
  model: z.ZodObject<{
22
19
  name: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodLiteral<"mirage">, z.ZodLiteral<"mirage_v2">, z.ZodLiteral<"lucy_v2v_720p_rt">, z.ZodLiteral<"lucy_2_rt">, z.ZodLiteral<"live_avatar">]>, z.ZodUnion<readonly [z.ZodLiteral<"lucy-dev-i2v">, z.ZodLiteral<"lucy-fast-v2v">, z.ZodLiteral<"lucy-pro-t2v">, z.ZodLiteral<"lucy-pro-i2v">, z.ZodLiteral<"lucy-pro-v2v">, z.ZodLiteral<"lucy-pro-flf2v">, z.ZodLiteral<"lucy-motion">, z.ZodLiteral<"lucy-restyle-v2v">]>, z.ZodUnion<readonly [z.ZodLiteral<"lucy-pro-t2i">, z.ZodLiteral<"lucy-pro-i2i">]>]>;
@@ -33,11 +30,9 @@ declare const realTimeClientConnectOptionsSchema: z.ZodObject<{
33
30
  text: z.ZodString;
34
31
  enhance: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
35
32
  }, z.core.$strip>>;
33
+ image: z.ZodOptional<z.ZodUnion<readonly [z.ZodCustom<Blob, Blob>, z.ZodCustom<File, File>, z.ZodString]>>;
36
34
  }, z.core.$strip>>;
37
35
  customizeOffer: z.ZodOptional<z.ZodCustom<z.core.$InferInnerFunctionTypeAsync<z.core.$ZodFunctionArgs, z.core.$ZodFunctionOut>, z.core.$InferInnerFunctionTypeAsync<z.core.$ZodFunctionArgs, z.core.$ZodFunctionOut>>>;
38
- avatar: z.ZodOptional<z.ZodObject<{
39
- avatarImage: z.ZodUnion<readonly [z.ZodCustom<Blob, Blob>, z.ZodCustom<File, File>, z.ZodString]>;
40
- }, z.core.$strip>>;
41
36
  }, z.core.$strip>;
42
37
  type RealTimeClientConnectOptions = z.infer<typeof realTimeClientConnectOptionsSchema>;
43
38
  type Events = {
@@ -69,4 +64,4 @@ type RealTimeClient = {
69
64
  playAudio?: (audio: Blob | File | ArrayBuffer) => Promise<void>;
70
65
  };
71
66
  //#endregion
72
- export { AvatarOptions, Events, RealTimeClient, RealTimeClientConnectOptions, RealTimeClientInitialState };
67
+ export { Events, RealTimeClient, RealTimeClientConnectOptions, RealTimeClientInitialState };
@@ -51,17 +51,11 @@ async function imageToBase64(image) {
51
51
  }
52
52
  const realTimeClientInitialStateSchema = modelStateSchema;
53
53
  const createAsyncFunctionSchema = (schema) => z.custom((fn) => schema.implementAsync(fn));
54
- const avatarOptionsSchema = z.object({ avatarImage: z.union([
55
- z.instanceof(Blob),
56
- z.instanceof(File),
57
- z.string()
58
- ]) });
59
54
  const realTimeClientConnectOptionsSchema = z.object({
60
55
  model: modelDefinitionSchema,
61
56
  onRemoteStream: z.custom((val) => typeof val === "function", { message: "onRemoteStream must be a function" }),
62
57
  initialState: realTimeClientInitialStateSchema.optional(),
63
- customizeOffer: createAsyncFunctionSchema(z.function()).optional(),
64
- avatar: avatarOptionsSchema.optional()
58
+ customizeOffer: createAsyncFunctionSchema(z.function()).optional()
65
59
  });
66
60
  const createRealTimeClient = (opts) => {
67
61
  const { baseUrl, apiKey, integration } = opts;
@@ -69,7 +63,7 @@ const createRealTimeClient = (opts) => {
69
63
  const parsedOptions = realTimeClientConnectOptionsSchema.safeParse(options);
70
64
  if (!parsedOptions.success) throw parsedOptions.error;
71
65
  const isAvatarLive = options.model.name === "live_avatar";
72
- const { onRemoteStream, initialState, avatar } = parsedOptions.data;
66
+ const { onRemoteStream, initialState } = parsedOptions.data;
73
67
  let audioStreamManager;
74
68
  let inputStream;
75
69
  if (isAvatarLive && !stream) {
@@ -78,13 +72,8 @@ const createRealTimeClient = (opts) => {
78
72
  } else inputStream = stream ?? new MediaStream();
79
73
  let webrtcManager;
80
74
  try {
81
- let avatarImageBase64;
82
- if (isAvatarLive && avatar?.avatarImage) if (typeof avatar.avatarImage === "string") {
83
- const response = await fetch(avatar.avatarImage);
84
- if (!response.ok) throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`);
85
- avatarImageBase64 = await blobToBase64(await response.blob());
86
- } else avatarImageBase64 = await blobToBase64(avatar.avatarImage);
87
- const initialPrompt = isAvatarLive && initialState?.prompt ? {
75
+ const initialImage = initialState?.image ? await imageToBase64(initialState.image) : void 0;
76
+ const initialPrompt = initialState?.prompt ? {
88
77
  text: initialState.prompt.text,
89
78
  enhance: initialState.prompt.enhance
90
79
  } : void 0;
@@ -104,8 +93,8 @@ const createRealTimeClient = (opts) => {
104
93
  customizeOffer: options.customizeOffer,
105
94
  vp8MinBitrate: 300,
106
95
  vp8StartBitrate: 600,
107
- isAvatarLive,
108
- avatarImageBase64,
96
+ modelName: options.model.name,
97
+ initialImage,
109
98
  initialPrompt
110
99
  });
111
100
  const manager = webrtcManager;
@@ -122,10 +111,6 @@ const createRealTimeClient = (opts) => {
122
111
  manager.getWebsocketMessageEmitter().on("generationTick", tickListener);
123
112
  await manager.connect(inputStream);
124
113
  const methods = realtimeMethods(manager, imageToBase64);
125
- if (!isAvatarLive && initialState?.prompt) {
126
- const { text, enhance } = initialState.prompt;
127
- await methods.setPrompt(text, { enhance });
128
- }
129
114
  const client = {
130
115
  set: methods.set,
131
116
  setPrompt: methods.setPrompt,
@@ -53,8 +53,11 @@ var WebRTCConnection = class {
53
53
  rejectConnect(/* @__PURE__ */ new Error("WebSocket closed"));
54
54
  };
55
55
  }), connectAbort]);
56
- if (this.callbacks.avatarImageBase64) await Promise.race([this.sendAvatarImage(this.callbacks.avatarImageBase64), connectAbort]);
57
- if (this.callbacks.initialPrompt) await Promise.race([this.sendInitialPrompt(this.callbacks.initialPrompt), connectAbort]);
56
+ if (this.callbacks.initialImage) await Promise.race([this.setImageBase64(this.callbacks.initialImage, {
57
+ prompt: this.callbacks.initialPrompt?.text,
58
+ enhance: this.callbacks.initialPrompt?.enhance
59
+ }), connectAbort]);
60
+ else if (this.callbacks.initialPrompt) await Promise.race([this.sendInitialPrompt(this.callbacks.initialPrompt), connectAbort]);
58
61
  await this.setupNewPeerConnection();
59
62
  await Promise.race([new Promise((resolve, reject) => {
60
63
  const checkConnection = setInterval(() => {
@@ -163,15 +166,6 @@ var WebRTCConnection = class {
163
166
  console.warn("[WebRTC] Message dropped: WebSocket is not open");
164
167
  return false;
165
168
  }
166
- async sendAvatarImage(imageBase64) {
167
- return this.setImageBase64(imageBase64);
168
- }
169
- /**
170
- * Send an image to the server (e.g., as a reference for inference).
171
- * Can be called after connection is established.
172
- * Pass null to clear the reference image or use a placeholder.
173
- * Optionally include a prompt to send with the image.
174
- */
175
169
  async setImageBase64(imageBase64, options) {
176
170
  return new Promise((resolve, reject) => {
177
171
  const timeoutId = setTimeout(() => {
@@ -249,7 +243,7 @@ var WebRTCConnection = class {
249
243
  this.pc = new RTCPeerConnection({ iceServers });
250
244
  this.setState("connecting");
251
245
  if (this.localStream) {
252
- if (this.callbacks.isAvatarLive) this.pc.addTransceiver("video", { direction: "recvonly" });
246
+ if (this.callbacks.modelName === "live_avatar") this.pc.addTransceiver("video", { direction: "recvonly" });
253
247
  this.localStream.getTracks().forEach((track) => {
254
248
  if (this.pc && this.localStream) this.pc.addTrack(track, this.localStream);
255
249
  });
@@ -36,8 +36,8 @@ var WebRTCManager = class {
36
36
  customizeOffer: config.customizeOffer,
37
37
  vp8MinBitrate: config.vp8MinBitrate,
38
38
  vp8StartBitrate: config.vp8StartBitrate,
39
- isAvatarLive: config.isAvatarLive,
40
- avatarImageBase64: config.avatarImageBase64,
39
+ modelName: config.modelName,
40
+ initialImage: config.initialImage,
41
41
  initialPrompt: config.initialPrompt
42
42
  });
43
43
  }
@@ -6,6 +6,7 @@ declare const modelStateSchema: z.ZodObject<{
6
6
  text: z.ZodString;
7
7
  enhance: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
8
8
  }, z.core.$strip>>;
9
+ image: z.ZodOptional<z.ZodUnion<readonly [z.ZodCustom<Blob, Blob>, z.ZodCustom<File, File>, z.ZodString]>>;
9
10
  }, z.core.$strip>;
10
11
  type ModelState = z.infer<typeof modelStateSchema>;
11
12
  //#endregion
@@ -1,10 +1,17 @@
1
1
  import { z } from "zod";
2
2
 
3
3
  //#region src/shared/types.ts
4
- const modelStateSchema = z.object({ prompt: z.object({
5
- text: z.string().min(1),
6
- enhance: z.boolean().optional().default(true)
7
- }).optional() });
4
+ const modelStateSchema = z.object({
5
+ prompt: z.object({
6
+ text: z.string().min(1),
7
+ enhance: z.boolean().optional().default(true)
8
+ }).optional(),
9
+ image: z.union([
10
+ z.instanceof(Blob),
11
+ z.instanceof(File),
12
+ z.string()
13
+ ]).optional()
14
+ });
8
15
 
9
16
  //#endregion
10
17
  export { modelStateSchema };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decartai/sdk",
3
- "version": "0.0.47",
3
+ "version": "0.0.48",
4
4
  "description": "Decart's JavaScript SDK",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -32,13 +32,15 @@
32
32
  "@biomejs/biome": "2.3.8",
33
33
  "@types/bun": "^1.3.3",
34
34
  "@types/node": "^22.15.17",
35
+ "@vitest/browser-playwright": "^4",
35
36
  "bumpp": "^10.1.0",
36
37
  "msw": "^2.11.3",
37
38
  "pkg-pr-new": "^0.0.56",
39
+ "playwright": "^1.58.2",
38
40
  "tsdown": "^0.14.1",
39
41
  "typescript": "^5.8.3",
40
42
  "vite": "^7.1.2",
41
- "vitest": "^3.1.3"
43
+ "vitest": "^4.0.18"
42
44
  },
43
45
  "dependencies": {
44
46
  "mitt": "^3.0.1",
@@ -51,6 +53,7 @@
51
53
  "dev:example": "vite dev --port 3000",
52
54
  "test": "vitest unit",
53
55
  "test:e2e": "vitest e2e",
56
+ "test:e2e:realtime": "vitest --config vitest.config.e2e-realtime.ts",
54
57
  "typecheck": "tsc --noEmit",
55
58
  "format": "biome format --write",
56
59
  "format:check": "biome check",