@decartai/sdk 0.1.14 → 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 (34) hide show
  1. package/README.md +24 -9
  2. package/dist/create-client.js +102 -0
  3. package/dist/files/types.js +4 -1
  4. package/dist/package.js +4 -0
  5. package/dist/process/types.d.ts +2 -2
  6. package/dist/realtime/browser/frame-metadata-diagnostics.js +90 -0
  7. package/dist/realtime/browser/frame-metadata-worker.js +2 -0
  8. package/dist/realtime/browser/mirror-stream.js +1 -1
  9. package/dist/realtime/browser/preflight.js +6 -7
  10. package/dist/realtime/browser/prepare-connection.js +27 -9
  11. package/dist/realtime/client.js +9 -0
  12. package/dist/realtime/config-realtime.js +51 -0
  13. package/dist/realtime/livekit.js +1 -1
  14. package/dist/realtime/media-channel.js +28 -6
  15. package/dist/realtime/methods.js +4 -0
  16. package/dist/realtime/observability/connection-quality.d.ts +3 -3
  17. package/dist/realtime/observability/connection-quality.js +3 -1
  18. package/dist/realtime/observability/realtime-observability.js +2 -16
  19. package/dist/realtime/observability/webrtc-stats.d.ts +3 -3
  20. package/dist/realtime/signaling-channel.js +3 -1
  21. package/dist/realtime/stream-session.js +4 -2
  22. package/dist/realtime/subscribe-client.js +1 -1
  23. package/dist/shared/model.d.ts +23 -4
  24. package/dist/shared/model.js +56 -1
  25. package/dist/shared/types.d.ts +1 -1
  26. package/dist/shared/types.js +6 -0
  27. package/dist/utils/errors.js +1 -1
  28. package/dist/utils/media.js +1 -1
  29. package/dist/utils/user-agent.js +1 -1
  30. package/dist/version.js +9 -4
  31. package/package.json +1 -1
  32. package/dist/realtime/browser/glass-to-glass-diagnostics.js +0 -27
  33. package/dist/realtime/browser/glass-to-glass.js +0 -212
  34. package/dist/realtime/browser/pixel-marker.js +0 -144
