@decartai/sdk 0.0.7 → 0.0.12

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 CHANGED
@@ -82,6 +82,34 @@ const result = await client.process({
82
82
  videoElement.src = URL.createObjectURL(result);
83
83
  ```
84
84
 
85
+ ## Development
86
+
87
+ ### Setup
88
+
89
+ ```bash
90
+ pnpm install
91
+ ```
92
+
93
+ ### Development Commands
94
+
95
+ - `pnpm build` - Build the project
96
+ - `pnpm dev:example` - Run Vite dev server for examples
97
+ - `pnpm test` - Run unit tests
98
+ - `pnpm test:e2e` - Run end-to-end tests
99
+ - `pnpm typecheck` - Type check with TypeScript
100
+ - `pnpm format` - Format code with Biome
101
+ - `pnpm lint` - Lint code with Biome
102
+
103
+ ### Publishing
104
+
105
+ 1. **Version bump**: Run `pnpm release` to bump the version (this uses `bumpp` to create a new version tag) and push it to GitHub
106
+ 2. **Automated publish**: The GitHub Actions workflow will:
107
+ - Build the project
108
+ - Publish to npm
109
+ - Create a GitHub release with changelog
110
+
111
+ The package is published to npm as `@decartai/sdk`.
112
+
85
113
  ## License
86
114
 
87
115
  MIT
package/dist/index.d.ts CHANGED
@@ -10,12 +10,25 @@ import { z } from "zod";
10
10
  declare const decartClientOptionsSchema: z.ZodObject<{
11
11
  apiKey: z.ZodString;
12
12
  baseUrl: z.ZodOptional<z.ZodURL>;
13
+ integration: z.ZodOptional<z.ZodString>;
13
14
  }, z.core.$strip>;
14
15
  type DecartClientOptions = z.infer<typeof decartClientOptionsSchema>;
15
16
  declare const createDecartClient: (options: DecartClientOptions) => {
16
17
  realtime: {
17
18
  connect: (stream: MediaStream, options: RealTimeClientConnectOptions) => Promise<RealTimeClient>;
18
19
  };
20
+ /**
21
+ * Client for video and image generation.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const client = createDecartClient({ apiKey: "your-api-key" });
26
+ * const result = await client.process({
27
+ * model: models.video("lucy-pro-t2v"),
28
+ * prompt: "A beautiful sunset over the ocean"
29
+ * });
30
+ * ```
31
+ */
19
32
  process: ProcessClient;
20
33
  };
21
34
  //#endregion
package/dist/index.js CHANGED
@@ -7,7 +7,8 @@ import { z } from "zod";
7
7
  //#region src/index.ts
8
8
  const decartClientOptionsSchema = z.object({
9
9
  apiKey: z.string().min(1),
10
- baseUrl: z.url().optional()
10
+ baseUrl: z.url().optional(),
11
+ integration: z.string().optional()
11
12
  });
12
13
  const createDecartClient = (options) => {
13
14
  const parsedOptions = decartClientOptionsSchema.safeParse(options);
@@ -17,14 +18,16 @@ const createDecartClient = (options) => {
17
18
  if (issue.path.includes("baseUrl")) throw createInvalidBaseUrlError(options.baseUrl);
18
19
  throw parsedOptions.error;
19
20
  }
20
- const { baseUrl = "https://api.decart.ai", apiKey } = parsedOptions.data;
21
+ const { baseUrl = "https://api.decart.ai", apiKey, integration } = parsedOptions.data;
21
22
  const realtime = createRealTimeClient({
22
23
  baseUrl: "wss://api3.decart.ai",
23
- apiKey
24
+ apiKey,
25
+ integration
24
26
  });
25
27
  const process = createProcessClient({
26
28
  baseUrl,
27
- apiKey
29
+ apiKey,
30
+ integration
28
31
  });
29
32
  return {
30
33
  realtime,
@@ -3,7 +3,7 @@ import { fileInputToBlob, sendRequest } from "./request.js";
3
3
 
4
4
  //#region src/process/client.ts
5
5
  const createProcessClient = (opts) => {
6
- const { apiKey, baseUrl } = opts;
6
+ const { apiKey, baseUrl, integration } = opts;
7
7
  const _process = async (options) => {
8
8
  const { model, signal,...inputs } = options;
9
9
  const parsedInputs = model.inputSchema.safeParse(inputs);
@@ -16,7 +16,8 @@ const createProcessClient = (opts) => {
16
16
  apiKey,
17
17
  model,
18
18
  inputs: processedInputs,
19
- signal
19
+ signal,
20
+ integration
20
21
  });
21
22
  };
22
23
  return _process;
@@ -1,4 +1,5 @@
1
1
  import { createInvalidInputError, createSDKError } from "../utils/errors.js";
2
+ import { buildUserAgent } from "../utils/user-agent.js";
2
3
 
3
4
  //#region src/process/request.ts
4
5
  async function fileInputToBlob(input) {
@@ -13,14 +14,17 @@ async function fileInputToBlob(input) {
13
14
  }
14
15
  throw createInvalidInputError("Invalid file input type");
15
16
  }
16
- async function sendRequest({ baseUrl, apiKey, model, inputs, signal }) {
17
+ async function sendRequest({ baseUrl, apiKey, model, inputs, signal, integration }) {
17
18
  const formData = new FormData();
18
19
  for (const [key, value] of Object.entries(inputs)) if (value !== void 0 && value !== null) if (value instanceof Blob) formData.append(key, value);
19
20
  else formData.append(key, String(value));
20
21
  const endpoint = `${baseUrl}${model.urlPath}`;
21
22
  const response = await fetch(endpoint, {
22
23
  method: "POST",
23
- headers: { "X-API-KEY": apiKey },
24
+ headers: {
25
+ "X-API-KEY": apiKey,
26
+ "User-Agent": buildUserAgent(integration)
27
+ },
24
28
  body: formData,
25
29
  signal
26
30
  });
@@ -1,12 +1,145 @@
1
- import { ModelDefinition, ModelInputSchemas } from "../shared/model.js";
1
+ import { ImageModels, ModelDefinition, ModelInputSchemas, VideoModels } from "../shared/model.js";
2
2
  import { z } from "zod";
3
3
 
4
4
  //#region src/process/types.d.ts
5
+ type FileInput = File | Blob | ReadableStream | URL | string;
5
6
  type InferModelInputs<T extends ModelDefinition> = T["name"] extends keyof ModelInputSchemas ? z.input<ModelInputSchemas[T["name"]]> : Record<string, never>;
7
+ /**
8
+ * Model-specific input documentation for image generation models.
9
+ */
10
+ interface ImageGenerationInputs {
11
+ /**
12
+ * Text description to use for the generation.
13
+ *
14
+ * See our [Prompt Engineering](https://docs.platform.decart.ai/models/image/image-generation#prompt-engineering) guide for how to write prompt for Decart image models effectively.
15
+ */
16
+ prompt: string;
17
+ }
18
+ /**
19
+ * Model-specific input documentation for image editing models.
20
+ */
21
+ interface ImageEditingInputs {
22
+ /**
23
+ * Text description of the changes to apply to the image.
24
+ *
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
+ */
27
+ prompt: string;
28
+ }
29
+ /**
30
+ * Model-specific input documentation for video models.
31
+ */
32
+ interface VideoModelInputs {
33
+ /**
34
+ * Text description to use for the generation.
35
+ *
36
+ * 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
+ */
38
+ prompt: string;
39
+ }
40
+ /**
41
+ * Default inputs for models that only require a prompt.
42
+ */
43
+ interface PromptInput {
44
+ /**
45
+ * Text description to use for the generation.
46
+ */
47
+ prompt: string;
48
+ }
49
+ /**
50
+ * Conditional type that selects the appropriate model-specific input documentation based on the model type.
51
+ * This allows different models to have field-specific documentation while maintaining type safety.
52
+ * Specific models are checked first, then falls back to category-based selection.
53
+ */
54
+ type ModelSpecificInputs<T extends ModelDefinition> = T["name"] extends "lucy-pro-i2i" ? ImageEditingInputs : T["name"] extends ImageModels ? ImageGenerationInputs : T["name"] extends VideoModels ? VideoModelInputs : PromptInput;
55
+ interface ProcessInputs {
56
+ /**
57
+ * Random seed for reproducible results.
58
+ *
59
+ * Using the same seed with the same prompt and settings will produce the same output every time.
60
+ * This is useful for testing, debugging, or when you want to recreate a specific result.
61
+ *
62
+ */
63
+ seed?: number;
64
+ /**
65
+ * The output resolution to use for the generation.
66
+ *
67
+ * @default "720p"
68
+ */
69
+ resolution?: "480p" | "720p";
70
+ /**
71
+ * The output orientation to use for the generation.
72
+ *
73
+ * @default "landscape"
74
+ */
75
+ 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
+ /**
82
+ * The start frame image (for first-last-frame models).
83
+ * Can be a File, Blob, ReadableStream, URL, or string URL.
84
+ */
85
+ start?: FileInput;
86
+ /**
87
+ * The end frame image (for first-last-frame models).
88
+ * Can be a File, Blob, ReadableStream, URL, or string URL.
89
+ */
90
+ end?: FileInput;
91
+ /**
92
+ * Whether to enhance the prompt.
93
+ *
94
+ * @remarks
95
+ * For best results, keep this `true` (default) to let Decart's AI enhance your prompts.
96
+ * Only disable it if you need exact prompt control.
97
+ *
98
+ * @default true
99
+ */
100
+ enhance_prompt?: boolean;
101
+ /**
102
+ * The number of inference steps.
103
+ *
104
+ * @default 50
105
+ */
106
+ num_inference_steps?: number;
107
+ }
108
+ /**
109
+ * ProcessInputs combined with model-specific inputs.
110
+ * This ensures fields have the correct descriptions based on the model type.
111
+ * Add fields to ImageGenerationInputs, ImageEditingInputs, VideoModelInputs, or PromptInput
112
+ * to provide model-specific documentation for any field.
113
+ */
114
+ type ModelSpecificProcessInputs<T extends ModelDefinition> = ProcessInputs & ModelSpecificInputs<T>;
115
+ /**
116
+ * Pick only the fields from ModelSpecificProcessInputs that exist in the inferred model inputs,
117
+ * so JSDoc comments will be preserved, while type inference will be accurate.
118
+ */
119
+ type PickDocumentedInputs<T extends ModelDefinition> = Pick<ModelSpecificProcessInputs<T>, keyof ModelSpecificProcessInputs<T> & keyof InferModelInputs<T>>;
120
+ /**
121
+ * Merge documented inputs with inferred inputs, ensuring zod types take precedence
122
+ * while preserving JSDoc comments from ModelSpecificProcessInputs.
123
+ *
124
+ * By intersecting PickDocumentedInputs with InferModelInputs, we get:
125
+ * - JSDoc comments from ModelSpecificProcessInputs (from PickDocumentedInputs)
126
+ * - Accurate types from zod schemas (from InferModelInputs, takes precedence in intersection)
127
+ */
128
+ type MergeDocumentedInputs<T extends ModelDefinition> = PickDocumentedInputs<T> & InferModelInputs<T>;
129
+ /**
130
+ * Options for the process client to generate video or image content.
131
+ *
132
+ * @template T - The model definition type
133
+ */
6
134
  type ProcessOptions<T extends ModelDefinition = ModelDefinition> = {
135
+ /**
136
+ * The model definition to use.
137
+ */
7
138
  model: T;
139
+ /**
140
+ * Optional `AbortSignal` for canceling the request.
141
+ */
8
142
  signal?: AbortSignal;
9
- } & InferModelInputs<T>;
10
- type FileInput = File | Blob | ReadableStream | URL | string;
143
+ } & MergeDocumentedInputs<T>;
11
144
  //#endregion
12
145
  export { FileInput, ProcessOptions };
@@ -17,7 +17,7 @@ const realTimeClientConnectOptionsSchema = z.object({
17
17
  customizeOffer: createAsyncFunctionSchema(z.function()).optional()
18
18
  });
19
19
  const createRealTimeClient = (opts) => {
20
- const { baseUrl, apiKey } = opts;
20
+ const { baseUrl, apiKey, integration } = opts;
21
21
  const connect = async (stream, options) => {
22
22
  const eventEmitter = mitt();
23
23
  const parsedOptions = realTimeClientConnectOptionsSchema.safeParse(options);
@@ -31,6 +31,7 @@ const createRealTimeClient = (opts) => {
31
31
  sessionId,
32
32
  fps: options.model.fps,
33
33
  initialState,
34
+ integration,
34
35
  onRemoteStream,
35
36
  onConnectionStateChange: (state) => {
36
37
  eventEmitter.emit("connectionChange", state);
@@ -1,3 +1,5 @@
1
+ import { buildUserAgent } from "../utils/user-agent.js";
2
+
1
3
  //#region src/realtime/webrtc-connection.ts
2
4
  const ICE_SERVERS = [{ urls: "stun:stun.l.google.com:19302" }];
3
5
  var WebRTCConnection = class {
@@ -9,13 +11,16 @@ var WebRTCConnection = class {
9
11
  constructor(callbacks = {}) {
10
12
  this.callbacks = callbacks;
11
13
  }
12
- async connect(url, localStream, timeout = 25e3) {
14
+ async connect(url, localStream, timeout = 25e3, integration) {
13
15
  const deadline = Date.now() + timeout;
14
16
  this.localStream = localStream;
17
+ const userAgent = encodeURIComponent(buildUserAgent(integration));
18
+ const separator = url.includes("?") ? "&" : "?";
19
+ const wsUrl = `${url}${separator}user_agent=${userAgent}`;
15
20
  await new Promise((resolve, reject) => {
16
21
  this.connectionReject = reject;
17
22
  const timer = setTimeout(() => reject(/* @__PURE__ */ new Error("WebSocket timeout")), timeout);
18
- this.ws = new WebSocket(url);
23
+ this.ws = new WebSocket(wsUrl);
19
24
  this.ws.onopen = () => {
20
25
  clearTimeout(timer);
21
26
  resolve();
@@ -24,7 +24,7 @@ var WebRTCManager = class {
24
24
  }
25
25
  async connect(localStream) {
26
26
  return pRetry(async () => {
27
- await this.connection.connect(this.config.webrtcUrl, localStream);
27
+ await this.connection.connect(this.config.webrtcUrl, localStream, 25e3, this.config.integration);
28
28
  return true;
29
29
  }, {
30
30
  retries: 5,
@@ -13,32 +13,44 @@ declare const modelInputSchemas: {
13
13
  readonly "lucy-pro-t2v": z.ZodObject<{
14
14
  prompt: z.ZodString;
15
15
  seed: z.ZodOptional<z.ZodNumber>;
16
- resolution: z.ZodOptional<z.ZodString>;
16
+ resolution: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
17
+ "720p": "720p";
18
+ "480p": "480p";
19
+ }>>>;
17
20
  orientation: z.ZodOptional<z.ZodString>;
18
21
  }, z.core.$strip>;
19
22
  readonly "lucy-pro-t2i": z.ZodObject<{
20
23
  prompt: z.ZodString;
21
24
  seed: z.ZodOptional<z.ZodNumber>;
22
- resolution: z.ZodOptional<z.ZodString>;
25
+ resolution: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
26
+ "720p": "720p";
27
+ "480p": "480p";
28
+ }>>>;
23
29
  orientation: z.ZodOptional<z.ZodString>;
24
30
  }, z.core.$strip>;
25
31
  readonly "lucy-pro-i2v": z.ZodObject<{
26
32
  prompt: z.ZodString;
27
33
  data: z.ZodUnion<readonly [z.ZodCustom<File, File>, z.ZodCustom<Blob, Blob>, z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>, z.ZodCustom<URL, URL>, z.ZodURL]>;
28
34
  seed: z.ZodOptional<z.ZodNumber>;
29
- resolution: z.ZodOptional<z.ZodString>;
35
+ resolution: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
36
+ "720p": "720p";
37
+ "480p": "480p";
38
+ }>>>;
30
39
  }, z.core.$strip>;
31
40
  readonly "lucy-dev-i2v": z.ZodObject<{
32
41
  prompt: z.ZodString;
33
42
  data: z.ZodUnion<readonly [z.ZodCustom<File, File>, z.ZodCustom<Blob, Blob>, z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>, z.ZodCustom<URL, URL>, z.ZodURL]>;
34
43
  seed: z.ZodOptional<z.ZodNumber>;
35
- resolution: z.ZodOptional<z.ZodString>;
44
+ resolution: z.ZodOptional<z.ZodDefault<z.ZodLiteral<"720p">>>;
36
45
  }, z.core.$strip>;
37
46
  readonly "lucy-pro-v2v": z.ZodObject<{
38
47
  prompt: z.ZodString;
39
48
  data: z.ZodUnion<readonly [z.ZodCustom<File, File>, z.ZodCustom<Blob, Blob>, z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>, z.ZodCustom<URL, URL>, z.ZodURL]>;
40
49
  seed: z.ZodOptional<z.ZodNumber>;
41
- resolution: z.ZodOptional<z.ZodString>;
50
+ resolution: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
51
+ "720p": "720p";
52
+ "480p": "480p";
53
+ }>>>;
42
54
  enhance_prompt: z.ZodOptional<z.ZodBoolean>;
43
55
  num_inference_steps: z.ZodOptional<z.ZodNumber>;
44
56
  }, z.core.$strip>;
@@ -46,7 +58,7 @@ declare const modelInputSchemas: {
46
58
  prompt: z.ZodString;
47
59
  data: z.ZodUnion<readonly [z.ZodCustom<File, File>, z.ZodCustom<Blob, Blob>, z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>, z.ZodCustom<URL, URL>, z.ZodURL]>;
48
60
  seed: z.ZodOptional<z.ZodNumber>;
49
- resolution: z.ZodOptional<z.ZodString>;
61
+ resolution: z.ZodOptional<z.ZodDefault<z.ZodLiteral<"720p">>>;
50
62
  enhance_prompt: z.ZodOptional<z.ZodBoolean>;
51
63
  }, z.core.$strip>;
52
64
  readonly "lucy-pro-flf2v": z.ZodObject<{
@@ -54,13 +66,19 @@ declare const modelInputSchemas: {
54
66
  start: z.ZodUnion<readonly [z.ZodCustom<File, File>, z.ZodCustom<Blob, Blob>, z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>, z.ZodCustom<URL, URL>, z.ZodURL]>;
55
67
  end: z.ZodUnion<readonly [z.ZodCustom<File, File>, z.ZodCustom<Blob, Blob>, z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>, z.ZodCustom<URL, URL>, z.ZodURL]>;
56
68
  seed: z.ZodOptional<z.ZodNumber>;
57
- resolution: z.ZodOptional<z.ZodString>;
69
+ resolution: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
70
+ "720p": "720p";
71
+ "480p": "480p";
72
+ }>>>;
58
73
  }, z.core.$strip>;
59
74
  readonly "lucy-pro-i2i": z.ZodObject<{
60
75
  prompt: z.ZodString;
61
76
  data: z.ZodUnion<readonly [z.ZodCustom<File, File>, z.ZodCustom<Blob, Blob>, z.ZodCustom<ReadableStream<unknown>, ReadableStream<unknown>>, z.ZodCustom<URL, URL>, z.ZodURL]>;
62
77
  seed: z.ZodOptional<z.ZodNumber>;
63
- resolution: z.ZodOptional<z.ZodString>;
78
+ resolution: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
79
+ "720p": "720p";
80
+ "480p": "480p";
81
+ }>>>;
64
82
  enhance_prompt: z.ZodOptional<z.ZodBoolean>;
65
83
  }, z.core.$strip>;
66
84
  };
@@ -71,11 +89,29 @@ type ModelDefinition<T extends Model = Model> = {
71
89
  fps: number;
72
90
  width: number;
73
91
  height: number;
74
- inputSchema: T extends keyof ModelInputSchemas ? ModelInputSchemas[T] : z.ZodObject<any>;
92
+ inputSchema: T extends keyof ModelInputSchemas ? ModelInputSchemas[T] : z.ZodTypeAny;
75
93
  };
76
94
  declare const models: {
77
95
  realtime: <T extends RealTimeModels>(model: T) => ModelDefinition<T>;
96
+ /**
97
+ * Get a video model identifier.
98
+ *
99
+ * Available options:
100
+ * - `"lucy-pro-t2v"` - Text-to-video
101
+ * - `"lucy-pro-i2v"` - Image-to-video
102
+ * - `"lucy-pro-v2v"` - Video-to-video
103
+ * - `"lucy-pro-flf2v"` - First-last-frame-to-video
104
+ * - `"lucy-dev-i2v"` - Image-to-video (Dev quality)
105
+ * - `"lucy-dev-v2v"` - Video-to-video (Dev quality)
106
+ */
78
107
  video: <T extends VideoModels>(model: T) => ModelDefinition<T>;
108
+ /**
109
+ * Get an image model identifier.
110
+ *
111
+ * Available options:
112
+ * - `"lucy-pro-t2i"` - Text-to-image
113
+ * - `"lucy-pro-i2i"` - Image-to-image
114
+ */
79
115
  image: <T extends ImageModels>(model: T) => ModelDefinition<T>;
80
116
  };
81
117
  //#endregion
@@ -28,59 +28,74 @@ const fileInputSchema = z.union([
28
28
  z.instanceof(URL),
29
29
  z.url()
30
30
  ]);
31
+ /**
32
+ * Resolution schema for dev models. Supports only 720p.
33
+ */
34
+ const devResolutionSchema = z.literal("720p").default("720p").optional().describe("The resolution to use for the generation. For dev models, only `720p` is supported.");
35
+ /**
36
+ * Resolution schema for pro models.
37
+ * @param defaultValue - Optional default value (e.g., "720p")
38
+ */
39
+ const proResolutionSchema = () => {
40
+ return z.enum(["720p", "480p"]).optional().describe("The resolution to use for the generation").default("720p");
41
+ };
42
+ /**
43
+ * Resolution schema for lucy-pro-v2v (supports 720p and 480p).
44
+ */
45
+ const proV2vResolutionSchema = z.enum(["720p", "480p"]).optional().describe("The resolution to use for the generation").default("720p");
31
46
  const modelInputSchemas = {
32
47
  "lucy-pro-t2v": z.object({
33
- prompt: z.string(),
34
- seed: z.number().optional(),
35
- resolution: z.string().optional(),
36
- orientation: z.string().optional()
48
+ prompt: z.string().describe("The prompt to use for the generation"),
49
+ seed: z.number().optional().describe("The seed to use for the generation"),
50
+ resolution: proResolutionSchema(),
51
+ orientation: z.string().optional().describe("The orientation to use for the generation")
37
52
  }),
38
53
  "lucy-pro-t2i": z.object({
39
- prompt: z.string(),
40
- seed: z.number().optional(),
41
- resolution: z.string().optional(),
42
- orientation: z.string().optional()
54
+ prompt: z.string().describe("The prompt to use for the generation"),
55
+ seed: z.number().optional().describe("The seed to use for the generation"),
56
+ resolution: proResolutionSchema(),
57
+ orientation: z.string().optional().describe("The orientation to use for the generation")
43
58
  }),
44
59
  "lucy-pro-i2v": z.object({
45
- prompt: z.string(),
46
- data: fileInputSchema,
47
- seed: z.number().optional(),
48
- resolution: z.string().optional()
60
+ prompt: z.string().describe("The prompt to use for the generation"),
61
+ data: fileInputSchema.describe("The image data to use for generation (File, Blob, ReadableStream, URL, or string URL)"),
62
+ seed: z.number().optional().describe("The seed to use for the generation"),
63
+ resolution: proResolutionSchema()
49
64
  }),
50
65
  "lucy-dev-i2v": z.object({
51
- prompt: z.string(),
52
- data: fileInputSchema,
53
- seed: z.number().optional(),
54
- resolution: z.string().optional()
66
+ prompt: z.string().describe("The prompt to use for the generation"),
67
+ data: fileInputSchema.describe("The image data to use for generation (File, Blob, ReadableStream, URL, or string URL)"),
68
+ seed: z.number().optional().describe("The seed to use for the generation"),
69
+ resolution: devResolutionSchema
55
70
  }),
56
71
  "lucy-pro-v2v": z.object({
57
- prompt: z.string(),
58
- data: fileInputSchema,
59
- seed: z.number().optional(),
60
- resolution: z.string().optional(),
61
- enhance_prompt: z.boolean().optional(),
62
- num_inference_steps: z.number().optional()
72
+ prompt: z.string().describe("The prompt to use for the generation"),
73
+ data: fileInputSchema.describe("The video data to use for generation (File, Blob, ReadableStream, URL, or string URL)"),
74
+ seed: z.number().optional().describe("The seed to use for the generation"),
75
+ resolution: proV2vResolutionSchema,
76
+ enhance_prompt: z.boolean().optional().describe("Whether to enhance the prompt"),
77
+ num_inference_steps: z.number().optional().describe("The number of inference steps")
63
78
  }),
64
79
  "lucy-dev-v2v": z.object({
65
- prompt: z.string(),
66
- data: fileInputSchema,
67
- seed: z.number().optional(),
68
- resolution: z.string().optional(),
69
- enhance_prompt: z.boolean().optional()
80
+ prompt: z.string().describe("The prompt to use for the generation"),
81
+ data: fileInputSchema.describe("The video data to use for generation (File, Blob, ReadableStream, URL, or string URL)"),
82
+ seed: z.number().optional().describe("The seed to use for the generation"),
83
+ resolution: devResolutionSchema,
84
+ enhance_prompt: z.boolean().optional().describe("Whether to enhance the prompt")
70
85
  }),
71
86
  "lucy-pro-flf2v": z.object({
72
- prompt: z.string(),
73
- start: fileInputSchema,
74
- end: fileInputSchema,
75
- seed: z.number().optional(),
76
- resolution: z.string().optional()
87
+ prompt: z.string().describe("The prompt to use for the generation"),
88
+ start: fileInputSchema.describe("The start frame image (File, Blob, ReadableStream, URL, or string URL)"),
89
+ end: fileInputSchema.describe("The end frame image (File, Blob, ReadableStream, URL, or string URL)"),
90
+ seed: z.number().optional().describe("The seed to use for the generation"),
91
+ resolution: proResolutionSchema()
77
92
  }),
78
93
  "lucy-pro-i2i": z.object({
79
- prompt: z.string(),
80
- data: fileInputSchema,
81
- seed: z.number().optional(),
82
- resolution: z.string().optional(),
83
- enhance_prompt: z.boolean().optional()
94
+ prompt: z.string().describe("The prompt to use for the generation"),
95
+ data: fileInputSchema.describe("The image data to use for generation (File, Blob, ReadableStream, URL, or string URL)"),
96
+ seed: z.number().optional().describe("The seed to use for the generation"),
97
+ resolution: proResolutionSchema(),
98
+ enhance_prompt: z.boolean().optional().describe("Whether to enhance the prompt")
84
99
  })
85
100
  };
86
101
  const modelDefinitionSchema = z.object({
@@ -104,7 +119,7 @@ const _models = {
104
119
  mirage_v2: {
105
120
  urlPath: "/v1/stream",
106
121
  name: "mirage_v2",
107
- fps: 18,
122
+ fps: 22,
108
123
  width: 1280,
109
124
  height: 704,
110
125
  inputSchema: z.object({})
@@ -0,0 +1,32 @@
1
+ import { VERSION } from "../version.js";
2
+
3
+ //#region src/utils/user-agent.ts
4
+ function getRuntimeEnvironment(globalThisAny = globalThis) {
5
+ if (globalThisAny.window) return "runtime/browser";
6
+ if (globalThisAny.navigator?.userAgent) return `runtime/${globalThisAny.navigator.userAgent.toLowerCase()}`;
7
+ if (globalThisAny.process?.versions?.node) return `runtime/node.js/${globalThisAny.process.version.substring(0)}`;
8
+ if (globalThisAny.EdgeRuntime) return "runtime/vercel-edge";
9
+ return "runtime/unknown";
10
+ }
11
+ /**
12
+ * Builds the User-Agent string for the SDK.
13
+ * Format: decart-js-sdk/{version} lang/js {integration} {runtime}
14
+ *
15
+ * @param integration - Optional integration identifier (e.g., "vercel-ai-sdk/3.0.0")
16
+ * @param globalThisAny - The global object (defaults to globalThis). Can be mocked for testing.
17
+ * @returns Complete User-Agent string
18
+ * @example
19
+ * buildUserAgent() // => "decart-js-sdk/0.0.7 lang/js runtime/node.js/v18.17.0"
20
+ * buildUserAgent("vercel-ai-sdk/3.0.0") // => "decart-js-sdk/0.0.7 lang/js vercel-ai-sdk/3.0.0 runtime/node.js/v18.17.0"
21
+ */
22
+ function buildUserAgent(integration, globalThisAny = globalThis) {
23
+ return [
24
+ `decart-js-sdk/${VERSION}`,
25
+ "lang/js",
26
+ ...integration ? [integration] : [],
27
+ getRuntimeEnvironment(globalThisAny)
28
+ ].join(" ");
29
+ }
30
+
31
+ //#endregion
32
+ export { buildUserAgent };
@@ -0,0 +1,10 @@
1
+ //#region src/version.ts
2
+ /**
3
+ * The current version of the Decart SDK.
4
+ * Injected at build time from package.json.
5
+ * Falls back to '0.0.0-dev' in development.
6
+ */
7
+ const VERSION = "0.0.12";
8
+
9
+ //#endregion
10
+ export { VERSION };
package/package.json CHANGED
@@ -1,61 +1,60 @@
1
1
  {
2
- "name": "@decartai/sdk",
3
- "version": "0.0.7",
4
- "description": "Decart's JavaScript SDK",
5
- "type": "module",
6
- "license": "MIT",
7
- "private": false,
8
- "homepage": "https://github.com/decartai/sdk#readme",
9
- "bugs": {
10
- "url": "https://github.com/decartai/sdk/issues"
11
- },
12
- "repository": {
13
- "type": "git",
14
- "url": "git+https://github.com/decartai/sdk.git"
15
- },
16
- "author": "Adir Amsalem <adir@decart.ai>",
17
- "sideEffects": false,
18
- "files": [
19
- "dist"
20
- ],
21
- "main": "./dist/index.js",
22
- "module": "./dist/index.js",
23
- "types": "./dist/index.d.ts",
24
- "exports": {
25
- ".": "./dist/index.js",
26
- "./package.json": "./package.json"
27
- },
28
- "publishConfig": {
29
- "access": "public"
30
- },
31
- "scripts": {
32
- "build": "tsdown",
33
- "dev": "tsdown --watch",
34
- "dev:example": "vite dev --port 3000",
35
- "test": "vitest unit",
36
- "test:e2e": "vitest e2e",
37
- "typecheck": "tsc --noEmit",
38
- "format": "biome format --write",
39
- "format:check": "biome check",
40
- "lint": "biome lint",
41
- "prepublishOnly": "pnpm build",
42
- "release": "bumpp && npm publish"
43
- },
44
- "devDependencies": {
45
- "@types/node": "^22.15.17",
46
- "biome": "^0.3.3",
47
- "bumpp": "^10.1.0",
48
- "msw": "^2.11.3",
49
- "pkg-pr-new": "^0.0.56",
50
- "tsdown": "^0.14.1",
51
- "typescript": "^5.8.3",
52
- "vite": "^7.1.2",
53
- "vitest": "^3.1.3"
54
- },
55
- "dependencies": {
56
- "mitt": "^3.0.1",
57
- "p-retry": "^6.2.1",
58
- "uuid": "^11.1.0",
59
- "zod": "^4.0.17"
60
- }
61
- }
2
+ "name": "@decartai/sdk",
3
+ "version": "0.0.12",
4
+ "description": "Decart's JavaScript SDK",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "private": false,
8
+ "homepage": "https://github.com/decartai/sdk#readme",
9
+ "bugs": {
10
+ "url": "https://github.com/decartai/sdk/issues"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/DecartAI/sdk"
15
+ },
16
+ "author": "Adir Amsalem <adir@decart.ai>",
17
+ "sideEffects": false,
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "main": "./dist/index.js",
22
+ "module": "./dist/index.js",
23
+ "types": "./dist/index.d.ts",
24
+ "exports": {
25
+ ".": "./dist/index.js",
26
+ "./package.json": "./package.json"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^22.15.17",
33
+ "biome": "^0.3.3",
34
+ "bumpp": "^10.1.0",
35
+ "msw": "^2.11.3",
36
+ "pkg-pr-new": "^0.0.56",
37
+ "tsdown": "^0.14.1",
38
+ "typescript": "^5.8.3",
39
+ "vite": "^7.1.2",
40
+ "vitest": "^3.1.3"
41
+ },
42
+ "dependencies": {
43
+ "mitt": "^3.0.1",
44
+ "p-retry": "^6.2.1",
45
+ "uuid": "^11.1.0",
46
+ "zod": "^4.0.17"
47
+ },
48
+ "scripts": {
49
+ "build": "tsdown",
50
+ "dev": "tsdown --watch",
51
+ "dev:example": "vite dev --port 3000",
52
+ "test": "vitest unit",
53
+ "test:e2e": "vitest e2e",
54
+ "typecheck": "tsc --noEmit",
55
+ "format": "biome format --write",
56
+ "format:check": "biome check",
57
+ "lint": "biome lint",
58
+ "release": "bumpp"
59
+ }
60
+ }