@xmaxai/sdk 1.0.0 → 1.0.2

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 (38) hide show
  1. package/CHANGELOG.md +10 -2
  2. package/README.md +9 -5
  3. package/dist/{chunk-M5QA6LWS.js → chunk-F567ONBH.js} +32 -190
  4. package/dist/chunk-F567ONBH.js.map +1 -0
  5. package/dist/{chunk-PLU2YVAS.js → chunk-TFGYBN3Q.js} +493 -136
  6. package/dist/chunk-TFGYBN3Q.js.map +1 -0
  7. package/dist/index.cjs +76 -294
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +376 -10
  10. package/dist/index.d.ts +376 -10
  11. package/dist/index.js +1003 -9
  12. package/dist/index.js.map +1 -1
  13. package/dist/react/index.cjs +34 -277
  14. package/dist/react/index.cjs.map +1 -1
  15. package/dist/react/index.d.cts +1 -3
  16. package/dist/react/index.d.ts +1 -3
  17. package/dist/react/index.js +6 -26
  18. package/dist/react/index.js.map +1 -1
  19. package/dist/{rtc-manager-gYDkADGw.d.cts → rtc-manager-DnQoznIg.d.cts} +2 -17
  20. package/dist/{rtc-manager-gYDkADGw.d.ts → rtc-manager-DnQoznIg.d.ts} +2 -17
  21. package/dist/video-file-stream-4TAGKL2Q.js +3 -0
  22. package/dist/{video-file-stream-UXJ6TNIB.js.map → video-file-stream-4TAGKL2Q.js.map} +1 -1
  23. package/package.json +1 -6
  24. package/dist/chunk-7X7QCO3O.js +0 -992
  25. package/dist/chunk-7X7QCO3O.js.map +0 -1
  26. package/dist/chunk-EGNRAZ5U.js +0 -432
  27. package/dist/chunk-EGNRAZ5U.js.map +0 -1
  28. package/dist/chunk-M5QA6LWS.js.map +0 -1
  29. package/dist/chunk-PLU2YVAS.js.map +0 -1
  30. package/dist/experimental/index.cjs +0 -3873
  31. package/dist/experimental/index.cjs.map +0 -1
  32. package/dist/experimental/index.d.cts +0 -2
  33. package/dist/experimental/index.d.ts +0 -2
  34. package/dist/experimental/index.js +0 -5
  35. package/dist/experimental/index.js.map +0 -1
  36. package/dist/index-BEgtCLkJ.d.cts +0 -346
  37. package/dist/index-D9wwNTfP.d.ts +0 -346
  38. package/dist/video-file-stream-UXJ6TNIB.js +0 -4
