@decartai/sdk 0.0.21 → 0.0.23
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/README.md +36 -8
- package/dist/index.d.ts +19 -2
- package/dist/index.js +43 -25
- package/dist/process/client.js +1 -1
- package/dist/process/types.d.ts +12 -5
- package/dist/queue/client.js +2 -2
- package/dist/queue/types.d.ts +0 -4
- package/dist/realtime/client.js +1 -2
- package/dist/realtime/webrtc-connection.js +1 -2
- package/dist/shared/model.js +5 -5
- package/dist/utils/env.js +9 -0
- package/dist/utils/errors.js +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -62,7 +62,9 @@ realtimeClient.setPrompt("Cyberpunk city");
|
|
|
62
62
|
realtimeClient.disconnect();
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
###
|
|
65
|
+
### Async Processing (Queue API)
|
|
66
|
+
|
|
67
|
+
For video generation jobs, use the queue API to submit jobs and poll for results:
|
|
66
68
|
|
|
67
69
|
```typescript
|
|
68
70
|
import { createDecartClient, models } from "@decartai/sdk";
|
|
@@ -71,15 +73,41 @@ const client = createDecartClient({
|
|
|
71
73
|
apiKey: "your-api-key-here"
|
|
72
74
|
});
|
|
73
75
|
|
|
74
|
-
//
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
// Submit and poll automatically
|
|
77
|
+
const result = await client.queue.submitAndPoll({
|
|
78
|
+
model: models.video("lucy-pro-t2v"),
|
|
79
|
+
prompt: "A cat playing piano",
|
|
80
|
+
onStatusChange: (job) => {
|
|
81
|
+
console.log(`Status: ${job.status}`);
|
|
82
|
+
}
|
|
80
83
|
});
|
|
81
84
|
|
|
82
|
-
|
|
85
|
+
if (result.status === "completed") {
|
|
86
|
+
videoElement.src = URL.createObjectURL(result.data);
|
|
87
|
+
} else {
|
|
88
|
+
console.error("Job failed:", result.error);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Or manage the polling manually:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// Submit the job
|
|
96
|
+
const job = await client.queue.submit({
|
|
97
|
+
model: models.video("lucy-pro-t2v"),
|
|
98
|
+
prompt: "A cat playing piano"
|
|
99
|
+
});
|
|
100
|
+
console.log(`Job ID: ${job.job_id}`);
|
|
101
|
+
|
|
102
|
+
// Poll for status
|
|
103
|
+
const status = await client.queue.status(job.job_id);
|
|
104
|
+
console.log(`Status: ${status.status}`);
|
|
105
|
+
|
|
106
|
+
// Get result when completed
|
|
107
|
+
if (status.status === "completed") {
|
|
108
|
+
const blob = await client.queue.result(job.job_id);
|
|
109
|
+
videoElement.src = URL.createObjectURL(blob);
|
|
110
|
+
}
|
|
83
111
|
```
|
|
84
112
|
|
|
85
113
|
## Development
|
package/dist/index.d.ts
CHANGED
|
@@ -10,12 +10,29 @@ import { z } from "zod";
|
|
|
10
10
|
|
|
11
11
|
//#region src/index.d.ts
|
|
12
12
|
declare const decartClientOptionsSchema: z.ZodObject<{
|
|
13
|
-
apiKey: z.ZodString
|
|
13
|
+
apiKey: z.ZodOptional<z.ZodString>;
|
|
14
14
|
baseUrl: z.ZodOptional<z.ZodURL>;
|
|
15
15
|
integration: z.ZodOptional<z.ZodString>;
|
|
16
16
|
}, z.core.$strip>;
|
|
17
17
|
type DecartClientOptions = z.infer<typeof decartClientOptionsSchema>;
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Create a Decart API client.
|
|
20
|
+
*
|
|
21
|
+
* @param options - Configuration options
|
|
22
|
+
* @param options.apiKey - API key for authentication. Defaults to the DECART_API_KEY environment variable.
|
|
23
|
+
* @param options.baseUrl - Override the default API base URL.
|
|
24
|
+
* @param options.integration - Optional integration identifier.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* // Option 1: Explicit API key
|
|
29
|
+
* const client = createDecartClient({ apiKey: "your-api-key" });
|
|
30
|
+
*
|
|
31
|
+
* // Option 2: Using DECART_API_KEY environment variable
|
|
32
|
+
* const client = createDecartClient();
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
declare const createDecartClient: (options?: DecartClientOptions) => {
|
|
19
36
|
realtime: {
|
|
20
37
|
connect: (stream: MediaStream, options: RealTimeClientConnectOptions) => Promise<RealTimeClient>;
|
|
21
38
|
};
|
package/dist/index.js
CHANGED
|
@@ -3,42 +3,60 @@ import { createProcessClient } from "./process/client.js";
|
|
|
3
3
|
import { createQueueClient } from "./queue/client.js";
|
|
4
4
|
import { models } from "./shared/model.js";
|
|
5
5
|
import { createRealTimeClient } from "./realtime/client.js";
|
|
6
|
+
import { readEnv } from "./utils/env.js";
|
|
6
7
|
import { z } from "zod";
|
|
7
8
|
|
|
8
9
|
//#region src/index.ts
|
|
9
10
|
const decartClientOptionsSchema = z.object({
|
|
10
|
-
apiKey: z.string().min(1),
|
|
11
|
+
apiKey: z.string().min(1).optional(),
|
|
11
12
|
baseUrl: z.url().optional(),
|
|
12
13
|
integration: z.string().optional()
|
|
13
14
|
});
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Create a Decart API client.
|
|
17
|
+
*
|
|
18
|
+
* @param options - Configuration options
|
|
19
|
+
* @param options.apiKey - API key for authentication. Defaults to the DECART_API_KEY environment variable.
|
|
20
|
+
* @param options.baseUrl - Override the default API base URL.
|
|
21
|
+
* @param options.integration - Optional integration identifier.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* // Option 1: Explicit API key
|
|
26
|
+
* const client = createDecartClient({ apiKey: "your-api-key" });
|
|
27
|
+
*
|
|
28
|
+
* // Option 2: Using DECART_API_KEY environment variable
|
|
29
|
+
* const client = createDecartClient();
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
const createDecartClient = (options = {}) => {
|
|
33
|
+
const apiKey = options.apiKey ?? readEnv("DECART_API_KEY");
|
|
34
|
+
if (!apiKey) throw createInvalidApiKeyError();
|
|
35
|
+
const parsedOptions = decartClientOptionsSchema.safeParse({
|
|
36
|
+
...options,
|
|
37
|
+
apiKey
|
|
38
|
+
});
|
|
16
39
|
if (!parsedOptions.success) {
|
|
17
|
-
|
|
18
|
-
if (issue.path.includes("apiKey")) throw createInvalidApiKeyError();
|
|
19
|
-
if (issue.path.includes("baseUrl")) throw createInvalidBaseUrlError(options.baseUrl);
|
|
40
|
+
if (parsedOptions.error.issues[0].path.includes("baseUrl")) throw createInvalidBaseUrlError(options.baseUrl);
|
|
20
41
|
throw parsedOptions.error;
|
|
21
42
|
}
|
|
22
|
-
const { baseUrl = "https://api.decart.ai",
|
|
23
|
-
const realtime = createRealTimeClient({
|
|
24
|
-
baseUrl: "wss://api3.decart.ai",
|
|
25
|
-
apiKey,
|
|
26
|
-
integration
|
|
27
|
-
});
|
|
28
|
-
const process = createProcessClient({
|
|
29
|
-
baseUrl,
|
|
30
|
-
apiKey,
|
|
31
|
-
integration
|
|
32
|
-
});
|
|
33
|
-
const queue = createQueueClient({
|
|
34
|
-
baseUrl,
|
|
35
|
-
apiKey,
|
|
36
|
-
integration
|
|
37
|
-
});
|
|
43
|
+
const { baseUrl = "https://api.decart.ai", integration } = parsedOptions.data;
|
|
38
44
|
return {
|
|
39
|
-
realtime
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
realtime: createRealTimeClient({
|
|
46
|
+
baseUrl: "wss://api3.decart.ai",
|
|
47
|
+
apiKey,
|
|
48
|
+
integration
|
|
49
|
+
}),
|
|
50
|
+
process: createProcessClient({
|
|
51
|
+
baseUrl,
|
|
52
|
+
apiKey,
|
|
53
|
+
integration
|
|
54
|
+
}),
|
|
55
|
+
queue: createQueueClient({
|
|
56
|
+
baseUrl,
|
|
57
|
+
apiKey,
|
|
58
|
+
integration
|
|
59
|
+
})
|
|
42
60
|
};
|
|
43
61
|
};
|
|
44
62
|
|
package/dist/process/client.js
CHANGED
|
@@ -6,7 +6,7 @@ import { sendRequest } from "./request.js";
|
|
|
6
6
|
const createProcessClient = (opts) => {
|
|
7
7
|
const { apiKey, baseUrl, integration } = opts;
|
|
8
8
|
const _process = async (options) => {
|
|
9
|
-
const { model, signal
|
|
9
|
+
const { model, signal, ...inputs } = options;
|
|
10
10
|
const parsedInputs = model.inputSchema.safeParse(inputs);
|
|
11
11
|
if (!parsedInputs.success) throw createInvalidInputError(`Invalid inputs for ${model.name}: ${parsedInputs.error.message}`);
|
|
12
12
|
const processedInputs = {};
|
package/dist/process/types.d.ts
CHANGED
|
@@ -25,6 +25,11 @@ interface ImageEditingInputs {
|
|
|
25
25
|
* It's highly recommended to read our [Prompt Engineering for Edits](https://docs.platform.decart.ai/models/image/image-editing#prompt-engineering-for-edits) guide for how to write effective editing prompts.
|
|
26
26
|
*/
|
|
27
27
|
prompt: string;
|
|
28
|
+
/**
|
|
29
|
+
* The data to use for generation (for image-to-image).
|
|
30
|
+
* Can be a File, Blob, ReadableStream, URL, or string URL.
|
|
31
|
+
*/
|
|
32
|
+
data?: FileInput;
|
|
28
33
|
}
|
|
29
34
|
/**
|
|
30
35
|
* Model-specific input documentation for video models.
|
|
@@ -36,6 +41,13 @@ interface VideoModelInputs {
|
|
|
36
41
|
* See our [Prompt Engineering](https://docs.platform.decart.ai/models/video/video-generation#prompt-engineering) guide for how to write prompt for Decart video models effectively.
|
|
37
42
|
*/
|
|
38
43
|
prompt: string;
|
|
44
|
+
/**
|
|
45
|
+
* The data to use for generation (for image-to-video and video-to-video).
|
|
46
|
+
* Can be a File, Blob, ReadableStream, URL, or string URL.
|
|
47
|
+
*
|
|
48
|
+
* Output video is limited to 5 seconds.
|
|
49
|
+
*/
|
|
50
|
+
data?: FileInput;
|
|
39
51
|
}
|
|
40
52
|
/**
|
|
41
53
|
* Default inputs for models that only require a prompt.
|
|
@@ -73,11 +85,6 @@ interface ProcessInputs {
|
|
|
73
85
|
* @default "landscape"
|
|
74
86
|
*/
|
|
75
87
|
orientation?: "landscape" | "portrait";
|
|
76
|
-
/**
|
|
77
|
-
* The data to use for generation (for image-to-image and video-to-video).
|
|
78
|
-
* Can be a File, Blob, ReadableStream, URL, or string URL.
|
|
79
|
-
*/
|
|
80
|
-
data?: FileInput;
|
|
81
88
|
/**
|
|
82
89
|
* The start frame image (for first-last-frame models).
|
|
83
90
|
* Can be a File, Blob, ReadableStream, URL, or string URL.
|
package/dist/queue/client.js
CHANGED
|
@@ -7,7 +7,7 @@ import { getJobContent, getJobStatus, submitJob } from "./request.js";
|
|
|
7
7
|
const createQueueClient = (opts) => {
|
|
8
8
|
const { apiKey, baseUrl, integration } = opts;
|
|
9
9
|
const submit = async (options) => {
|
|
10
|
-
const { model, signal
|
|
10
|
+
const { model, signal, ...inputs } = options;
|
|
11
11
|
const parsedInputs = model.inputSchema.safeParse(inputs);
|
|
12
12
|
if (!parsedInputs.success) throw createInvalidInputError(`Invalid inputs for ${model.name}: ${parsedInputs.error.message}`);
|
|
13
13
|
const processedInputs = {};
|
|
@@ -39,7 +39,7 @@ const createQueueClient = (opts) => {
|
|
|
39
39
|
});
|
|
40
40
|
};
|
|
41
41
|
const submitAndPoll = async (options) => {
|
|
42
|
-
const { onStatusChange, signal
|
|
42
|
+
const { onStatusChange, signal, ...submitOptions } = options;
|
|
43
43
|
const job = await submit(submitOptions);
|
|
44
44
|
if (onStatusChange) onStatusChange(job);
|
|
45
45
|
return pollUntilComplete({
|
package/dist/queue/types.d.ts
CHANGED
|
@@ -36,10 +36,6 @@ type QueueJobResult = {
|
|
|
36
36
|
* Re-exports ProcessInputs fields with queue-specific documentation.
|
|
37
37
|
*/
|
|
38
38
|
interface QueueInputs extends ProcessInputs {
|
|
39
|
-
/**
|
|
40
|
-
* The data to use for generation (for image-to-image and video-to-video).
|
|
41
|
-
*/
|
|
42
|
-
data?: FileInput;
|
|
43
39
|
/**
|
|
44
40
|
* The start frame image (for first-last-frame models).
|
|
45
41
|
*/
|
package/dist/realtime/client.js
CHANGED
|
@@ -24,9 +24,8 @@ const createRealTimeClient = (opts) => {
|
|
|
24
24
|
if (!parsedOptions.success) throw parsedOptions.error;
|
|
25
25
|
const sessionId = v4();
|
|
26
26
|
const { onRemoteStream, initialState } = parsedOptions.data;
|
|
27
|
-
const url = `${baseUrl}${options.model.urlPath}`;
|
|
28
27
|
const webrtcManager = new WebRTCManager({
|
|
29
|
-
webrtcUrl: `${
|
|
28
|
+
webrtcUrl: `${`${baseUrl}${options.model.urlPath}`}?api_key=${apiKey}&model=${options.model.name}`,
|
|
30
29
|
apiKey,
|
|
31
30
|
sessionId,
|
|
32
31
|
fps: options.model.fps,
|
|
@@ -17,8 +17,7 @@ var WebRTCConnection = class {
|
|
|
17
17
|
const deadline = Date.now() + timeout;
|
|
18
18
|
this.localStream = localStream;
|
|
19
19
|
const userAgent = encodeURIComponent(buildUserAgent(integration));
|
|
20
|
-
const
|
|
21
|
-
const wsUrl = `${url}${separator}user_agent=${userAgent}`;
|
|
20
|
+
const wsUrl = `${url}${url.includes("?") ? "&" : "?"}user_agent=${userAgent}`;
|
|
22
21
|
await new Promise((resolve, reject) => {
|
|
23
22
|
this.connectionReject = reject;
|
|
24
23
|
const timer = setTimeout(() => reject(/* @__PURE__ */ new Error("WebSocket timeout")), timeout);
|
package/dist/shared/model.js
CHANGED
|
@@ -63,19 +63,19 @@ const modelInputSchemas = {
|
|
|
63
63
|
}),
|
|
64
64
|
"lucy-pro-i2v": z.object({
|
|
65
65
|
prompt: z.string().min(1).max(1e3).describe("The prompt to use for the generation"),
|
|
66
|
-
data: fileInputSchema.describe("The image data to use for generation (File, Blob, ReadableStream, URL, or string URL)"),
|
|
66
|
+
data: fileInputSchema.describe("The image data to use for generation (File, Blob, ReadableStream, URL, or string URL). Output video is limited to 5 seconds."),
|
|
67
67
|
seed: z.number().optional().describe("The seed to use for the generation"),
|
|
68
68
|
resolution: proResolutionSchema()
|
|
69
69
|
}),
|
|
70
70
|
"lucy-dev-i2v": z.object({
|
|
71
71
|
prompt: z.string().min(1).max(1e3).describe("The prompt to use for the generation"),
|
|
72
|
-
data: fileInputSchema.describe("The image data to use for generation (File, Blob, ReadableStream, URL, or string URL)"),
|
|
72
|
+
data: fileInputSchema.describe("The image data to use for generation (File, Blob, ReadableStream, URL, or string URL). Output video is limited to 5 seconds."),
|
|
73
73
|
seed: z.number().optional().describe("The seed to use for the generation"),
|
|
74
74
|
resolution: devResolutionSchema
|
|
75
75
|
}),
|
|
76
76
|
"lucy-pro-v2v": z.object({
|
|
77
77
|
prompt: z.string().min(1).max(1e3).describe("The prompt to use for the generation"),
|
|
78
|
-
data: fileInputSchema.describe("The video data to use for generation (File, Blob, ReadableStream, URL, or string URL)"),
|
|
78
|
+
data: fileInputSchema.describe("The video data to use for generation (File, Blob, ReadableStream, URL, or string URL). Output video is limited to 5 seconds."),
|
|
79
79
|
seed: z.number().optional().describe("The seed to use for the generation"),
|
|
80
80
|
resolution: proV2vResolutionSchema,
|
|
81
81
|
enhance_prompt: z.boolean().optional().describe("Whether to enhance the prompt"),
|
|
@@ -83,7 +83,7 @@ const modelInputSchemas = {
|
|
|
83
83
|
}),
|
|
84
84
|
"lucy-fast-v2v": z.object({
|
|
85
85
|
prompt: z.string().min(1).max(1e3).describe("The prompt to use for the generation"),
|
|
86
|
-
data: fileInputSchema.describe("The video data to use for generation (File, Blob, ReadableStream, URL, or string URL)"),
|
|
86
|
+
data: fileInputSchema.describe("The video data to use for generation (File, Blob, ReadableStream, URL, or string URL). Output video is limited to 5 seconds."),
|
|
87
87
|
seed: z.number().optional().describe("The seed to use for the generation"),
|
|
88
88
|
resolution: proV2vResolutionSchema,
|
|
89
89
|
enhance_prompt: z.boolean().optional().describe("Whether to enhance the prompt")
|
|
@@ -103,7 +103,7 @@ const modelInputSchemas = {
|
|
|
103
103
|
enhance_prompt: z.boolean().optional().describe("Whether to enhance the prompt")
|
|
104
104
|
}),
|
|
105
105
|
"lucy-motion": z.object({
|
|
106
|
-
data: fileInputSchema.describe("The image data to use for generation (File, Blob, ReadableStream, URL, or string URL)"),
|
|
106
|
+
data: fileInputSchema.describe("The image data to use for generation (File, Blob, ReadableStream, URL, or string URL). Output video is limited to 5 seconds."),
|
|
107
107
|
trajectory: z.array(z.object({
|
|
108
108
|
frame: z.number().min(0),
|
|
109
109
|
x: z.number().min(0),
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/utils/env.ts
|
|
2
|
+
const readEnv = (env) => {
|
|
3
|
+
const globalThisAny = globalThis;
|
|
4
|
+
if (typeof globalThisAny.process !== "undefined") return globalThisAny.process.env?.[env]?.trim();
|
|
5
|
+
if (typeof globalThisAny.Deno !== "undefined") return globalThisAny.Deno.env?.get?.(env)?.trim();
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
export { readEnv };
|
package/dist/utils/errors.js
CHANGED
|
@@ -21,7 +21,7 @@ function createSDKError(code, message, data, cause) {
|
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
function createInvalidApiKeyError() {
|
|
24
|
-
return createSDKError(ERROR_CODES.INVALID_API_KEY, "API key
|
|
24
|
+
return createSDKError(ERROR_CODES.INVALID_API_KEY, "Missing API key. Pass `apiKey` to createDecartClient() or set the DECART_API_KEY environment variable.");
|
|
25
25
|
}
|
|
26
26
|
function createInvalidBaseUrlError(url) {
|
|
27
27
|
return createSDKError(ERROR_CODES.INVALID_BASE_URL, `Invalid base URL${url ? `: ${url}` : ""}`);
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decartai/sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"description": "Decart's JavaScript SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"mitt": "^3.0.1",
|
|
44
44
|
"p-retry": "^6.2.1",
|
|
45
|
-
"uuid": "^
|
|
45
|
+
"uuid": "^13.0.0",
|
|
46
46
|
"zod": "^4.0.17"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|