@@ -44,43 +44,78 @@ const REALTIME_CONFIG = {
44
44
  telemetryReportIntervalMs: 1e4,
45
45
  telemetryUrl: "https://platform.decart.ai/api/v1/telemetry",
46
46
  telemetryMaxItemsPerReport: 120,
47
+ /**
48
+ * Thresholds for the derived in-session connection-quality signal
49
+ * (see observability/connection-quality.ts). Tuned for a camera-up
50
+ * real-time pipeline (~3–3.5 Mbps upstream, model fps ~25–30). All
51
+ * values are tunable here so behaviour can change without code edits.
52
+ */
47
53
  connectionQuality: {
54
+ /** Rolling-window size used to smooth raw per-sample metrics. */
48
55
  windowSamples: 5,
56
+ /**
57
+ * Samples to wait before the bitrate dimensions count — the encoder
58
+ * and BWE ramp for several seconds after connect, so early low
59
+ * bitrate is not a slow network. RTT/loss/stall start scoring sooner.
60
+ * `decart-try-on` waits 30 samples watching inbound bitrate alone.
61
+ */
49
62
  warmupSamples: 8,
63
+ /** Consecutive worse samples required before the level downgrades. */
50
64
  downgradeConsecutive: 5,
65
+ /** Consecutive better samples required before the level upgrades (recover slow). */
51
66
  upgradeConsecutive: 5,
67
+ /** Round-trip time bands (ms). Bands widen by relayExtraMs on TURN-relayed paths. */
52
68
  rtt: {
53
69
  goodMs: 150,
54
70
  fairMs: 300,
55
71
  poorMs: 500,
56
72
  relayExtraMs: 100
57
73
  },
74
+ /**
75
+ * Mid-stream (steady-state) true glass-to-glass latency bands (ms) — the
76
+ * real per-frame camera→display latency through the model, used for the
77
+ * latency dimension *instead of* RTT when frame-metadata measurement is on.
78
+ * Already includes both network legs, so relayExtraMs does not apply.
79
+ * Excludes startup (see `ttff`). Anchored to Datadog
80
+ * `rt.stream.pipeline_latency_ms` (server-side median ~285ms / p95 ~510ms)
81
+ * plus network + jitter-buffer + decode headroom. Tune with real data.
82
+ */
58
83
  glassToGlass: {
59
84
  goodMs: 500,
60
85
  fairMs: 900,
61
86
  poorMs: 1500
62
87
  },
88
+ /**
89
+ * Time-to-first-frame bands (ms) — startup latency from connect to the
90
+ * first rendered model frame. An order of magnitude larger than mid-stream
91
+ * and judged separately (a slow first frame is a different problem from a
92
+ * laggy steady state). ~4–5s is an acceptable ("fair") cold start today.
93
+ */
63
94
  ttff: {
64
95
  goodMs: 4e3,
65
96
  fairMs: 6e3,
66
97
  poorMs: 1e4
67
98
  },
99
+ /** Fraction of outbound packets the server reports lost (0..1). */
68
100
  loss: {
69
101
  good: .001,
70
102
  fair: .01,
71
103
  poor: .05
72
104
  },
105
+ /** End-to-end frame drop ratio (0..1), when a frame identity is available. */
73
106
  g2gDrop: {
74
107
  good: .001,
75
108
  fair: .01,
76
109
  poor: .05
77
110
  },
111
+ /** Upstream headroom = available BWE ÷ the intended publish bitrate (requiredUpstreamKbps). */
78
112
  upstream: {
79
113
  goodRatio: 1,
80
114
  fairRatio: .8,
81
115
  poorRatio: .5,
82
116
  requiredUpstreamKbps: 3500
83
117
  },
118
+ /** Rendered (inbound) frames-per-second. */
84
119
  stall: {
85
120
  goodFps: 20,
86
121
  fairFps: 12,
@@ -88,13 +123,29 @@ const REALTIME_CONFIG = {
88
123
  }
89
124
  }
90
125
  },
126
+ /**
127
+ * SDK-only preflight (see preflight.ts). Validates WebRTC reachability
128
+ * (does UDP egress work / will the path need TURN) and latency via a
129
+ * throwaway RTCPeerConnection — no backend session, no media server.
130
+ */
91
131
  preflight: {
132
+ /** Public STUN servers used to gather server-reflexive candidates. */
92
133
  defaultStunUrls: ["stun:stun.l.google.com:19302"],
134
+ /** Abort candidate gathering after this long. */
93
135
  iceGatherTimeoutMs: 5e3,
136
+ /** RTT bands (ms) for the preflight verdict. */
94
137
  rtt: {
95
138
  goodMs: 150,
96
139
  marginalMs: 300
97
140
  },
141
+ /**
142
+ * Deep probe (`checkConnectivity({ deep: true, model })`): briefly opens a
143
+ * real session with a synthetic source + frame-metadata measurement to get a
144
+ * true glass-to-glass verdict, then tears it down. Costs a short GPU session.
145
+ * The verdict reuses the in-session `connectionQuality` bands. Duration must
146
+ * cover TTFF (~4–5s) + mid-stream warm-up (~2s) before steady-state samples
147
+ * accrue; resolves early once `minSamples` exist.
148
+ */
98
149
  active: {
99
150
  durationMs: 12e3,
100
151
  minSamples: 5
@@ -23,4 +23,4 @@ function loadLiveKitClient() {
23
23
  return liveKitModulePromise;
24
24
  }
25
25
  //#endregion
26
- export { loadLiveKitClient };
26
+ export { loadLiveKitClient, validateLiveKitModule };
@@ -3,7 +3,7 @@ import { REALTIME_CONFIG } from "./config-realtime.js";
3
3
  import { loadLiveKitClient } from "./livekit.js";
4
4
  import mitt from "mitt";
5
5
  //#region src/realtime/media-channel.ts
6
- function getDefaultVideoPublishOptions(source, videoCodec) {
6
+ function getDefaultVideoPublishOptions(source, videoCodec, frameMetadata = false) {
7
7
  const resolvedCodec = videoCodec ?? REALTIME_CONFIG.livekit.defaultVideoCodec;
8
8
  const maxBitrate = resolvedCodec === "vp9" ? REALTIME_CONFIG.livekit.vp9MaxVideoBitrateBps : REALTIME_CONFIG.livekit.defaultMaxVideoBitrateBps;
9
9
  return {
@@ -13,13 +13,16 @@ function getDefaultVideoPublishOptions(source, videoCodec) {
13
13
  videoEncoding: {
14
14
  maxBitrate,
15
15
  maxFramerate: REALTIME_CONFIG.livekit.defaultPublishFps
16
- }
16
+ },
17
+ ...frameMetadata ? { frameMetadata: { timestamp: true } } : {}
17
18
  };
18
19
  }
19
20
  var LiveKitMediaChannel = class {
21
+ config;
20
22
  room = null;
21
23
  cameraTrackSource = null;
22
24
  remoteStream = null;
25
+ frameMetadataEnabled = false;
23
26
  events = mitt();
24
27
  logger;
25
28
  constructor(config) {
@@ -38,14 +41,32 @@ var LiveKitMediaChannel = class {
38
41
  async connect(opts) {
39
42
  const { Room: LiveKitRoom, RoomEvent, Track } = await loadLiveKitClient();
40
43
  this.cameraTrackSource = Track.Source.Camera;
41
- this.room ??= new LiveKitRoom(REALTIME_CONFIG.livekit.roomOptions);
44
+ if (!this.room) {
45
+ let worker;
46
+ if (this.config.createFrameMetadataWorker) try {
47
+ worker = this.config.createFrameMetadataWorker();
48
+ } catch (error) {
49
+ this.logger.warn("Failed to create LiveKit frame-metadata worker; continuing without latency metrics", { error: error instanceof Error ? error.message : String(error) });
50
+ }
51
+ this.frameMetadataEnabled = worker !== void 0;
52
+ try {
53
+ this.room = new LiveKitRoom({
54
+ ...REALTIME_CONFIG.livekit.roomOptions,
55
+ ...worker ? { frameMetadata: { worker } } : {}
56
+ });
57
+ } catch (error) {
58
+ worker?.terminate();
59
+ this.frameMetadataEnabled = false;
60
+ throw error;
61
+ }
62
+ }
42
63
  const room = this.room;
43
64
  room.on(RoomEvent.TrackSubscribed, (track, _pub, participant) => {
44
65
  if (!participant.identity.startsWith(REALTIME_CONFIG.livekit.inferenceServerIdentityPrefix)) return;
45
66
  if (track.kind !== "video" && track.kind !== "audio") return;
46
67
  const mediaStreamTrack = track.mediaStreamTrack;
47
68
  if (mediaStreamTrack) {
48
- if (track.kind === "video") this.config.observability?.attachRemoteVideoTrack(mediaStreamTrack);
69
+ if (track.kind === "video") this.config.observability?.attachRemoteVideoTrack(track);
49
70
  const tracks = this.remoteStream?.getTracks() ?? [];
50
71
  if (!tracks.includes(mediaStreamTrack)) tracks.push(mediaStreamTrack);
51
72
  this.remoteStream = new MediaStream(tracks);
@@ -79,6 +100,7 @@ var LiveKitMediaChannel = class {
79
100
  this.room = null;
80
101
  this.cameraTrackSource = null;
81
102
  this.remoteStream = null;
103
+ this.frameMetadataEnabled = false;
82
104
  this.config.observability?.setLiveKitRoom(null);
83
105
  if (room) room.disconnect().catch(() => {});
84
106
  }
@@ -86,10 +108,10 @@ var LiveKitMediaChannel = class {
86
108
  if (!this.room) return;
87
109
  for (const track of stream.getTracks()) if (track.kind === "video") {
88
110
  if (!this.cameraTrackSource) throw new Error("Cannot publish video track: media channel is not connected");
89
- await this.room.localParticipant.publishTrack(track, getDefaultVideoPublishOptions(this.cameraTrackSource, this.config.videoCodec));
111
+ await this.room.localParticipant.publishTrack(track, getDefaultVideoPublishOptions(this.cameraTrackSource, this.config.videoCodec, this.frameMetadataEnabled));
90
112
  } else await this.room.localParticipant.publishTrack(track);
91
113
  }
92
114
  };
93
115
  const createLiveKitMediaChannel = (config) => new LiveKitMediaChannel(config);
94
116
  //#endregion
95
- export { createLiveKitMediaChannel };
117
+ export { LiveKitMediaChannel, createLiveKitMediaChannel, getDefaultVideoPublishOptions };
@@ -6,6 +6,10 @@ import { z } from "zod";
6
6
  const setInputSchema = z.object({
7
7
  prompt: z.string().min(1).optional(),
8
8
  enhance: z.boolean().optional().default(true),
9
+ /**
10
+ * - `Blob`/`File`/data:/http(s):/base64 string: bytes traverse the wire as base64.
11
+ * - `"file_..."` id (from `client.files.upload(...).id`): sent as a server-side reference.
12
+ */
9
13
  image: z.union([
10
14
  globalInstanceSchema("Blob"),
11
15
  globalInstanceSchema("File"),
@@ -17,7 +17,7 @@ type ConnectionQualityMetrics = {
17
17
  /**
18
18
  * Mid-stream (steady-state) glass-to-glass latency (ms) — the real per-frame
19
19
  * camera→display latency through the model, excluding startup. Only populated
20
- * when the opt-in pixel-marker measurement is on (`connect({ debugQuality: true })`)
20
+ * when the opt-in frame-metadata measurement is on (`connect({ debugQuality: true })`)
21
21
  * and past warm-up; null otherwise. When present it drives the latency verdict
22
22
  * instead of `rttMs`.
23
23
  */
@@ -36,8 +36,8 @@ type ConnectionQualityMetrics = {
36
36
  /** Server's view of upstream (client→server) jitter in ms, or null. Observational. */
37
37
  upstreamJitterMs: number | null;
38
38
  /**
39
- * End-to-end frame drop ratio (0–1) inferred from the pixel-marker seq stream.
40
- * Only populated under the opt-in g2g measurement; null otherwise.
39
+ * End-to-end frame drop ratio (0–1). Null until frame identity is propagated
40
+ * end-to-end; latency measurement itself only requires the capture timestamp.
41
41
  */
42
42
  g2gDropRatio: number | null;
43
43
  /** Estimated available upstream bandwidth in kbps. Chromium-only — null on Safari/Firefox. */
@@ -76,6 +76,7 @@ function minOrNull(values) {
76
76
  return values.length === 0 ? null : Math.min(...values);
77
77
  }
78
78
  var RingBuffer = class {
79
+ size;
79
80
  values = [];
80
81
  constructor(size) {
81
82
  this.size = size;
@@ -101,6 +102,7 @@ var RingBuffer = class {
101
102
  * warm-up state changes; `current()` returns the latest at any time.
102
103
  */
103
104
  var ConnectionQualityEvaluator = class {
105
+ thresholds;
104
106
  rtt;
105
107
  glassToGlass;
106
108
  loss;
@@ -216,4 +218,4 @@ var ConnectionQualityEvaluator = class {
216
218
  }
217
219
  };
218
220
  //#endregion
219
- export { ConnectionQualityEvaluator, extractSignals, scoreLowerBetter, worst };
221
+ export { ConnectionQualityEvaluator, RANK, extractSignals, scoreLowerBetter, scoreMetrics, worst };
@@ -5,6 +5,7 @@ import { NullTelemetryReporter, TelemetryReporter } from "./telemetry-reporter.j
5
5
  import { WebRTCStatsCollector } from "./webrtc-stats.js";
6
6
  //#region src/realtime/observability/realtime-observability.ts
7
7
  var RealtimeObservability = class {
8
+ options;
8
9
  telemetryReporter = new NullTelemetryReporter();
9
10
  telemetryReporterReady = false;
10
11
  pendingTelemetryDiagnostics = [];
@@ -20,22 +21,7 @@ var RealtimeObservability = class {
20
21
  this.options = options;
21
22
  this.glassToGlass = options.glassToGlass;
22
23
  }
23
- /**
24
- * Wrap the outgoing stream so each frame carries a marker, feeding the shared
25
- * tracker that the reader matches against. Returns the stream to publish
26
- * (unchanged when g2g is off or stamping can't start). Owned here so the
27
- * writer and reader of the tracker share one lifecycle and survive reconnects.
28
- */
29
- attachOutgoingStream(stream, fps) {
30
- if (!this.glassToGlass) return stream;
31
- try {
32
- return this.glassToGlass.attachOutgoingStream(stream, fps);
33
- } catch (error) {
34
- this.options.logger.warn("Failed to start glass-to-glass stamp pump; continuing without it", { error: error instanceof Error ? error.message : String(error) });
35
- return stream;
36
- }
37
- }
38
- /** Feed the remote video track to the marker reader (called from the media channel). */
24
+ /** Feed the LiveKit remote video track to the frame-metadata reader. */
39
25
  attachRemoteVideoTrack(track) {
40
26
  this.glassToGlass?.attachRemoteVideoTrack(track);
41
27
  }
@@ -133,8 +133,8 @@ type WebRTCStats = {
133
133
  };
134
134
  /**
135
135
  * True glass-to-glass latency + end-to-end drop signal, merged in by
136
- * `RealtimeObservability` when the opt-in pixel-marker measurement is active
137
- * (see glass-to-glass.ts). Null otherwise — the stats collector does not
136
+ * `RealtimeObservability` when the opt-in frame-metadata measurement is active.
137
+ * Null otherwise — the stats collector does not
138
138
  * populate it.
139
139
  */
140
140
  glassToGlass: G2GMetrics | null;
@@ -154,4 +154,4 @@ type IceCandidatePair = {
154
154
  remote: IceCandidateInfo;
155
155
  };
156
156
  //#endregion
157
- export { WebRTCStats };
157
+ export { IceCandidateInfo, IceCandidatePair, WebRTCStats };
@@ -36,6 +36,7 @@ function buildInitialStateRequest(initialState) {
36
36
  return null;
37
37
  }
38
38
  var SignalingChannel = class {
39
+ config;
39
40
  ws = null;
40
41
  events = mitt();
41
42
  pendingAcks = [];
@@ -66,7 +67,8 @@ var SignalingChannel = class {
66
67
  const userSetInitialState = opts.initialState != null && (opts.initialState.image != null || opts.initialState.imageRef != null || opts.initialState.prompt != null);
67
68
  const joinMessage = {
68
69
  type: "livekit_join",
69
- passthrough: opts.passthrough ?? !userSetInitialState
70
+ passthrough: opts.passthrough ?? !userSetInitialState,
71
+ ...opts.frameTiming ? { client_capabilities: { frame_timing: true } } : {}
70
72
  };
71
73
  if (!this.writeMessage(joinMessage)) {
72
74
  roomInfoWait.cancel();
@@ -16,6 +16,7 @@ function getInitialImageSizeKb(image) {
16
16
  return Math.max(0, Math.round(bytes / 1024));
17
17
  }
18
18
  var StreamSession = class {
19
+ config;
19
20
  signaling;
20
21
  media;
21
22
  events = mitt();
@@ -109,7 +110,8 @@ var StreamSession = class {
109
110
  const { roomInfo, initialStateAck } = await this.signaling.openAndJoin({
110
111
  connectTimeout: REALTIME_CONFIG.session.connectionTimeoutMs,
111
112
  initialState,
112
- passthrough: this.config.initialPassthrough
113
+ passthrough: this.config.initialPassthrough,
114
+ frameTiming: this.config.frameTiming
113
115
  });
114
116
  this.watchInitialStateAck(initialStateAck, attempt);
115
117
  if (this.disposed || this.currentAttempt !== attempt) {
@@ -266,4 +268,4 @@ var StreamSession = class {
266
268
  }
267
269
  };
268
270
  //#endregion
269
- export { StreamSession };
271
+ export { StreamSession, encodeSubscribeToken };
@@ -122,4 +122,4 @@ const createRealTimeSubscribeClient = (opts) => {
122
122
  return { subscribe };
123
123
  };
124
124
  //#endregion
125
- export { createRealTimeSubscribeClient };
125
+ export { createRealTimeSubscribeClient, decodeSubscribeToken };
@@ -7,6 +7,7 @@ declare const canonicalModelSchema: z.ZodEnum<{
7
7
  "lucy-2.5": "lucy-2.5";
8
8
  "lucy-vton-2": "lucy-vton-2";
9
9
  "lucy-vton-3": "lucy-vton-3";
10
+ "lucy-vton-3.5": "lucy-vton-3.5";
10
11
  "lucy-restyle-2": "lucy-restyle-2";
11
12
  "lucy-clip": "lucy-clip";
12
13
  "lucy-image-2": "lucy-image-2";
@@ -24,10 +25,10 @@ declare const modelAliases: {
24
25
  };
25
26
  /** @internal Test-only helper to reset deprecation warning tracking */
26
27
 
27
- declare const realtimeModels: z.ZodUnion<readonly [z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-2">, z.ZodLiteral<"lucy-vton-3">, z.ZodLiteral<"lucy-restyle-2">, z.ZodLiteral<"lucy-latest">, z.ZodLiteral<"lucy-vton-latest">, z.ZodLiteral<"lucy-restyle-latest">, z.ZodLiteral<"lucy-2.1-vton-2">]>;
28
- declare const videoModels: z.ZodUnion<readonly [z.ZodLiteral<"lucy-clip">, z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-2">, z.ZodLiteral<"lucy-vton-3">, z.ZodLiteral<"lucy-restyle-2">, z.ZodLiteral<"lucy-latest">, z.ZodLiteral<"lucy-vton-latest">, z.ZodLiteral<"lucy-restyle-latest">, z.ZodLiteral<"lucy-clip-latest">, z.ZodLiteral<"lucy-2.1-vton-2">, z.ZodLiteral<"lucy-pro-v2v">, z.ZodLiteral<"lucy-restyle-v2v">]>;
28
+ declare const realtimeModels: z.ZodUnion<readonly [z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-2">, z.ZodLiteral<"lucy-vton-3">, z.ZodLiteral<"lucy-vton-3.5">, z.ZodLiteral<"lucy-restyle-2">, z.ZodLiteral<"lucy-latest">, z.ZodLiteral<"lucy-vton-latest">, z.ZodLiteral<"lucy-restyle-latest">, z.ZodLiteral<"lucy-2.1-vton-2">]>;
29
+ declare const videoModels: z.ZodUnion<readonly [z.ZodLiteral<"lucy-clip">, z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-2">, z.ZodLiteral<"lucy-vton-3">, z.ZodLiteral<"lucy-vton-3.5">, z.ZodLiteral<"lucy-restyle-2">, z.ZodLiteral<"lucy-latest">, z.ZodLiteral<"lucy-vton-latest">, z.ZodLiteral<"lucy-restyle-latest">, z.ZodLiteral<"lucy-clip-latest">, z.ZodLiteral<"lucy-2.1-vton-2">, z.ZodLiteral<"lucy-pro-v2v">, z.ZodLiteral<"lucy-restyle-v2v">]>;
29
30
  declare const imageModels: z.ZodUnion<readonly [z.ZodLiteral<"lucy-image-2">, z.ZodLiteral<"lucy-image-latest">, z.ZodLiteral<"lucy-pro-i2i">]>;
30
- declare const modelSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-2">, z.ZodLiteral<"lucy-vton-3">, z.ZodLiteral<"lucy-restyle-2">, z.ZodLiteral<"lucy-latest">, z.ZodLiteral<"lucy-vton-latest">, z.ZodLiteral<"lucy-restyle-latest">, z.ZodLiteral<"lucy-2.1-vton-2">]>, z.ZodUnion<readonly [z.ZodLiteral<"lucy-clip">, z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-2">, z.ZodLiteral<"lucy-vton-3">, z.ZodLiteral<"lucy-restyle-2">, z.ZodLiteral<"lucy-latest">, z.ZodLiteral<"lucy-vton-latest">, z.ZodLiteral<"lucy-restyle-latest">, z.ZodLiteral<"lucy-clip-latest">, z.ZodLiteral<"lucy-2.1-vton-2">, z.ZodLiteral<"lucy-pro-v2v">, z.ZodLiteral<"lucy-restyle-v2v">]>, z.ZodUnion<readonly [z.ZodLiteral<"lucy-image-2">, z.ZodLiteral<"lucy-image-latest">, z.ZodLiteral<"lucy-pro-i2i">]>]>;
31
+ declare const modelSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-2">, z.ZodLiteral<"lucy-vton-3">, z.ZodLiteral<"lucy-vton-3.5">, z.ZodLiteral<"lucy-restyle-2">, z.ZodLiteral<"lucy-latest">, z.ZodLiteral<"lucy-vton-latest">, z.ZodLiteral<"lucy-restyle-latest">, z.ZodLiteral<"lucy-2.1-vton-2">]>, z.ZodUnion<readonly [z.ZodLiteral<"lucy-clip">, z.ZodLiteral<"lucy-2.1">, z.ZodLiteral<"lucy-2.5">, z.ZodLiteral<"lucy-vton-2">, z.ZodLiteral<"lucy-vton-3">, z.ZodLiteral<"lucy-vton-3.5">, z.ZodLiteral<"lucy-restyle-2">, z.ZodLiteral<"lucy-latest">, z.ZodLiteral<"lucy-vton-latest">, z.ZodLiteral<"lucy-restyle-latest">, z.ZodLiteral<"lucy-clip-latest">, z.ZodLiteral<"lucy-2.1-vton-2">, z.ZodLiteral<"lucy-pro-v2v">, z.ZodLiteral<"lucy-restyle-v2v">]>, z.ZodUnion<readonly [z.ZodLiteral<"lucy-image-2">, z.ZodLiteral<"lucy-image-latest">, z.ZodLiteral<"lucy-pro-i2i">]>]>;
31
32
  type Model = z.infer<typeof modelSchema>;
32
33
  type RealTimeModels = z.infer<typeof realtimeModels>;
33
34
  type VideoModels = z.infer<typeof videoModels>;
@@ -165,6 +166,22 @@ declare const modelInputSchemas: {
165
166
  resolution: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"720p">>>;
166
167
  enhance_prompt: z.ZodOptional<z.ZodBoolean>;
167
168
  }, z.core.$strip>;
169
+ readonly "lucy-vton-3.5": z.ZodObject<{
170
+ prompt: z.ZodString;
171
+ reference_image: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<File, unknown, z.core.$ZodTypeInternals<File, unknown>>, z.ZodType<Blob, unknown, z.core.$ZodTypeInternals<Blob, unknown>>, z.ZodType<ReadableStream<any>, unknown, z.core.$ZodTypeInternals<ReadableStream<any>, unknown>>, z.ZodType<URL, unknown, z.core.$ZodTypeInternals<URL, unknown>>, z.ZodURL, z.ZodObject<{
172
+ uri: z.ZodString;
173
+ type: z.ZodString;
174
+ name: z.ZodString;
175
+ }, z.core.$strip>]>>;
176
+ data: z.ZodUnion<readonly [z.ZodType<File, unknown, z.core.$ZodTypeInternals<File, unknown>>, z.ZodType<Blob, unknown, z.core.$ZodTypeInternals<Blob, unknown>>, z.ZodType<ReadableStream<any>, unknown, z.core.$ZodTypeInternals<ReadableStream<any>, unknown>>, z.ZodType<URL, unknown, z.core.$ZodTypeInternals<URL, unknown>>, z.ZodURL, z.ZodObject<{
177
+ uri: z.ZodString;
178
+ type: z.ZodString;
179
+ name: z.ZodString;
180
+ }, z.core.$strip>]>;
181
+ seed: z.ZodOptional<z.ZodNumber>;
182
+ resolution: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"720p">>>;
183
+ enhance_prompt: z.ZodOptional<z.ZodBoolean>;
184
+ }, z.core.$strip>;
168
185
  readonly "lucy-latest": z.ZodObject<{
169
186
  prompt: z.ZodString;
170
187
  reference_image: z.ZodOptional<z.ZodUnion<readonly [z.ZodType<File, unknown, z.core.$ZodTypeInternals<File, unknown>>, z.ZodType<Blob, unknown, z.core.$ZodTypeInternals<Blob, unknown>>, z.ZodType<ReadableStream<any>, unknown, z.core.$ZodTypeInternals<ReadableStream<any>, unknown>>, z.ZodType<URL, unknown, z.core.$ZodTypeInternals<URL, unknown>>, z.ZodURL, z.ZodObject<{
@@ -381,6 +398,7 @@ declare const models: {
381
398
  * - `"lucy-2.5"` - Lucy 2.5 realtime video editing
382
399
  * - `"lucy-vton-2"` - Lucy virtual try-on 2
383
400
  * - `"lucy-vton-3"` - Lucy virtual try-on 3
401
+ * - `"lucy-vton-3.5"` - Lucy virtual try-on 3.5 (latest)
384
402
  * - `"lucy-restyle-2"` - Realtime video restyling
385
403
  */
386
404
  realtime: <T extends RealTimeModels>(model: T) => ModelDefinition<T>;
@@ -393,6 +411,7 @@ declare const models: {
393
411
  * - `"lucy-2.5"` - Long-form video editing (Lucy 2.5)
394
412
  * - `"lucy-vton-2"` - Virtual try-on 2 video editing
395
413
  * - `"lucy-vton-3"` - Virtual try-on 3 video editing
414
+ * - `"lucy-vton-3.5"` - Virtual try-on 3.5 video editing (latest)
396
415
  * - `"lucy-restyle-2"` - Video restyling
397
416
  */
398
417
  video: <T extends VideoModels>(model: T) => ModelDefinition<T> & {
@@ -411,4 +430,4 @@ declare const models: {
411
430
  };
412
431
  };
413
432
  //#endregion
414
- export { CanonicalModel, CustomModelDefinition, ImageModelDefinition, ImageModels, ListedModelDefinition, Model, ModelDefinition, ModelFps, ModelInputSchemas, ModelKind, RealTimeModels, VideoModelDefinition, VideoModels, isCanonicalModel, isImageModel, isModel, isRealtimeModel, isVideoModel, listModels, modelAliases, models, resolveCanonicalModelAlias, resolveFpsNumber, resolveModelAlias };
433
+ export { CanonicalModel, CustomModelDefinition, ImageModelDefinition, ImageModels, ListedModelDefinition, Model, ModelDefinition, ModelFps, ModelInputSchemas, ModelKind, RealTimeModels, VideoModelDefinition, VideoModels, canonicalModelSchema, imageModels, isCanonicalModel, isImageModel, isModel, isRealtimeModel, isVideoModel, listModels, modelAliases, modelInputSchemas, modelSchema, models, realtimeModels, resolveCanonicalModelAlias, resolveFpsNumber, resolveModelAlias, videoModels };
@@ -7,6 +7,7 @@ const CANONICAL_MODEL_NAMES = [
7
7
  "lucy-2.5",
8
8
  "lucy-vton-2",
9
9
  "lucy-vton-3",
10
+ "lucy-vton-3.5",
10
11
  "lucy-restyle-2",
11
12
  "lucy-clip",
12
13
  "lucy-image-2"
@@ -16,6 +17,7 @@ const CANONICAL_REALTIME_MODEL_NAMES = [
16
17
  "lucy-2.5",
17
18
  "lucy-vton-2",
18
19
  "lucy-vton-3",
20
+ "lucy-vton-3.5",
19
21
  "lucy-restyle-2"
20
22
  ];
21
23
  const CANONICAL_VIDEO_MODEL_NAMES = [
@@ -24,6 +26,7 @@ const CANONICAL_VIDEO_MODEL_NAMES = [
24
26
  "lucy-2.5",
25
27
  "lucy-vton-2",
26
28
  "lucy-vton-3",
29
+ "lucy-vton-3.5",
27
30
  "lucy-restyle-2"
28
31
  ];
29
32
  const CANONICAL_IMAGE_MODEL_NAMES = ["lucy-image-2"];
@@ -54,6 +57,7 @@ const realtimeModels = z.union([
54
57
  z.literal("lucy-2.5"),
55
58
  z.literal("lucy-vton-2"),
56
59
  z.literal("lucy-vton-3"),
60
+ z.literal("lucy-vton-3.5"),
57
61
  z.literal("lucy-restyle-2"),
58
62
  z.literal("lucy-latest"),
59
63
  z.literal("lucy-vton-latest"),
@@ -66,6 +70,7 @@ const videoModels = z.union([
66
70
  z.literal("lucy-2.5"),
67
71
  z.literal("lucy-vton-2"),
68
72
  z.literal("lucy-vton-3"),
73
+ z.literal("lucy-vton-3.5"),
69
74
  z.literal("lucy-restyle-2"),
70
75
  z.literal("lucy-latest"),
71
76
  z.literal("lucy-vton-latest"),
@@ -185,6 +190,7 @@ const modelInputSchemas = {
185
190
  "lucy-2.5": videoEdit2Schema,
186
191
  "lucy-vton-2": videoEdit2Schema,
187
192
  "lucy-vton-3": videoEdit2Schema,
193
+ "lucy-vton-3.5": videoEdit2Schema,
188
194
  "lucy-latest": videoEdit2Schema,
189
195
  "lucy-vton-latest": videoEdit2Schema,
190
196
  "lucy-restyle-latest": restyleSchema,
@@ -259,6 +265,17 @@ const _models = {
259
265
  height: 624,
260
266
  inputSchema: z.object({})
261
267
  },
268
+ "lucy-vton-3.5": {
269
+ urlPath: "/v1/stream",
270
+ name: "lucy-vton-3.5",
271
+ fps: {
272
+ ideal: 30,
273
+ max: 30
274
+ },
275
+ width: 1088,
276
+ height: 624,
277
+ inputSchema: z.object({})
278
+ },
262
279
  "lucy-restyle-2": {
263
280
  urlPath: "/v1/stream",
264
281
  name: "lucy-restyle-2",
@@ -390,6 +407,15 @@ const _models = {
390
407
  height: 624,
391
408
  inputSchema: modelInputSchemas["lucy-vton-3"]
392
409
  },
410
+ "lucy-vton-3.5": {
411
+ urlPath: "/v1/generate/lucy-vton-3.5",
412
+ queueUrlPath: "/v1/jobs/lucy-vton-3.5",
413
+ name: "lucy-vton-3.5",
414
+ fps: 20,
415
+ width: 1088,
416
+ height: 624,
417
+ inputSchema: modelInputSchemas["lucy-vton-3.5"]
418
+ },
393
419
  "lucy-restyle-2": {
394
420
  urlPath: "/v1/generate/lucy-restyle-2",
395
421
  queueUrlPath: "/v1/jobs/lucy-restyle-2",
@@ -488,18 +514,47 @@ function listModels(options = {}) {
488
514
  });
489
515
  }
490
516
  const models = {
517
+ /**
518
+ * Get a realtime streaming model identifier.
519
+ *
520
+ * Available options:
521
+ * - `"lucy-2.1"` - Lucy 2.1 realtime video editing
522
+ * - `"lucy-2.5"` - Lucy 2.5 realtime video editing
523
+ * - `"lucy-vton-2"` - Lucy virtual try-on 2
524
+ * - `"lucy-vton-3"` - Lucy virtual try-on 3
525
+ * - `"lucy-vton-3.5"` - Lucy virtual try-on 3.5 (latest)
526
+ * - `"lucy-restyle-2"` - Realtime video restyling
527
+ */
491
528
  realtime: (model) => {
492
529
  warnDeprecated(model);
493
530
  const modelDefinition = _models.realtime[model];
494
531
  if (!modelDefinition) throw createModelNotFoundError(model);
495
532
  return modelDefinition;
496
533
  },
534
+ /**
535
+ * Get a video model identifier.
536
+ *
537
+ * Available options:
538
+ * - `"lucy-clip"` - Video-to-video editing
539
+ * - `"lucy-2.1"` - Long-form video editing (Lucy 2.1)
540
+ * - `"lucy-2.5"` - Long-form video editing (Lucy 2.5)
541
+ * - `"lucy-vton-2"` - Virtual try-on 2 video editing
542
+ * - `"lucy-vton-3"` - Virtual try-on 3 video editing
543
+ * - `"lucy-vton-3.5"` - Virtual try-on 3.5 video editing (latest)
544
+ * - `"lucy-restyle-2"` - Video restyling
545
+ */
497
546
  video: (model) => {
498
547
  warnDeprecated(model);
499
548
  const modelDefinition = _models.video[model];
500
549
  if (!modelDefinition) throw createModelNotFoundError(model);
501
550
  return modelDefinition;
502
551
  },
552
+ /**
553
+ * Get an image model identifier.
554
+ *
555
+ * Available options:
556
+ * - `"lucy-image-2"` - Image-to-image editing
557
+ */
503
558
  image: (model) => {
504
559
  warnDeprecated(model);
505
560
  const modelDefinition = _models.image[model];
@@ -508,4 +563,4 @@ const models = {
508
563
  }
509
564
  };
510
565
  //#endregion
511
- export { isCanonicalModel, isImageModel, isModel, isRealtimeModel, isVideoModel, listModels, modelAliases, modelDefinitionSchema, models, resolveCanonicalModelAlias, resolveFpsNumber, resolveModelAlias };
566
+ export { canonicalImageModels, canonicalModelSchema, canonicalRealtimeModels, canonicalVideoModels, imageModels, isCanonicalModel, isImageModel, isModel, isRealtimeModel, isVideoModel, listModels, modelAliases, modelDefinitionSchema, modelInputSchemas, modelSchema, models, realtimeModels, resolveCanonicalModelAlias, resolveFpsNumber, resolveModelAlias, videoModels };
@@ -11,4 +11,4 @@ declare const modelStateSchema: z.ZodObject<{
11
11
  }, z.core.$strip>;
12
12
  type ModelState = z.infer<typeof modelStateSchema>;
13
13
  //#endregion
14
- export { ModelState };
14
+ export { ModelState, modelStateSchema };
@@ -6,6 +6,12 @@ const modelStateSchema = z.object({
6
6
  text: z.string().min(1),
7
7
  enhance: z.boolean().optional().default(true)
8
8
  }).optional(),
9
+ /**
10
+ * Initial image for the session. Pass either bytes (`Blob`/`File`/data URL/
11
+ * http(s) URL/base64 string) or a `"file_..."` id returned by
12
+ * `client.files.upload(...)`.id — the SDK detects the prefix and sends a
13
+ * server-side reference instead of base64.
14
+ */
9
15
  image: z.union([
10
16
  globalInstanceSchema("Blob"),
11
17
  globalInstanceSchema("File"),
@@ -98,4 +98,4 @@ function createQueueResultError(message, status) {
98
98
  return createSDKError(ERROR_CODES.QUEUE_RESULT_ERROR, message, { status });
99
99
  }
100
100
  //#endregion
101
- export { ERROR_CODES, classifyWebrtcError, createInvalidApiKeyError, createInvalidBaseUrlError, createInvalidInputError, createLiveKitInitializationError, createModelNotFoundError, createQueueResultError, createQueueStatusError, createQueueSubmitError, createReactNativeSetupRequiredError, createSDKError, createUnsupportedPlatformFeatureError };
101
+ export { ERROR_CODES, classifyWebrtcError, createInvalidApiKeyError, createInvalidBaseUrlError, createInvalidInputError, createLiveKitInitializationError, createModelNotFoundError, createQueueResultError, createQueueStatusError, createQueueSubmitError, createReactNativeSetupRequiredError, createSDKError, createUnsupportedPlatformFeatureError, createWebrtcIceError, createWebrtcServerError, createWebrtcSignalingError, createWebrtcTimeoutError, createWebrtcWebsocketError };
@@ -40,4 +40,4 @@ async function imageToBase64(image) {
40
40
  return blobToBase64(image);
41
41
  }
42
42
  //#endregion
43
- export { imageToBase64 };
43
+ export { blobToBase64, imageToBase64 };
@@ -27,4 +27,4 @@ function buildUserAgent(integration, globalThisAny = globalThis) {
27
27
  ].join(" ");
28
28
  }
29
29
  //#endregion
30
- export { buildUserAgent };
30
+ export { buildUserAgent, getRuntimeEnvironment };
package/dist/version.js CHANGED
@@ -1,9 +1,14 @@
1
+ import { version } from "./package.js";
1
2
  //#region src/version.ts
2
3
  /**
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.
4
+ * The current version of the Decart SDK, read from package.json.
5
+ *
6
+ * Read as a real module binding rather than a build-time `define` replacement:
7
+ * `define` is rejected by the pinned tsdown/rolldown ("Invalid key: define"),
8
+ * so a magic-token approach silently fell back to a placeholder and shipped the
9
+ * wrong version in the User-Agent. The bundler tree-shakes this import down to
10
+ * just the version string at build time.
6
11
  */
7
- const VERSION = typeof __PACKAGE_VERSION__ !== "undefined" ? __PACKAGE_VERSION__ : "0.0.0-dev";
12
+ const VERSION = version;
8
13
  //#endregion
9
14
  export { VERSION };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decartai/sdk",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "Decart's JavaScript SDK",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,27 +0,0 @@
1
- import { SeqTracker, createMarkerReader, createStampPump } from "./glass-to-glass.js";
2
- //#region src/realtime/browser/glass-to-glass-diagnostics.ts
3
- function createBrowserGlassToGlassDiagnostics() {
4
- const tracker = new SeqTracker();
5
- const reader = createMarkerReader(tracker);
6
- let pump;
7
- return {
8
- attachOutgoingStream: (stream, fps) => {
9
- pump?.dispose();
10
- pump = createStampPump(stream, {
11
- tracker,
12
- fps
13
- });
14
- return pump.stream;
15
- },
16
- attachRemoteVideoTrack: (track) => reader.attach(track),
17
- markStart: () => tracker.markStart(performance.now()),
18
- snapshot: () => tracker.snapshot(),
19
- dispose: () => {
20
- pump?.dispose();
21
- pump = void 0;
22
- reader.dispose();
23
- }
24
- };
25
- }
26
- //#endregion
27
- export { createBrowserGlassToGlassDiagnostics };