@decartai/sdk 0.1.14 → 0.1.16

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 +1 -1
  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 +1 -1
  24. package/dist/shared/model.js +28 -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 };
@@ -411,4 +411,4 @@ declare const models: {
411
411
  };
412
412
  };
413
413
  //#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 };
414
+ 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 };
@@ -488,18 +488,45 @@ function listModels(options = {}) {
488
488
  });
489
489
  }
490
490
  const models = {
491
+ /**
492
+ * Get a realtime streaming model identifier.
493
+ *
494
+ * Available options:
495
+ * - `"lucy-2.1"` - Lucy 2.1 realtime video editing
496
+ * - `"lucy-2.5"` - Lucy 2.5 realtime video editing
497
+ * - `"lucy-vton-2"` - Lucy virtual try-on 2
498
+ * - `"lucy-vton-3"` - Lucy virtual try-on 3
499
+ * - `"lucy-restyle-2"` - Realtime video restyling
500
+ */
491
501
  realtime: (model) => {
492
502
  warnDeprecated(model);
493
503
  const modelDefinition = _models.realtime[model];
494
504
  if (!modelDefinition) throw createModelNotFoundError(model);
495
505
  return modelDefinition;
496
506
  },
507
+ /**
508
+ * Get a video model identifier.
509
+ *
510
+ * Available options:
511
+ * - `"lucy-clip"` - Video-to-video editing
512
+ * - `"lucy-2.1"` - Long-form video editing (Lucy 2.1)
513
+ * - `"lucy-2.5"` - Long-form video editing (Lucy 2.5)
514
+ * - `"lucy-vton-2"` - Virtual try-on 2 video editing
515
+ * - `"lucy-vton-3"` - Virtual try-on 3 video editing
516
+ * - `"lucy-restyle-2"` - Video restyling
517
+ */
497
518
  video: (model) => {
498
519
  warnDeprecated(model);
499
520
  const modelDefinition = _models.video[model];
500
521
  if (!modelDefinition) throw createModelNotFoundError(model);
501
522
  return modelDefinition;
502
523
  },
524
+ /**
525
+ * Get an image model identifier.
526
+ *
527
+ * Available options:
528
+ * - `"lucy-image-2"` - Image-to-image editing
529
+ */
503
530
  image: (model) => {
504
531
  warnDeprecated(model);
505
532
  const modelDefinition = _models.image[model];
@@ -508,4 +535,4 @@ const models = {
508
535
  }
509
536
  };
510
537
  //#endregion
511
- export { isCanonicalModel, isImageModel, isModel, isRealtimeModel, isVideoModel, listModels, modelAliases, modelDefinitionSchema, models, resolveCanonicalModelAlias, resolveFpsNumber, resolveModelAlias };
538
+ 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.16",
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 };