@@ -1,992 +0,0 @@
1
- import { XmaxOpenClient, XMAX_OPEN_API_PRODUCTION_BASE_URL, RtcManager, ACTIVE_STATUS, createNativeCameraStream, createTracksRtcRoomEvent, createStopRtcRoomEvent, createTaskUid, createStartRtcRoomEvent, createDragTrackController, notifyError, getFitContentRect } from './chunk-M5QA6LWS.js';
2
- import { createSDKI18n, resolveUploadVideoSize, DEFAULT_SESSION_TARGET_SIZE, resolveRtcPublishFps, resolveSessionTargetSize } from './chunk-PLU2YVAS.js';
3
-
4
- // src/drag/remote-view-host.ts
5
- function createRemoteViewHost(wrapper) {
6
- const computed = getComputedStyle(wrapper);
7
- if (computed.position === "static") {
8
- wrapper.style.position = "relative";
9
- }
10
- const videoHost = document.createElement("div");
11
- videoHost.dataset.XmaxRemoteVideo = "true";
12
- videoHost.style.cssText = "position:relative;z-index:0;width:100%;height:100%;overflow:hidden;display:flex;align-items:center;justify-content:center;";
13
- const dragHost = document.createElement("div");
14
- dragHost.dataset.XmaxDragSurface = "true";
15
- dragHost.style.cssText = "position:absolute;inset:0;z-index:20;touch-action:none;";
16
- wrapper.replaceChildren();
17
- wrapper.appendChild(videoHost);
18
- wrapper.appendChild(dragHost);
19
- return { wrapper, videoHost, dragHost };
20
- }
21
-
22
- // src/shared/ref-image.ts
23
- async function resolveRefImageUrl(client, input) {
24
- if (input instanceof File) {
25
- return (await client.uploadImage(input)).url;
26
- }
27
- const raw = input.trim();
28
- if (!raw) {
29
- return "";
30
- }
31
- if (/^https?:\/\//i.test(raw)) {
32
- return raw;
33
- }
34
- const res = await fetch(raw);
35
- if (!res.ok) {
36
- throw new Error(`Failed to load ref image: ${res.status}`);
37
- }
38
- const blob = await res.blob();
39
- const mime = blob.type || "image/png";
40
- const ext = mime === "image/jpeg" ? "jpg" : mime === "image/webp" ? "webp" : mime === "image/gif" ? "gif" : "png";
41
- const file = new File([blob], `ref.${ext}`, { type: mime });
42
- return (await client.uploadImage(file)).url;
43
- }
44
-
45
- // src/realtime/initial-state.ts
46
- var DEFAULT_RTC_START_MODEL = "default";
47
- function resolveGenerationModel(model) {
48
- const trimmed = model?.trim();
49
- return trimmed || DEFAULT_RTC_START_MODEL;
50
- }
51
- function resolvePromptText(prompt) {
52
- if (typeof prompt === "string") {
53
- return prompt.trim();
54
- }
55
- return prompt?.text?.trim() ?? "";
56
- }
57
- function resolveInitialRefImage(initialState) {
58
- if (!initialState) {
59
- return void 0;
60
- }
61
- if (typeof initialState.refImage === "string" && initialState.refImage.trim()) {
62
- return initialState.refImage.trim();
63
- }
64
- if (typeof initialState.image === "string" && initialState.image.trim()) {
65
- return initialState.image.trim();
66
- }
67
- return void 0;
68
- }
69
- function shouldAutoStartOnConnect(initialState) {
70
- return initialState?.autoStart === true;
71
- }
72
-
73
- // src/realtime/prewarm.ts
74
- var RealtimePrewarmHandle = class _RealtimePrewarmHandle {
75
- constructor(client, rtc, sessionUid, modelName) {
76
- this.client = client;
77
- this.rtc = rtc;
78
- this.sessionUid = sessionUid;
79
- this.consumed = false;
80
- this.disposed = false;
81
- this.modelName = modelName;
82
- }
83
- static async create(model, clientOptions) {
84
- const modelName = model.name.trim();
85
- if (!modelName) {
86
- throw new Error("model.name is required");
87
- }
88
- const sdkI18n = createSDKI18n({});
89
- const client = new XmaxOpenClient({
90
- apiKey: clientOptions.apiKey,
91
- authToken: clientOptions.authToken,
92
- baseUrl: clientOptions.baseUrl ?? XMAX_OPEN_API_PRODUCTION_BASE_URL,
93
- onError: clientOptions.onError
94
- });
95
- const rtc = new RtcManager({
96
- onLog: (entry) => clientOptions.onLog?.({ scope: "rtc", ...entry }),
97
- onRemoteSeiReceived: clientOptions.onRemoteSei,
98
- onSeiGateChange: clientOptions.onSeiGateChange,
99
- i18n: sdkI18n
100
- });
101
- const createdSession = await client.createSession(modelName);
102
- const sessionUid = createdSession.sessionUid?.trim();
103
- if (!sessionUid) {
104
- throw new Error("Session uid is missing");
105
- }
106
- const joinInfo = client.getRtcJoinInfo(createdSession);
107
- await rtc.join(joinInfo);
108
- const handle = new _RealtimePrewarmHandle(client, rtc, sessionUid, modelName);
109
- client.startHeartbeat(
110
- sessionUid,
111
- clientOptions.heartbeatIntervalMs ?? 1e4,
112
- (heartbeatSession) => {
113
- if (heartbeatSession.status !== ACTIVE_STATUS) {
114
- void handle.cancel();
115
- }
116
- },
117
- () => {
118
- void handle.cancel();
119
- }
120
- );
121
- return handle;
122
- }
123
- consume(expectedModelName) {
124
- const normalized = expectedModelName.trim();
125
- if (this.consumed || this.disposed || !normalized || this.modelName !== normalized) {
126
- return null;
127
- }
128
- this.consumed = true;
129
- return {
130
- client: this.client,
131
- rtc: this.rtc,
132
- sessionUid: this.sessionUid
133
- };
134
- }
135
- async cancel() {
136
- if (this.consumed || this.disposed) {
137
- return;
138
- }
139
- this.disposed = true;
140
- this.client.beginTeardown();
141
- try {
142
- await this.client.closeSession(this.sessionUid);
143
- } catch {
144
- }
145
- try {
146
- await this.rtc.leave();
147
- } catch {
148
- }
149
- this.client.endTeardown();
150
- }
151
- };
152
-
153
- // src/realtime/session.ts
154
- function resolvePromptInput(prompt) {
155
- if (typeof prompt === "string") {
156
- return prompt.trim();
157
- }
158
- return prompt?.text?.trim() ?? "";
159
- }
160
- function resolveRefImagePath(refImage) {
161
- const trimmed = refImage?.trim();
162
- return trimmed || void 0;
163
- }
164
- function getVideoTrack(stream) {
165
- const track = stream.getVideoTracks()[0];
166
- if (!track) {
167
- throw new Error("Missing video track in MediaStream");
168
- }
169
- return track;
170
- }
171
- function readVideoSize(track) {
172
- const settings = track.getSettings?.();
173
- if (typeof settings?.width === "number" && settings.width > 0 && typeof settings?.height === "number" && settings.height > 0) {
174
- return { width: settings.width, height: settings.height };
175
- }
176
- return null;
177
- }
178
- var RealtimeSession = class _RealtimeSession {
179
- constructor(client, rtc, reportError, options, clientOptions) {
180
- this.sessionUid = null;
181
- this.taskUid = null;
182
- this.localVideoSize = null;
183
- this.currentPrompt = "";
184
- this.currentGenerationModel = "";
185
- this.currentStaticGenerate = void 0;
186
- this.disconnected = false;
187
- this.remoteViewHost = null;
188
- this.dragController = null;
189
- this.dragTrackFitMode = "cover";
190
- this.sessionTargetSize = null;
191
- this.mirroredInputStream = null;
192
- this.hiddenRemoteElement = null;
193
- this.remoteStreamNotifyTimer = null;
194
- this.lastNotifiedRemoteStream = null;
195
- this.dragOption = void 0;
196
- this.client = client;
197
- this.rtc = rtc;
198
- this.reportError = reportError;
199
- this.onRemoteStream = options.onRemoteStream;
200
- this.onPublishPipelineWaitChange = clientOptions?.onPublishPipelineWaitChange;
201
- if (options.remoteElement) {
202
- this.remoteElement = options.remoteElement;
203
- if (options.drag !== false) {
204
- this.remoteViewHost = createRemoteViewHost(this.remoteElement);
205
- }
206
- return;
207
- }
208
- if (options.onRemoteStream) {
209
- const hidden = document.createElement("div");
210
- hidden.setAttribute("data-Xmax-remote-host", "true");
211
- hidden.style.cssText = "position:fixed;left:-9999px;top:-9999px;width:1px;height:1px;opacity:0;pointer-events:none;overflow:hidden";
212
- document.body.appendChild(hidden);
213
- this.hiddenRemoteElement = hidden;
214
- this.remoteElement = hidden;
215
- this.remoteViewHost = createRemoteViewHost(hidden);
216
- this.rtc.setOnRemotePlayerMounted(() => {
217
- this.scheduleNotifyRemoteStream();
218
- });
219
- return;
220
- }
221
- this.remoteElement = null;
222
- }
223
- get remoteVideoContainer() {
224
- return this.remoteViewHost?.videoHost ?? this.remoteElement;
225
- }
226
- static async connect(stream, options, clientOptions) {
227
- const sdkI18n = createSDKI18n({});
228
- const notifyUserError = clientOptions.onError;
229
- const reportError = (error, fallbackMessage) => {
230
- throw notifyError(error, notifyUserError, fallbackMessage ?? sdkI18n.t("errors.requestFailed"));
231
- };
232
- const modelName = options.model.name.trim();
233
- const prewarmed = options.prewarmed instanceof RealtimePrewarmHandle ? options.prewarmed.consume(modelName) : null;
234
- const client = prewarmed?.client ?? new XmaxOpenClient({
235
- apiKey: clientOptions.apiKey,
236
- authToken: clientOptions.authToken,
237
- baseUrl: clientOptions.baseUrl ?? XMAX_OPEN_API_PRODUCTION_BASE_URL,
238
- onError: notifyUserError
239
- });
240
- const rtc = prewarmed?.rtc ?? new RtcManager({
241
- onLog: (entry) => clientOptions.onLog?.({ scope: "rtc", ...entry }),
242
- onRemoteSeiReceived: clientOptions.onRemoteSei,
243
- onSeiGateChange: clientOptions.onSeiGateChange,
244
- i18n: sdkI18n
245
- });
246
- const session = new _RealtimeSession(client, rtc, reportError, options, clientOptions);
247
- try {
248
- await session.bootstrap(stream, options, clientOptions.heartbeatIntervalMs ?? 1e4, prewarmed);
249
- return session;
250
- } catch (error) {
251
- await session.safeDisconnect();
252
- throw reportError(error);
253
- }
254
- }
255
- async bootstrap(stream, options, heartbeatIntervalMs, prewarmed = null) {
256
- this.dragOption = options.drag;
257
- const modelName = options.model.name.trim();
258
- if (!modelName) {
259
- throw new Error("model.name is required");
260
- }
261
- if (prewarmed) {
262
- this.sessionUid = prewarmed.sessionUid;
263
- } else {
264
- const createdSession = await this.client.createSession(modelName);
265
- if (!createdSession.sessionUid?.trim()) {
266
- throw new Error("Session uid is missing");
267
- }
268
- this.sessionUid = createdSession.sessionUid;
269
- this.client.startHeartbeat(
270
- createdSession.sessionUid,
271
- heartbeatIntervalMs,
272
- (heartbeatSession) => {
273
- if (heartbeatSession.status !== ACTIVE_STATUS) {
274
- void this.safeDisconnect();
275
- }
276
- },
277
- () => {
278
- void this.safeDisconnect();
279
- }
280
- );
281
- const joinInfo = this.client.getRtcJoinInfo(createdSession);
282
- await this.rtc.join(joinInfo);
283
- }
284
- if (options.localElement) {
285
- this.rtc.setLocalVideoContainer(options.localElement);
286
- }
287
- if (this.remoteVideoContainer) {
288
- this.rtc.setRemoteVideoContainer(this.remoteVideoContainer);
289
- }
290
- this.sessionSizeOverride = options.size;
291
- const videoTrack = getVideoTrack(stream);
292
- const isFileInput = options.inputKind === "file";
293
- this.dragTrackFitMode = isFileInput ? "contain" : "cover";
294
- const rawVideoSize = readVideoSize(videoTrack);
295
- const publishSize = options.size ?? (rawVideoSize ? resolveUploadVideoSize(rawVideoSize.width, rawVideoSize.height) : DEFAULT_SESSION_TARGET_SIZE);
296
- let publishTrack = videoTrack;
297
- if (isFileInput) {
298
- if (options.size) {
299
- this.localVideoSize = { width: options.size[0], height: options.size[1] };
300
- } else if (rawVideoSize) {
301
- this.localVideoSize = { width: rawVideoSize.width, height: rawVideoSize.height };
302
- } else {
303
- this.localVideoSize = null;
304
- }
305
- } else if (options.prebuiltCameraStream) {
306
- this.mirroredInputStream = options.prebuiltCameraStream;
307
- publishTrack = options.prebuiltCameraStream.videoTrack;
308
- this.localVideoSize = {
309
- width: options.prebuiltCameraStream.width,
310
- height: options.prebuiltCameraStream.height
311
- };
312
- } else {
313
- const processedStream = await createNativeCameraStream(stream);
314
- this.mirroredInputStream = processedStream;
315
- publishTrack = processedStream.videoTrack;
316
- this.localVideoSize = { width: processedStream.width, height: processedStream.height };
317
- }
318
- const initialState = options.initialState;
319
- this.currentPrompt = resolvePromptText(initialState?.prompt);
320
- this.currentGenerationModel = resolveGenerationModel(initialState?.model);
321
- this.currentStaticGenerate = initialState?.staticGenerate;
322
- const publishFpsOptions = {
323
- mobile: options.mobile,
324
- highQuality: true,
325
- fps: isFileInput ? options.model.fps : resolveRtcPublishFps({ mobile: options.mobile })
326
- };
327
- await this.rtc.startExternalVideoPublishing(publishTrack, publishSize, publishFpsOptions);
328
- let initialRefImageUrl;
329
- const initialRefImage = resolveInitialRefImage(initialState);
330
- if (initialRefImage) {
331
- initialRefImageUrl = await resolveRefImageUrl(this.client, initialRefImage);
332
- } else if (initialState?.image instanceof File) {
333
- initialRefImageUrl = await resolveRefImageUrl(this.client, initialState.image);
334
- } else if (initialState?.image instanceof Blob) {
335
- const mime = initialState.image.type || "image/png";
336
- const file = new File([initialState.image], "ref-image", { type: mime });
337
- initialRefImageUrl = await resolveRefImageUrl(this.client, file);
338
- }
339
- if (options.localElement) {
340
- queueMicrotask(() => this.refreshLocalPreview());
341
- }
342
- if (shouldAutoStartOnConnect(initialState)) {
343
- await this.runStart({
344
- prompt: this.currentPrompt || void 0,
345
- model: this.currentGenerationModel || void 0,
346
- size: options.size,
347
- refImage: initialRefImageUrl,
348
- staticGenerate: this.currentStaticGenerate
349
- });
350
- }
351
- }
352
- async setPrompt(prompt, _options) {
353
- try {
354
- const promptText = resolvePromptInput(prompt);
355
- this.currentPrompt = promptText;
356
- if (!this.taskUid) {
357
- await this.runStart({
358
- prompt: promptText || void 0
359
- });
360
- return;
361
- }
362
- await this.restart({ prompt: promptText });
363
- } catch (error) {
364
- this.reportError(error);
365
- }
366
- }
367
- async set(input) {
368
- try {
369
- let refImage;
370
- if (input.image === null) {
371
- refImage = void 0;
372
- } else if (input.image !== void 0) {
373
- refImage = await this.setRefImage(input.image);
374
- }
375
- const prompt = input.prompt !== void 0 ? resolvePromptInput(input.prompt) : void 0;
376
- if (prompt !== void 0) {
377
- this.currentPrompt = prompt;
378
- }
379
- await this.restart({
380
- prompt,
381
- refImage
382
- });
383
- } catch (error) {
384
- this.reportError(error);
385
- }
386
- }
387
- async setImage(image, options) {
388
- try {
389
- const refImage = await this.setRefImage(image);
390
- const prompt = options?.prompt ? resolvePromptInput(options.prompt) : void 0;
391
- if (prompt !== void 0) {
392
- this.currentPrompt = prompt;
393
- }
394
- await this.restart({
395
- prompt,
396
- refImage
397
- });
398
- } catch (error) {
399
- this.reportError(error);
400
- }
401
- }
402
- async setRefImage(input) {
403
- try {
404
- const resolved = await resolveRefImageUrl(this.client, input);
405
- return resolved;
406
- } catch (error) {
407
- this.reportError(error);
408
- }
409
- }
410
- async restart(options) {
411
- try {
412
- let resolvedRefImage;
413
- if (options && "refImage" in options) {
414
- const ref = options.refImage;
415
- if (ref === null || ref === "") {
416
- resolvedRefImage = void 0;
417
- } else if (typeof ref === "string" && ref.trim()) {
418
- resolvedRefImage = await this.setRefImage(ref.trim());
419
- }
420
- }
421
- if (options?.prompt !== void 0) {
422
- this.currentPrompt = options.prompt.trim();
423
- }
424
- if (options?.model !== void 0) {
425
- this.currentGenerationModel = resolveGenerationModel(options.model);
426
- }
427
- if (options?.staticGenerate !== void 0) {
428
- this.currentStaticGenerate = options.staticGenerate;
429
- }
430
- await this.runStart({
431
- prompt: this.currentPrompt || void 0,
432
- model: this.currentGenerationModel || void 0,
433
- size: options?.size,
434
- refImage: resolvedRefImage,
435
- staticGenerate: this.currentStaticGenerate
436
- });
437
- } catch (error) {
438
- this.reportError(error);
439
- }
440
- }
441
- async setMode(options) {
442
- return this.restart(options);
443
- }
444
- async refreshRemoteOutput(options) {
445
- if (!this.remoteVideoContainer) {
446
- return;
447
- }
448
- this.rtc.setRemoteVideoContainer(this.remoteVideoContainer);
449
- await this.rtc.refreshRemoteVideoBinding(options);
450
- this.scheduleNotifyRemoteStream();
451
- }
452
- refreshLocalPreview() {
453
- this.rtc.refreshLocalVideoPreview();
454
- }
455
- getInputPreviewStream() {
456
- return this.mirroredInputStream?.previewStream ?? null;
457
- }
458
- detachRemoteOutput() {
459
- this.rtc.setRemoteVideoContainer(null);
460
- }
461
- async sendTracks(tracks) {
462
- if (!this.rtc.snapshot.joined || !this.taskUid) {
463
- return;
464
- }
465
- try {
466
- await this.rtc.sendRoomEvent(
467
- createTracksRtcRoomEvent({
468
- userId: this.rtc.snapshot.userId ?? void 0,
469
- uid: this.taskUid,
470
- sessionUid: this.taskUid,
471
- tracks
472
- })
473
- );
474
- } catch {
475
- }
476
- }
477
- async stop(options) {
478
- this.updateDragController(false);
479
- const preserveRemoteDom = options?.preserveRemoteDom ?? false;
480
- if (preserveRemoteDom) {
481
- this.rtc.setPreserveRemoteDom(true);
482
- }
483
- if (!this.rtc.snapshot.joined) {
484
- this.rtc.clearRemoteVideo({ preserveDom: preserveRemoteDom });
485
- if (!preserveRemoteDom && this.remoteVideoContainer) {
486
- this.rtc.setRemoteVideoContainer(null);
487
- }
488
- this.taskUid = null;
489
- if (preserveRemoteDom) {
490
- this.rtc.setPreserveRemoteDom(false);
491
- }
492
- return;
493
- }
494
- try {
495
- await this.rtc.sendRoomEvent(
496
- createStopRtcRoomEvent({
497
- userId: this.rtc.snapshot.userId ?? void 0,
498
- sessionUid: this.taskUid ?? void 0
499
- })
500
- );
501
- } finally {
502
- this.rtc.clearRemoteVideo({ preserveDom: preserveRemoteDom });
503
- if (!preserveRemoteDom && this.remoteVideoContainer) {
504
- this.rtc.setRemoteVideoContainer(null);
505
- }
506
- this.taskUid = null;
507
- if (preserveRemoteDom) {
508
- this.rtc.setPreserveRemoteDom(false);
509
- }
510
- }
511
- }
512
- async disconnect(options) {
513
- if (this.disconnected) {
514
- return;
515
- }
516
- this.disconnected = true;
517
- await this.safeDisconnect(options);
518
- }
519
- getSessionUid() {
520
- return this.sessionUid;
521
- }
522
- async runStart(options) {
523
- if (!this.rtc.snapshot.joined) {
524
- return;
525
- }
526
- const startPrompt = options.prompt?.trim() ?? this.currentPrompt;
527
- if (options.model !== void 0) {
528
- this.currentGenerationModel = resolveGenerationModel(options.model);
529
- }
530
- if (options.staticGenerate !== void 0) {
531
- this.currentStaticGenerate = options.staticGenerate;
532
- }
533
- const modelLabel = resolveGenerationModel(this.currentGenerationModel);
534
- await this.rtc.ensurePublishedInputBeforeStart();
535
- this.rtc.setRemoteVideoContainer(null);
536
- this.rtc.clearRemoteVideo();
537
- const size = resolveSessionTargetSize({
538
- localVideoSize: this.localVideoSize,
539
- overrideSize: options.size ?? this.sessionSizeOverride
540
- });
541
- this.sessionTargetSize = size;
542
- const taskUid = createTaskUid();
543
- this.taskUid = taskUid;
544
- this.rtc.configureSessionSei(taskUid);
545
- try {
546
- if (this.remoteVideoContainer) {
547
- this.rtc.setRemoteVideoContainer(this.remoteVideoContainer);
548
- }
549
- const startRoomEvent = createStartRtcRoomEvent({
550
- userId: this.rtc.snapshot.userId ?? void 0,
551
- uid: taskUid,
552
- sessionUid: taskUid,
553
- model: modelLabel,
554
- size,
555
- prompt: startPrompt,
556
- refImagePath: resolveRefImagePath(options.refImage),
557
- staticGenerate: this.currentStaticGenerate
558
- });
559
- console.log("[Xmax SDK] \u771F\u5B9E\u53D1\u9001 start ->", startRoomEvent);
560
- await this.rtc.sendRoomEvent(startRoomEvent);
561
- await this.rtc.refreshRemoteVideoBinding({ force: true });
562
- this.updateDragController(true);
563
- this.scheduleNotifyRemoteStream();
564
- } catch (error) {
565
- this.rtc.configureSessionSei(null);
566
- throw error;
567
- }
568
- }
569
- isDragEnabled() {
570
- if (this.dragOption === false) {
571
- return false;
572
- }
573
- if (this.dragOption === true) {
574
- return true;
575
- }
576
- return Boolean(this.remoteElement && !this.hiddenRemoteElement);
577
- }
578
- updateDragController(active) {
579
- const dragHost = this.remoteViewHost?.dragHost;
580
- if (!dragHost || !active || !this.taskUid || !this.isDragEnabled()) {
581
- this.dragController?.setEnabled(false);
582
- return;
583
- }
584
- const targetSize = this.sessionTargetSize ?? DEFAULT_SESSION_TARGET_SIZE;
585
- if (!this.dragController) {
586
- this.dragController = createDragTrackController(dragHost, {
587
- targetSize,
588
- fitMode: this.dragTrackFitMode,
589
- mirrored: false,
590
- enabled: true,
591
- onTracks: (tracks) => {
592
- const media = this.remoteViewHost?.videoHost?.querySelector("video, canvas");
593
- const mediaRect = media?.getBoundingClientRect();
594
- const dragRect = dragHost.getBoundingClientRect();
595
- console.log("[Xmax] sendTracks", {
596
- taskUid: this.taskUid,
597
- targetSize: this.sessionTargetSize,
598
- fitMode: this.dragTrackFitMode,
599
- tracks,
600
- dragRect: dragRect ? { w: dragRect.width, h: dragRect.height } : null,
601
- mediaRect: mediaRect ? { w: mediaRect.width, h: mediaRect.height, l: mediaRect.left, t: mediaRect.top } : null
602
- });
603
- void this.sendTracks(tracks);
604
- }
605
- });
606
- return;
607
- }
608
- this.dragController.setTargetSize(targetSize);
609
- this.dragController.setFitMode(this.dragTrackFitMode);
610
- this.dragController.setMirrored(false);
611
- this.dragController.setEnabled(true);
612
- }
613
- scheduleNotifyRemoteStream() {
614
- if (!this.onRemoteStream) {
615
- return;
616
- }
617
- this.clearRemoteStreamNotifyTimer();
618
- if (this.notifyRemoteStreamOnce()) {
619
- return;
620
- }
621
- let attempts = 0;
622
- this.remoteStreamNotifyTimer = setInterval(() => {
623
- attempts += 1;
624
- if (this.notifyRemoteStreamOnce() || attempts >= 60) {
625
- this.clearRemoteStreamNotifyTimer();
626
- }
627
- }, 500);
628
- }
629
- notifyRemoteStreamOnce() {
630
- const videoRoot = this.remoteVideoContainer;
631
- if (!this.onRemoteStream || !videoRoot) {
632
- return false;
633
- }
634
- const video = videoRoot instanceof HTMLVideoElement ? videoRoot : videoRoot.querySelector("video");
635
- if (!(video instanceof HTMLVideoElement) || !(video.srcObject instanceof MediaStream)) {
636
- return false;
637
- }
638
- if (this.lastNotifiedRemoteStream === video.srcObject) {
639
- return true;
640
- }
641
- this.lastNotifiedRemoteStream = video.srcObject;
642
- this.onRemoteStream(video.srcObject);
643
- return true;
644
- }
645
- clearRemoteStreamNotifyTimer() {
646
- if (this.remoteStreamNotifyTimer !== null) {
647
- clearInterval(this.remoteStreamNotifyTimer);
648
- this.remoteStreamNotifyTimer = null;
649
- }
650
- }
651
- async safeDisconnect(options) {
652
- this.clearRemoteStreamNotifyTimer();
653
- this.lastNotifiedRemoteStream = null;
654
- const activeSessionUid = this.sessionUid;
655
- this.sessionUid = null;
656
- this.client.beginTeardown();
657
- if (activeSessionUid) {
658
- try {
659
- await this.client.closeSession(activeSessionUid);
660
- } catch {
661
- }
662
- }
663
- const generationActive = !!this.taskUid && this.rtc.snapshot.joined;
664
- try {
665
- if (generationActive) {
666
- await this.stop();
667
- } else {
668
- this.updateDragController(false);
669
- this.rtc.clearRemoteVideo();
670
- if (this.remoteVideoContainer) {
671
- this.rtc.setRemoteVideoContainer(null);
672
- }
673
- this.taskUid = null;
674
- }
675
- } catch {
676
- }
677
- try {
678
- if (this.rtc.snapshot.joined) {
679
- await this.rtc.stopVideoPublishing();
680
- }
681
- } catch {
682
- }
683
- try {
684
- if (this.rtc.snapshot.joined) {
685
- await this.rtc.leave();
686
- }
687
- } catch {
688
- }
689
- this.client.endTeardown();
690
- this.taskUid = null;
691
- this.currentPrompt = "";
692
- this.currentGenerationModel = "";
693
- this.currentStaticGenerate = void 0;
694
- this.sessionTargetSize = null;
695
- this.dragController?.destroy();
696
- this.dragController = null;
697
- this.mirroredInputStream?.destroy();
698
- this.mirroredInputStream = null;
699
- if (this.hiddenRemoteElement) {
700
- this.hiddenRemoteElement.remove();
701
- this.hiddenRemoteElement = null;
702
- }
703
- }
704
- };
705
-
706
- // src/realtime/create-client.ts
707
- function resolveClientOptions(options) {
708
- return {
709
- ...options,
710
- baseUrl: options.baseUrl?.trim() || XMAX_OPEN_API_PRODUCTION_BASE_URL
711
- };
712
- }
713
- function createXmaxClient(options) {
714
- const resolved = resolveClientOptions(options);
715
- const httpClient = new XmaxOpenClient({
716
- apiKey: resolved.apiKey,
717
- authToken: resolved.authToken,
718
- baseUrl: resolved.baseUrl,
719
- onError: resolved.onError
720
- });
721
- return {
722
- files: {
723
- uploadImage: (file) => httpClient.uploadImage(file),
724
- uploadVideo: (file) => httpClient.uploadVideo(file),
725
- upload: (file) => httpClient.uploadImage(file)
726
- },
727
- realtime: {
728
- prewarm: (options2) => RealtimePrewarmHandle.create(options2.model, resolved),
729
- connect: (stream, connectOptions) => RealtimeSession.connect(stream, connectOptions, resolved)
730
- }
731
- };
732
- }
733
-
734
- // src/drag/drag-video-sync.ts
735
- var DRAG_SYNCED_ATTR = "data-xmax-drag-synced";
736
- function toContentRect(rect) {
737
- return {
738
- left: rect.left,
739
- top: rect.top,
740
- width: rect.width,
741
- height: rect.height
742
- };
743
- }
744
- function isMediaInsetInContainer(mediaRect, containerRect) {
745
- if (!mediaRect.width || !mediaRect.height || !containerRect.width || !containerRect.height) {
746
- return false;
747
- }
748
- const widthRatio = mediaRect.width / containerRect.width;
749
- const heightRatio = mediaRect.height / containerRect.height;
750
- return widthRatio < 0.98 || heightRatio < 0.98;
751
- }
752
- function intersectContentRects(a, b) {
753
- const left = Math.max(a.left, b.left);
754
- const top = Math.max(a.top, b.top);
755
- const right = Math.min(a.left + a.width, b.left + b.width);
756
- const bottom = Math.min(a.top + a.height, b.top + b.height);
757
- return {
758
- left,
759
- top,
760
- width: Math.max(0, right - left),
761
- height: Math.max(0, bottom - top)
762
- };
763
- }
764
- function readMediaIntrinsicSize(media) {
765
- const video = media;
766
- if ("videoWidth" in video && video.videoWidth > 0 && video.videoHeight > 0) {
767
- return [video.videoWidth, video.videoHeight];
768
- }
769
- if (media.width > 0 && media.height > 0) {
770
- return [media.width, media.height];
771
- }
772
- return null;
773
- }
774
- function resolveMediaObjectFit(media, fallback) {
775
- if (typeof getComputedStyle !== "function") {
776
- return fallback;
777
- }
778
- const fit = getComputedStyle(media).objectFit;
779
- if (fit === "contain" || fit === "cover" || fit === "fill") {
780
- return fit;
781
- }
782
- return fallback;
783
- }
784
- function resolveRemoteDragLayout(input) {
785
- const { wrapperRect, mediaRect, media, targetSize, fitMode } = input;
786
- if (!wrapperRect.width || !wrapperRect.height || !mediaRect.width || !mediaRect.height) {
787
- return null;
788
- }
789
- const wrapper = toContentRect(wrapperRect);
790
- if (fitMode === "contain") {
791
- const overlay2 = toContentRect(mediaRect);
792
- const hitRect = intersectContentRects(overlay2, wrapper);
793
- const drawable2 = hitRect.width > 0 && hitRect.height > 0 ? hitRect : wrapper;
794
- return { overlay: drawable2, mapping: overlay2, hitRect: drawable2, source: "media" };
795
- }
796
- if (isMediaInsetInContainer(mediaRect, wrapperRect)) {
797
- const overlay2 = toContentRect(mediaRect);
798
- return { overlay: overlay2, mapping: overlay2, hitRect: overlay2, source: "media" };
799
- }
800
- const intrinsic = media ? readMediaIntrinsicSize(media) : null;
801
- const frameSize = intrinsic ?? targetSize;
802
- const objectFit = media ? resolveMediaObjectFit(media, fitMode) : fitMode;
803
- if (objectFit === "fill") {
804
- const overlay2 = toContentRect(mediaRect);
805
- return { overlay: overlay2, mapping: overlay2, hitRect: wrapper, source: "intrinsic" };
806
- }
807
- const mapping = getFitContentRect(mediaRect, frameSize, objectFit);
808
- const overlay = intersectContentRects(mapping, wrapper);
809
- const drawable = overlay.width > 0 && overlay.height > 0 ? overlay : wrapper;
810
- return {
811
- overlay: drawable,
812
- mapping,
813
- hitRect: wrapper,
814
- source: intrinsic ? "intrinsic" : "fit"
815
- };
816
- }
817
- function resetDragSurfaceFullBleed(dragSurface) {
818
- dragSurface.style.inset = "0";
819
- dragSurface.style.left = "";
820
- dragSurface.style.top = "";
821
- dragSurface.style.right = "";
822
- dragSurface.style.bottom = "";
823
- dragSurface.style.width = "";
824
- dragSurface.style.height = "";
825
- dragSurface.removeAttribute(DRAG_SYNCED_ATTR);
826
- }
827
- function applyDragSurfaceOverlayStyles(dragSurface, overlay, wrapperRect) {
828
- const nextLeft = `${overlay.left - wrapperRect.left}px`;
829
- const nextTop = `${overlay.top - wrapperRect.top}px`;
830
- const nextWidth = `${overlay.width}px`;
831
- const nextHeight = `${overlay.height}px`;
832
- if (dragSurface.hasAttribute(DRAG_SYNCED_ATTR) && dragSurface.style.inset === "auto" && dragSurface.style.left === nextLeft && dragSurface.style.top === nextTop && dragSurface.style.width === nextWidth && dragSurface.style.height === nextHeight) {
833
- return false;
834
- }
835
- dragSurface.style.inset = "auto";
836
- dragSurface.style.left = nextLeft;
837
- dragSurface.style.top = nextTop;
838
- dragSurface.style.width = nextWidth;
839
- dragSurface.style.height = nextHeight;
840
- dragSurface.style.right = "";
841
- dragSurface.style.bottom = "";
842
- dragSurface.setAttribute(DRAG_SYNCED_ATTR, "");
843
- return true;
844
- }
845
- function syncDragSurfaceToVideo(dragSurface, targetSize, fitMode) {
846
- const wrapper = dragSurface.parentElement;
847
- if (!wrapper) {
848
- resetDragSurfaceFullBleed(dragSurface);
849
- return false;
850
- }
851
- const layout = resolveRemoteDragLayoutFromSurface(dragSurface, targetSize, fitMode);
852
- if (!layout || !layout.overlay.width || !layout.overlay.height) {
853
- resetDragSurfaceFullBleed(dragSurface);
854
- return false;
855
- }
856
- const wrapperRect = wrapper.getBoundingClientRect();
857
- const { overlay } = layout;
858
- return applyDragSurfaceOverlayStyles(dragSurface, overlay, wrapperRect);
859
- }
860
- function resolveRemoteDragLayoutFromSurface(dragSurface, targetSize, fitMode) {
861
- const wrapper = dragSurface.parentElement;
862
- if (!wrapper) {
863
- return null;
864
- }
865
- const videoHost = wrapper.querySelector("[data-xmax-remote-video]");
866
- if (!videoHost) {
867
- return null;
868
- }
869
- const media = videoHost.querySelector("video, canvas");
870
- if (!media) {
871
- return null;
872
- }
873
- return resolveRemoteDragLayout({
874
- wrapperRect: wrapper.getBoundingClientRect(),
875
- mediaRect: media.getBoundingClientRect(),
876
- media,
877
- targetSize,
878
- fitMode
879
- });
880
- }
881
- function observeDragSurfaceVideoSync(dragSurface, options) {
882
- const wrapper = dragSurface.parentElement;
883
- if (!wrapper) {
884
- return () => {
885
- };
886
- }
887
- const mediaListeners = /* @__PURE__ */ new Map();
888
- let rafId = null;
889
- let observedVideoHost = null;
890
- const bindMediaListeners = (media) => {
891
- if (mediaListeners.has(media)) {
892
- return;
893
- }
894
- const rerender = () => scheduleApply();
895
- const bindings = [];
896
- const add = (type) => {
897
- media.addEventListener(type, rerender);
898
- bindings.push(() => media.removeEventListener(type, rerender));
899
- };
900
- add("loadedmetadata");
901
- add("loadeddata");
902
- add("resize");
903
- mediaListeners.set(media, bindings);
904
- };
905
- const apply = () => {
906
- const changed = syncDragSurfaceToVideo(dragSurface, options.getTargetSize(), options.getFitMode());
907
- if (changed) {
908
- options.onSync?.();
909
- }
910
- const videoHost2 = wrapper.querySelector("[data-xmax-remote-video]");
911
- const media = videoHost2?.querySelector("video, canvas");
912
- if (media) {
913
- bindMediaListeners(media);
914
- }
915
- };
916
- const scheduleApply = () => {
917
- if (rafId !== null) {
918
- return;
919
- }
920
- rafId = requestAnimationFrame(() => {
921
- rafId = null;
922
- apply();
923
- });
924
- };
925
- const bindVideoHostObserver = (videoHostObserver) => {
926
- const host = wrapper.querySelector("[data-xmax-remote-video]");
927
- if (!host || host === observedVideoHost || !videoHostObserver) {
928
- return;
929
- }
930
- videoHostObserver.disconnect();
931
- observedVideoHost = host;
932
- videoHostObserver.observe(host, {
933
- childList: true,
934
- subtree: true,
935
- attributes: true,
936
- attributeFilter: ["style", "class", "width", "height"]
937
- });
938
- };
939
- apply();
940
- const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => scheduleApply()) : null;
941
- resizeObserver?.observe(wrapper);
942
- const videoHost = wrapper.querySelector("[data-xmax-remote-video]");
943
- if (videoHost) {
944
- resizeObserver?.observe(videoHost);
945
- }
946
- const observeMedia = () => {
947
- const host = wrapper.querySelector("[data-xmax-remote-video]");
948
- const media = host?.querySelector("video, canvas");
949
- if (media) {
950
- resizeObserver?.observe(media);
951
- bindMediaListeners(media);
952
- }
953
- };
954
- observeMedia();
955
- const videoHostMutationObserver = typeof MutationObserver !== "undefined" ? new MutationObserver(() => {
956
- observeMedia();
957
- scheduleApply();
958
- }) : null;
959
- bindVideoHostObserver(videoHostMutationObserver);
960
- const wrapperMutationObserver = typeof MutationObserver !== "undefined" ? new MutationObserver(() => {
961
- bindVideoHostObserver(videoHostMutationObserver);
962
- observeMedia();
963
- scheduleApply();
964
- }) : null;
965
- wrapperMutationObserver?.observe(wrapper, {
966
- childList: true,
967
- subtree: true
968
- });
969
- const onWindowChange = () => scheduleApply();
970
- window.addEventListener("resize", onWindowChange);
971
- window.addEventListener("scroll", onWindowChange, true);
972
- return () => {
973
- if (rafId !== null) {
974
- cancelAnimationFrame(rafId);
975
- rafId = null;
976
- }
977
- resizeObserver?.disconnect();
978
- wrapperMutationObserver?.disconnect();
979
- videoHostMutationObserver?.disconnect();
980
- for (const unbind of Array.from(mediaListeners.values())) {
981
- unbind.forEach((dispose) => dispose());
982
- }
983
- mediaListeners.clear();
984
- window.removeEventListener("resize", onWindowChange);
985
- window.removeEventListener("scroll", onWindowChange, true);
986
- resetDragSurfaceFullBleed(dragSurface);
987
- };
988
- }
989
-
990
- export { RealtimePrewarmHandle, RealtimeSession, createRemoteViewHost, createXmaxClient, observeDragSurfaceVideoSync, resolveRefImageUrl, syncDragSurfaceToVideo };
991
- //# sourceMappingURL=chunk-7X7QCO3O.js.map
992
- //# sourceMappingURL=chunk-7X7QCO3O.js.map