@manycore/aholo-viewer 1.0.0-alpha.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -41331,7 +41331,7 @@ var init_Splatting = __esm({
41331
41331
  return this.enabled && (this.shouldRenderNextFrame || this.isSortDirty || this.isSorting);
41332
41332
  }
41333
41333
  async flushSortTask() {
41334
- if (this.sortCurrentVersion === this.sortLastVersion || this.sortTaskRunning) {
41334
+ if (this.sortCurrentVersion === this.sortLastVersion || this.sortTaskRunning || !this.pendingSortTask) {
41335
41335
  return;
41336
41336
  }
41337
41337
  this.sortTaskRunning = true;
@@ -46184,7 +46184,7 @@ var init_SnapshotRendererV2 = __esm({
46184
46184
  }
46185
46185
  const splat = scene.splatManager.splats[0];
46186
46186
  const { promise, resolve } = deferred();
46187
- splat.on(SplatSortedEvent, resolve);
46187
+ splat.once(SplatSortedEvent, resolve);
46188
46188
  const ratio = this.realRatio;
46189
46189
  const renderSize = {
46190
46190
  width: Math.floor(size.width * ratio),
@@ -46288,7 +46288,9 @@ var init_SnapshotRendererV2 = __esm({
46288
46288
  }
46289
46289
  }
46290
46290
  const ctx = { drawableList, scene, camera: renderCamera, size, freeables };
46291
- await this.prerender(ctx);
46291
+ if (ctx.scene.splatManager.splatCounts) {
46292
+ await this.prerender(ctx);
46293
+ }
46292
46294
  const target4 = this.inner_render(ctx);
46293
46295
  const resultBuffer = new Uint8Array(size.width * size.height * 4);
46294
46296
  const projectionMatrix = renderCamera.projectionMatrix.clone();
@@ -46342,7 +46344,7 @@ var require_package = __commonJS({
46342
46344
  "../../external/egs-core/packages/egs/package.json"(exports, module) {
46343
46345
  module.exports = {
46344
46346
  name: "@qunhe/egs",
46345
- version: "1.2.84",
46347
+ version: "1.2.87",
46346
46348
  description: "Manycore EGS Graphics System",
46347
46349
  license: "MIT",
46348
46350
  main: "index.js",
@@ -46364,7 +46366,7 @@ var require_package = __commonJS({
46364
46366
  },
46365
46367
  release: {
46366
46368
  scripts: {
46367
- "pre-release": "pnpm build:release"
46369
+ "pre-release": "echo build"
46368
46370
  },
46369
46371
  publishRoot: "./build"
46370
46372
  }
@@ -66863,6 +66865,13 @@ var ResourceManager3 = class {
66863
66865
  };
66864
66866
 
66865
66867
  // ../../external/egs-core/packages/utils/splat-utils/lod/index.ts
66868
+ var DEFAULT_DISTANCE_STEP = [{
66869
+ distance: 5,
66870
+ step: 3
66871
+ }, {
66872
+ distance: 10,
66873
+ step: 2
66874
+ }];
66866
66875
  function DefaultLoadResource(url7) {
66867
66876
  const type = detectSplatFileType(url7, new Uint8Array());
66868
66877
  return parseSplatData(type, url7);
@@ -66990,6 +66999,7 @@ var LodSplat = class {
66990
66999
  this.behindPenalty = config?.behindPenalty ?? 0.1;
66991
67000
  this.behindTolerance = config?.behindTolerance ?? -0.2;
66992
67001
  this.behindDistanceTolerance = config?.behindDistanceTolerance ?? 2;
67002
+ this.distanceStep = config?.distanceStep ?? DEFAULT_DISTANCE_STEP;
66993
67003
  this.hysteresisTicks = config?.hysteresisTicks ?? 4;
66994
67004
  this.schedulerParallelCounts = config?.schedulerParallelCounts ?? 4;
66995
67005
  this.schedulerExistingTaskLimit = config?.schedulerExistingTaskLimit ?? 64;
@@ -67052,7 +67062,8 @@ var LodSplat = class {
67052
67062
  outsidePenalty,
67053
67063
  behindPenalty,
67054
67064
  behindTolerance,
67055
- behindDistanceTolerance
67065
+ behindDistanceTolerance,
67066
+ distanceStep
67056
67067
  } = this;
67057
67068
  camera.updateMatrixWorld();
67058
67069
  const { position: cameraPos2, quaternion: cameraQuat } = camera;
@@ -67060,27 +67071,60 @@ var LodSplat = class {
67060
67071
  const cameraDir = new Vector3(0, 0, -1).applyQuaternion(cameraQuat);
67061
67072
  const nodeWeights = nodes.map((node, idx) => {
67062
67073
  const closestPoint = node.box.clampPoint(cameraPos2, tempVec32);
67063
- const dist = cameraPos2.distanceTo(closestPoint);
67074
+ const insideBox = node.box.containsPoint(cameraPos2);
67075
+ const dist = insideBox ? 0 : cameraPos2.distanceTo(closestPoint);
67064
67076
  const dirDot = cameraDir.dot(closestPoint.sub(cameraPos2).normalize());
67065
67077
  const isInside = frustum.intersectsBox(node.box);
67066
- const isBehind = dirDot < behindTolerance && dist > behindDistanceTolerance;
67078
+ const isBehind = !insideBox && dirDot < behindTolerance && dist > behindDistanceTolerance;
67067
67079
  const weight = node.weight / (1 + 0.1 * dist * dist) * (isInside ? 1 : outsidePenalty * (isBehind ? behindPenalty : 1));
67068
- return { idx, node, weight, isInside, isBehind };
67080
+ return { idx, node, weight, isInside, isBehind, dist };
67069
67081
  }).sort((a, b) => b.weight - a.weight);
67082
+ const steppedNodes = distanceStep.map((e) => ({
67083
+ ...e,
67084
+ nodes: []
67085
+ }));
67086
+ steppedNodes.push({
67087
+ distance: Infinity,
67088
+ step: 1,
67089
+ nodes: []
67090
+ });
67091
+ let stepIndex = 0;
67092
+ for (const node of nodeWeights) {
67093
+ if (!node.isInside) {
67094
+ steppedNodes[steppedNodes.length - 1].nodes.push(node);
67095
+ continue;
67096
+ }
67097
+ if (node.dist <= steppedNodes[stepIndex].distance) {
67098
+ steppedNodes[stepIndex].nodes.push(node);
67099
+ } else {
67100
+ stepIndex++;
67101
+ steppedNodes[stepIndex].nodes.push(node);
67102
+ }
67103
+ }
67070
67104
  const levels = new Uint8Array(nodes.length).fill(maxLevel);
67071
67105
  let insideOnly = true;
67072
67106
  let restBudget = maxBudget - lessUsedBudget;
67073
67107
  while (restBudget > 0) {
67074
67108
  const prev = restBudget;
67075
- for (let i = 0; i < nodeWeights.length; i++) {
67076
- const { idx, node: { lods }, isInside } = nodeWeights[i];
67077
- if (insideOnly && !isInside) {
67078
- continue;
67079
- }
67080
- const level = levels[idx];
67081
- if (level > minLevel) {
67082
- restBudget -= lods[level - 1].counts - lods[level].counts;
67083
- levels[idx] = level - 1;
67109
+ for (const stepped of steppedNodes) {
67110
+ for (let step = 0; step < stepped.step; step++) {
67111
+ for (const node of stepped.nodes) {
67112
+ const { idx, node: { lods }, isInside } = node;
67113
+ if (insideOnly && !isInside) {
67114
+ continue;
67115
+ }
67116
+ const level = levels[idx];
67117
+ if (level > minLevel) {
67118
+ restBudget -= lods[level - 1].counts - lods[level].counts;
67119
+ levels[idx] = level - 1;
67120
+ }
67121
+ if (restBudget <= 0) {
67122
+ break;
67123
+ }
67124
+ }
67125
+ if (restBudget <= 0) {
67126
+ break;
67127
+ }
67084
67128
  }
67085
67129
  if (restBudget <= 0) {
67086
67130
  break;
@@ -67153,18 +67197,22 @@ var LodSplat = class {
67153
67197
  // src/index.ts
67154
67198
  init_egs();
67155
67199
 
67156
- // src/render-cloud/index.ts
67157
- var render_cloud_exports = {};
67158
- __export(render_cloud_exports, {
67200
+ // ../render-cloud/src/index.ts
67201
+ var src_exports = {};
67202
+ __export(src_exports, {
67159
67203
  OfflineRenderClient: () => OfflineRenderClient,
67160
67204
  RenderCloudError: () => RenderCloudError,
67161
67205
  closeStreamKeepalive: () => closeStreamKeepalive,
67162
67206
  createRealtimeSession: () => createRealtimeSession,
67207
+ formatRenderCloudUserError: () => formatRenderCloudUserError,
67163
67208
  matrixColumnsToUsdMatrix4d: () => matrixColumnsToUsdMatrix4d,
67209
+ readRenderCloudApiErrorDetails: () => readRenderCloudApiErrorDetails,
67210
+ readRenderCloudApiErrorMessage: () => readRenderCloudApiErrorMessage,
67211
+ readRenderCloudApiErrorReason: () => readRenderCloudApiErrorReason,
67164
67212
  usdMatrix4dToMatrixColumns: () => usdMatrix4dToMatrixColumns
67165
67213
  });
67166
67214
 
67167
- // src/render-cloud/constants.ts
67215
+ // ../render-cloud/src/constants.ts
67168
67216
  var RENDER_CLOUD_V1_PATHS = {
67169
67217
  offlineJobs: "/jobs",
67170
67218
  streams: "/streams",
@@ -67176,7 +67224,7 @@ var RENDER_CLOUD_DEFAULT_MAX_PATCHES_PER_MINUTE = 60;
67176
67224
  var RENDER_CLOUD_DEFAULT_PATCH_THROTTLE_MS = 1e3;
67177
67225
  var RENDER_CLOUD_MAX_STREAM_RESOLUTION_LONG_EDGE = 1920;
67178
67226
 
67179
- // src/render-cloud/utils.ts
67227
+ // ../render-cloud/src/utils.ts
67180
67228
  var RenderCloudError = class extends Error {
67181
67229
  constructor(message, status, body) {
67182
67230
  super(message);
@@ -67210,26 +67258,62 @@ function readLegacyGatewayFailure(body) {
67210
67258
  const message = record.m;
67211
67259
  return typeof message === "string" && message.trim() ? message.trim() : `gateway error (${code})`;
67212
67260
  }
67213
- function readRenderCloudApiErrorMessage(body) {
67261
+ function unwrapRenderCloudApiErrorRecord(body) {
67214
67262
  if (!body || typeof body !== "object") {
67215
67263
  return void 0;
67216
67264
  }
67217
67265
  const record = body;
67218
67266
  const nested = record.error;
67219
- if (nested && typeof nested === "object" && "message" in nested) {
67220
- const nestedMessage = nested.message;
67221
- if (typeof nestedMessage === "string" && nestedMessage.trim()) {
67222
- return nestedMessage.trim();
67223
- }
67267
+ if (nested && typeof nested === "object") {
67268
+ return nested;
67269
+ }
67270
+ if ("message" in record || "code" in record || "status" in record || "details" in record) {
67271
+ return record;
67272
+ }
67273
+ return void 0;
67274
+ }
67275
+ function readRenderCloudApiErrorDetails(body) {
67276
+ const record = unwrapRenderCloudApiErrorRecord(body);
67277
+ if (!record) {
67278
+ return void 0;
67279
+ }
67280
+ const details = record.details;
67281
+ if (details && typeof details === "object" && !Array.isArray(details)) {
67282
+ return details;
67283
+ }
67284
+ return void 0;
67285
+ }
67286
+ function readRenderCloudApiErrorReason(body) {
67287
+ const reason = readRenderCloudApiErrorDetails(body)?.reason;
67288
+ return typeof reason === "string" && reason.trim() ? reason.trim() : void 0;
67289
+ }
67290
+ function readRenderCloudApiErrorMessage(body) {
67291
+ const record = unwrapRenderCloudApiErrorRecord(body);
67292
+ if (!record) {
67293
+ return void 0;
67224
67294
  }
67225
67295
  const message = record.message;
67226
67296
  return typeof message === "string" && message.trim() ? message.trim() : void 0;
67227
67297
  }
67298
+ function formatRenderCloudUserError(body, options) {
67299
+ const message = readRenderCloudApiErrorMessage(body);
67300
+ const reason = readRenderCloudApiErrorReason(body);
67301
+ return message ?? reason ?? options?.fallbackMessage;
67302
+ }
67228
67303
  function readGatewayErrorMessage(body) {
67229
67304
  const legacy = readLegacyGatewayFailure(body);
67230
67305
  if (legacy) {
67231
67306
  return legacy;
67232
67307
  }
67308
+ if (body && typeof body === "object") {
67309
+ const record = body;
67310
+ if (record.error) {
67311
+ const operationError = readRenderCloudApiErrorMessage(record.error);
67312
+ if (operationError) {
67313
+ return operationError;
67314
+ }
67315
+ }
67316
+ }
67233
67317
  return readRenderCloudApiErrorMessage(body);
67234
67318
  }
67235
67319
  function safeJsonParse(text) {
@@ -67277,7 +67361,7 @@ var PatchRateLimiter = class {
67277
67361
  _maxPerMinute = new WeakMap();
67278
67362
  _timestamps = new WeakMap();
67279
67363
 
67280
- // src/render-cloud/usd.ts
67364
+ // ../render-cloud/src/usd.ts
67281
67365
  function matrixColumnsToUsdMatrix4d(columns) {
67282
67366
  const rows = [
67283
67367
  [0, 0, 0, 0],
@@ -67399,7 +67483,7 @@ function patchUsdCamera(usda, camera, options) {
67399
67483
  return next;
67400
67484
  }
67401
67485
 
67402
- // src/render-cloud/client.ts
67486
+ // ../render-cloud/src/client.ts
67403
67487
  function resolveConfig(config) {
67404
67488
  return {
67405
67489
  origin: config.origin.replace(/\/$/, ""),
@@ -67421,7 +67505,7 @@ var RenderCloudClient = class {
67421
67505
  get resolved() {
67422
67506
  return __privateGet(this, _config);
67423
67507
  }
67424
- /** `POST /rendercloud/v1/streams` 鈥?submit (no `operationId`). */
67508
+ /** `POST /rendercloud/v1/streams` submit (no `operationId`). */
67425
67509
  submitStream(usda, requestId) {
67426
67510
  const body = {
67427
67511
  requestId: requestId ?? __privateGet(this, _config).createRequestId(),
@@ -67429,12 +67513,12 @@ var RenderCloudClient = class {
67429
67513
  };
67430
67514
  return this.json(RENDER_CLOUD_V1_PATHS.streams, { method: "POST", json: body });
67431
67515
  }
67432
- /** `POST /rendercloud/v1/streams` 鈥?poll (`operationId` only). */
67516
+ /** `POST /rendercloud/v1/streams` poll (`operationId` only). */
67433
67517
  pollStream(operationId) {
67434
67518
  const body = { operationId };
67435
67519
  return this.json(RENDER_CLOUD_V1_PATHS.streams, { method: "POST", json: body });
67436
67520
  }
67437
- /** `POST /rendercloud/v1/streams/{sessionId}:push` 鈥?scene/camera updates. */
67521
+ /** `POST /rendercloud/v1/streams/{sessionId}:push` scene/camera updates. */
67438
67522
  pushStream(sessionId, usda, requestId) {
67439
67523
  const body = {
67440
67524
  requestId: requestId ?? __privateGet(this, _config).createRequestId(),
@@ -67446,7 +67530,7 @@ var RenderCloudClient = class {
67446
67530
  closeStream(sessionId) {
67447
67531
  return this.json(RENDER_CLOUD_V1_PATHS.streamClose(sessionId), { method: "DELETE" });
67448
67532
  }
67449
- /** `POST /rendercloud/v1/jobs` 鈥?submit offline render. */
67533
+ /** `POST /rendercloud/v1/jobs` submit offline render. */
67450
67534
  submitOfflineJob(usda, imgSize, requestId) {
67451
67535
  const body = {
67452
67536
  requestId: requestId ?? __privateGet(this, _config).createRequestId(),
@@ -67455,7 +67539,7 @@ var RenderCloudClient = class {
67455
67539
  };
67456
67540
  return this.json(RENDER_CLOUD_V1_PATHS.offlineJobs, { method: "POST", json: body });
67457
67541
  }
67458
- /** `POST /rendercloud/v1/jobs` 鈥?poll offline job. */
67542
+ /** `POST /rendercloud/v1/jobs` poll offline job. */
67459
67543
  pollOfflineJob(operationId) {
67460
67544
  const body = { operationId };
67461
67545
  return this.json(RENDER_CLOUD_V1_PATHS.offlineJobs, { method: "POST", json: body });
@@ -67538,7 +67622,7 @@ function formatErrorMessage(status, body, rawText) {
67538
67622
  return `Render Cloud request failed (${status})`;
67539
67623
  }
67540
67624
 
67541
- // src/render-cloud/streaming.ts
67625
+ // ../render-cloud/src/streaming.ts
67542
67626
  function buildStreamingWebSocketUrl(host, nodeId, token) {
67543
67627
  const nid = encodeURIComponent(nodeId);
67544
67628
  const tok = encodeURIComponent(token);
@@ -67658,7 +67742,7 @@ function isFatalStreamingCode(code) {
67658
67742
  return code === "1000" || code === "1001" || code === "1003";
67659
67743
  }
67660
67744
 
67661
- // src/render-cloud/realtime.ts
67745
+ // ../render-cloud/src/realtime.ts
67662
67746
  async function createRealtimeSession(config, options) {
67663
67747
  const client = new RenderCloudClient(config);
67664
67748
  const resolved = client.resolved;
@@ -67674,6 +67758,7 @@ async function createRealtimeSession(config, options) {
67674
67758
  let state = "creating";
67675
67759
  let streaming;
67676
67760
  let closed = false;
67761
+ let serverCloseStarted = false;
67677
67762
  let readyPromise;
67678
67763
  let patchTimer;
67679
67764
  let pendingPatch = false;
@@ -67690,57 +67775,89 @@ async function createRealtimeSession(config, options) {
67690
67775
  if (options.onStateChange) {
67691
67776
  stateHandlers.add(options.onStateChange);
67692
67777
  }
67693
- const submitOperation = await client.submitStream(usda);
67694
- const operationId = submitOperation.operationId;
67695
- if (operationId === void 0 || operationId === null || String(operationId).length === 0) {
67696
- const gatewayMessage = readGatewayErrorMessage(submitOperation);
67697
- if (gatewayMessage) {
67698
- throw new Error(`Render Cloud: ${gatewayMessage}`);
67699
- }
67700
- throw new Error("Render Cloud did not return an operationId.");
67701
- }
67702
- setState("polling");
67703
- const streamResult = await pollStreamUntilActive(client, operationId, pollInterval, pollTimeout);
67704
- sessionId = streamResult.sessionId || String(operationId);
67705
- const wsUrl = resolveStreamingUrl(
67706
- buildStreamingWebSocketUrl(streamResult.host, streamResult.nodeId, streamResult.token),
67707
- resolved
67708
- );
67709
- setState("connecting");
67710
- await connectStreaming(wsUrl, streamResult.streamId);
67711
- setState("ready");
67712
- return {
67713
- get sessionId() {
67714
- return sessionId;
67715
- },
67716
- get state() {
67717
- return state;
67718
- },
67719
- ready() {
67720
- return readyPromise ?? Promise.resolve();
67721
- },
67722
- push(nextUsda) {
67723
- usda = nextUsda;
67724
- schedulePatch();
67725
- },
67726
- pushCamera(camera, patchOptions) {
67727
- usda = patchUsdCamera(usda, camera, patchOptions);
67728
- schedulePatch();
67729
- },
67730
- onFrame(handler) {
67731
- frameHandlers.add(handler);
67732
- return () => frameHandlers.delete(handler);
67733
- },
67734
- onError(handler) {
67735
- errorHandlers.add(handler);
67736
- return () => errorHandlers.delete(handler);
67737
- },
67738
- onStateChange(handler) {
67739
- stateHandlers.add(handler);
67740
- return () => stateHandlers.delete(handler);
67741
- },
67742
- close: () => closeSession()
67778
+ throwIfRealtimeAborted(options.signal);
67779
+ let unlinkAbortSignal = () => {
67743
67780
  };
67781
+ unlinkAbortSignal = bindAbortSignal(options.signal, () => {
67782
+ void closeSession();
67783
+ });
67784
+ try {
67785
+ const submitOperation = await client.submitStream(usda);
67786
+ const operationId = submitOperation.operationId;
67787
+ if (operationId === void 0 || operationId === null || String(operationId).length === 0) {
67788
+ const apiError = submitOperation.error;
67789
+ if (apiError) {
67790
+ throw new RenderCloudError(
67791
+ apiError.message ?? "Render Cloud stream creation failed.",
67792
+ apiError.code,
67793
+ apiError
67794
+ );
67795
+ }
67796
+ const gatewayMessage = readGatewayErrorMessage(submitOperation);
67797
+ if (gatewayMessage) {
67798
+ throw new RenderCloudError(gatewayMessage, 0, submitOperation);
67799
+ }
67800
+ throw new RenderCloudError("Render Cloud did not return an operationId.", 0, submitOperation);
67801
+ }
67802
+ sessionId = String(operationId);
67803
+ options.onSessionId?.(sessionId);
67804
+ throwIfRealtimeAborted(options.signal);
67805
+ setState("polling");
67806
+ const streamResult = await pollStreamUntilActive(client, sessionId, pollInterval, pollTimeout, options.signal);
67807
+ const activeSessionId = streamResult.sessionId || sessionId;
67808
+ if (activeSessionId !== sessionId) {
67809
+ sessionId = activeSessionId;
67810
+ options.onSessionId?.(sessionId);
67811
+ }
67812
+ const wsUrl = resolveStreamingUrl(
67813
+ buildStreamingWebSocketUrl(streamResult.host, streamResult.nodeId, streamResult.token),
67814
+ resolved
67815
+ );
67816
+ throwIfRealtimeAborted(options.signal);
67817
+ setState("connecting");
67818
+ await connectStreaming(wsUrl, streamResult.streamId);
67819
+ throwIfRealtimeAborted(options.signal);
67820
+ setState("ready");
67821
+ return {
67822
+ get sessionId() {
67823
+ return sessionId;
67824
+ },
67825
+ get state() {
67826
+ return state;
67827
+ },
67828
+ ready() {
67829
+ return readyPromise ?? Promise.resolve();
67830
+ },
67831
+ push(nextUsda) {
67832
+ usda = nextUsda;
67833
+ schedulePatch();
67834
+ },
67835
+ pushCamera(camera, patchOptions) {
67836
+ usda = patchUsdCamera(usda, camera, patchOptions);
67837
+ schedulePatch();
67838
+ },
67839
+ onFrame(handler) {
67840
+ frameHandlers.add(handler);
67841
+ return () => frameHandlers.delete(handler);
67842
+ },
67843
+ onError(handler) {
67844
+ errorHandlers.add(handler);
67845
+ return () => errorHandlers.delete(handler);
67846
+ },
67847
+ onStateChange(handler) {
67848
+ stateHandlers.add(handler);
67849
+ return () => stateHandlers.delete(handler);
67850
+ },
67851
+ close: () => closeSession()
67852
+ };
67853
+ } catch (error) {
67854
+ if (sessionId) {
67855
+ await closeSession();
67856
+ } else {
67857
+ unlinkAbortSignal();
67858
+ }
67859
+ throw error;
67860
+ }
67744
67861
  function setState(next) {
67745
67862
  state = next;
67746
67863
  for (const handler of stateHandlers) {
@@ -67800,6 +67917,7 @@ async function createRealtimeSession(config, options) {
67800
67917
  readyPromise = new Promise((resolve, reject) => {
67801
67918
  let settled = false;
67802
67919
  const timeout = setTimeout(() => {
67920
+ settled = true;
67803
67921
  reject(new Error("Timed out waiting for Render Cloud streaming to become ready."));
67804
67922
  }, pollTimeout);
67805
67923
  streaming = new StreamingConnection({
@@ -67824,9 +67942,19 @@ async function createRealtimeSession(config, options) {
67824
67942
  },
67825
67943
  onError: (error) => {
67826
67944
  clearTimeout(timeout);
67827
- reject(error);
67945
+ if (!settled) {
67946
+ settled = true;
67947
+ reject(error);
67948
+ }
67828
67949
  },
67829
67950
  onClose: () => {
67951
+ clearTimeout(timeout);
67952
+ if (!settled) {
67953
+ settled = true;
67954
+ reject(
67955
+ closed ? createRealtimeAbortError() : new Error("Render Cloud streaming WebSocket closed before ready.")
67956
+ );
67957
+ }
67830
67958
  if (!closed) {
67831
67959
  setState("closed");
67832
67960
  }
@@ -67836,16 +67964,22 @@ async function createRealtimeSession(config, options) {
67836
67964
  await readyPromise;
67837
67965
  }
67838
67966
  async function closeSession() {
67839
- if (closed) {
67967
+ if (closed && (serverCloseStarted || !sessionId)) {
67840
67968
  return;
67841
67969
  }
67842
67970
  closed = true;
67971
+ unlinkAbortSignal();
67843
67972
  if (patchTimer !== void 0) {
67844
67973
  clearTimeout(patchTimer);
67845
67974
  patchTimer = void 0;
67846
67975
  }
67847
67976
  streaming?.close(1e3, "client-close");
67848
67977
  streaming = void 0;
67978
+ if (!sessionId || serverCloseStarted) {
67979
+ setState("closed");
67980
+ return;
67981
+ }
67982
+ serverCloseStarted = true;
67849
67983
  try {
67850
67984
  await client.closeStream(sessionId);
67851
67985
  } catch (error) {
@@ -67854,17 +67988,24 @@ async function createRealtimeSession(config, options) {
67854
67988
  setState("closed");
67855
67989
  }
67856
67990
  }
67857
- async function pollStreamUntilActive(client, operationId, intervalMs, timeoutMs) {
67991
+ async function pollStreamUntilActive(client, operationId, intervalMs, timeoutMs, signal) {
67858
67992
  const started = Date.now();
67859
67993
  while (Date.now() - started < timeoutMs) {
67994
+ throwIfRealtimeAborted(signal);
67860
67995
  const operation = await client.pollStream(operationId);
67996
+ throwIfRealtimeAborted(signal);
67861
67997
  if (operation.done && operation.error) {
67862
- throw new Error(operation.error.message ?? "Render Cloud stream creation failed.");
67998
+ const apiError = operation.error;
67999
+ throw new RenderCloudError(
68000
+ apiError.message ?? "Render Cloud stream creation failed.",
68001
+ apiError.code,
68002
+ apiError
68003
+ );
67863
68004
  }
67864
68005
  if (operation.done && operation.result) {
67865
68006
  const result = operation.result;
67866
68007
  if (result.status === "FAILED" || result.status === "CLOSED") {
67867
- throw new Error(`Render Cloud stream creation failed (${result.status}).`);
68008
+ throw new RenderCloudError(`Render Cloud stream creation failed (${result.status}).`, 0, result);
67868
68009
  }
67869
68010
  if (result.status === "ACTIVE" && result.host && result.nodeId && result.streamId && result.token) {
67870
68011
  return {
@@ -67881,15 +68022,56 @@ async function pollStreamUntilActive(client, operationId, intervalMs, timeoutMs)
67881
68022
  `Render Cloud stream ended without ACTIVE credentials (status=${result.status ?? "unknown"}).`
67882
68023
  );
67883
68024
  }
67884
- await sleep2(intervalMs);
68025
+ await sleepWithAbort(intervalMs, signal);
67885
68026
  }
67886
68027
  throw new Error("Timed out waiting for Render Cloud stream to become ACTIVE.");
67887
68028
  }
67888
68029
  function resolveStreamingUrl(url7, resolved) {
67889
68030
  return resolved.transformStreamingUrl ? resolved.transformStreamingUrl(url7) : url7;
67890
68031
  }
68032
+ function bindAbortSignal(signal, onAbort) {
68033
+ if (!signal) {
68034
+ return () => {
68035
+ };
68036
+ }
68037
+ if (signal.aborted) {
68038
+ onAbort();
68039
+ return () => {
68040
+ };
68041
+ }
68042
+ signal.addEventListener("abort", onAbort, { once: true });
68043
+ return () => {
68044
+ signal.removeEventListener("abort", onAbort);
68045
+ };
68046
+ }
68047
+ async function sleepWithAbort(ms, signal) {
68048
+ if (!signal) {
68049
+ await sleep2(ms);
68050
+ return;
68051
+ }
68052
+ throwIfRealtimeAborted(signal);
68053
+ await new Promise((resolve, reject) => {
68054
+ const timeout = setTimeout(() => {
68055
+ signal.removeEventListener("abort", abort);
68056
+ resolve();
68057
+ }, ms);
68058
+ const abort = () => {
68059
+ clearTimeout(timeout);
68060
+ reject(createRealtimeAbortError());
68061
+ };
68062
+ signal.addEventListener("abort", abort, { once: true });
68063
+ });
68064
+ }
68065
+ function throwIfRealtimeAborted(signal) {
68066
+ if (signal?.aborted) {
68067
+ throw createRealtimeAbortError();
68068
+ }
68069
+ }
68070
+ function createRealtimeAbortError() {
68071
+ return new DOMException("Render Cloud realtime session was aborted.", "AbortError");
68072
+ }
67891
68073
 
67892
- // src/render-cloud/offline.ts
68074
+ // ../render-cloud/src/offline.ts
67893
68075
  var _client;
67894
68076
  var OfflineRenderClient = class {
67895
68077
  constructor(config) {
@@ -68027,7 +68209,7 @@ export {
68027
68209
  Quaternion,
68028
68210
  Ray,
68029
68211
  Raycaster,
68030
- render_cloud_exports as RenderCloud,
68212
+ src_exports as RenderCloud,
68031
68213
  SamplerFilter,
68032
68214
  SamplerWrap,
68033
68215
  Scene3D,