@eyepop.ai/eyepop 3.18.0 → 3.19.1

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.
@@ -8671,11 +8671,13 @@ __export(index_exports, {
8671
8671
  DEFAULT_PREDICTION_VERSION: () => DEFAULT_PREDICTION_VERSION,
8672
8672
  DataApiType: () => DataApiType,
8673
8673
  DataEndpoint: () => DataEndpoint,
8674
+ DepthMap: () => DepthMap,
8674
8675
  Endpoint: () => Endpoint,
8675
8676
  EndpointState: () => EndpointState,
8676
8677
  EvaluationStatus: () => EvaluationStatus,
8677
8678
  ExportedBy: () => ExportedBy,
8678
8679
  EyePop: () => EyePop,
8680
+ EyePopDataWebSocketError: () => EyePopDataWebSocketError,
8679
8681
  EyepopLineDecoder: () => EyepopLineDecoder,
8680
8682
  ForwardOperatorType: () => ForwardOperatorType,
8681
8683
  InferenceType: () => InferenceType,
@@ -8711,6 +8713,7 @@ __export(index_exports, {
8711
8713
  WorkflowPhase: () => WorkflowPhase,
8712
8714
  accessTokenCredential: () => accessTokenCredential,
8713
8715
  apiKeyCredential: () => apiKeyCredential,
8716
+ decodeDepthMap: () => decodeDepthMap,
8714
8717
  default: () => index_default,
8715
8718
  encodeMultipartFormData: () => encodeMultipartFormData,
8716
8719
  getBaseUrl: () => getBaseUrl,
@@ -11520,57 +11523,8 @@ if ("document" in globalThis && "implementation" in globalThis.document) {
11520
11523
  };
11521
11524
  }
11522
11525
 
11523
- // ../../node_modules/url-join/lib/url-join.js
11524
- function normalize(strArray) {
11525
- var resultArray = [];
11526
- if (strArray.length === 0) {
11527
- return "";
11528
- }
11529
- if (typeof strArray[0] !== "string") {
11530
- throw new TypeError("Url must be a string. Received " + strArray[0]);
11531
- }
11532
- if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
11533
- var first = strArray.shift();
11534
- strArray[0] = first + strArray[0];
11535
- }
11536
- if (strArray[0].match(/^file:\/\/\//)) {
11537
- strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1:///");
11538
- } else {
11539
- strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1://");
11540
- }
11541
- for (var i = 0; i < strArray.length; i++) {
11542
- var component = strArray[i];
11543
- if (typeof component !== "string") {
11544
- throw new TypeError("Url must be a string. Received " + component);
11545
- }
11546
- if (component === "") {
11547
- continue;
11548
- }
11549
- if (i > 0) {
11550
- component = component.replace(/^[\/]+/, "");
11551
- }
11552
- if (i < strArray.length - 1) {
11553
- component = component.replace(/[\/]+$/, "");
11554
- } else {
11555
- component = component.replace(/[\/]+$/, "/");
11556
- }
11557
- resultArray.push(component);
11558
- }
11559
- var str = resultArray.join("/");
11560
- str = str.replace(/\/(\?|&|#[^!])/g, "$1");
11561
- var parts = str.split("?");
11562
- str = parts.shift() + (parts.length > 0 ? "?" : "") + parts.join("&");
11563
- return str;
11564
- }
11565
- function urlJoin() {
11566
- var input;
11567
- if (typeof arguments[0] === "object") {
11568
- input = arguments[0];
11569
- } else {
11570
- input = [].slice.call(arguments);
11571
- }
11572
- return normalize(input);
11573
- }
11526
+ // data/data_endpoint.ts
11527
+ var import_url_join = __toESM(require("url-join"));
11574
11528
 
11575
11529
  // data/data_types.ts
11576
11530
  var DataApiType = /* @__PURE__ */ ((DataApiType2) => {
@@ -11923,6 +11877,33 @@ var EvaluateDatasetJob = class {
11923
11877
  // data/data_endpoint.ts
11924
11878
  var WS_INITIAL_RECONNECT_DELAY = 1e3;
11925
11879
  var WS_MAX_RECONNECT_DELAY = 6e4;
11880
+ function ws_origin(url) {
11881
+ try {
11882
+ return new URL(url).origin;
11883
+ } catch {
11884
+ return url;
11885
+ }
11886
+ }
11887
+ function ws_failure_reason(event, sourceError) {
11888
+ if (sourceError instanceof Error) {
11889
+ return sourceError.message;
11890
+ }
11891
+ if (typeof sourceError === "string") {
11892
+ return sourceError;
11893
+ }
11894
+ return event?.message ?? "";
11895
+ }
11896
+ var EyePopDataWebSocketError = class extends Error {
11897
+ constructor(url, event) {
11898
+ const sourceError = event?.error ?? event;
11899
+ const reason = ws_failure_reason(event, sourceError);
11900
+ super(reason ? `EyePop Dataset event WebSocket connection failed: ${reason}` : "EyePop Dataset event WebSocket connection failed");
11901
+ this.code = "DATA_WEBSOCKET_CONNECTION_FAILED";
11902
+ this.name = "EyePopDataWebSocketError";
11903
+ this.endpoint = ws_origin(url);
11904
+ this.sourceError = sourceError;
11905
+ }
11906
+ };
11926
11907
  function omit_nulls(_, value) {
11927
11908
  if (value === null) {
11928
11909
  return void 0;
@@ -11936,6 +11917,9 @@ var DataEndpoint = class extends Endpoint {
11936
11917
  this.vlmApiUrl = null;
11937
11918
  this._ws = null;
11938
11919
  this._ws_current_reconnect_delay = null;
11920
+ this._ws_reconnect_timeout = null;
11921
+ this._ws_reconnect_enabled = false;
11922
+ this._ws_connecting = null;
11939
11923
  this._accountId = options.accountId || null;
11940
11924
  this._account_event_handlers = [];
11941
11925
  this._dataset_uuid_to_event_handlers = /* @__PURE__ */ new Map();
@@ -11959,14 +11943,15 @@ var DataEndpoint = class extends Endpoint {
11959
11943
  };
11960
11944
  }
11961
11945
  async disconnect(wait = true) {
11946
+ this._ws_reconnect_enabled = false;
11947
+ if (this._ws_reconnect_timeout) {
11948
+ clearTimeout(this._ws_reconnect_timeout);
11949
+ this._ws_reconnect_timeout = null;
11950
+ }
11962
11951
  this.datasetApiUrl = null;
11963
11952
  this.vlmApiUrl = null;
11964
11953
  if (this._ws) {
11965
- try {
11966
- this._ws.close();
11967
- } catch (e) {
11968
- this._logger.warn("ignored exception", e);
11969
- }
11954
+ this.close_ws(this._ws, "unsubscribe");
11970
11955
  this._ws = null;
11971
11956
  }
11972
11957
  await super.disconnect(wait);
@@ -12004,13 +11989,14 @@ var DataEndpoint = class extends Endpoint {
12004
11989
  const vlmApiUrl = new URL(config.vlm_api_url, this.eyepopUrl());
12005
11990
  this.vlmApiUrl = vlmApiUrl.toString();
12006
11991
  if (this.options().disableWs) {
11992
+ this._ws_reconnect_enabled = false;
12007
11993
  this._logger.info("disabled ws connection");
12008
11994
  } else {
12009
11995
  await this.reconnect_ws();
12010
11996
  }
12011
11997
  if (this.options().useCookie) {
12012
11998
  const client = this._client;
12013
- const url = urlJoin(this.datasetApiUrl, "security", "check?set_cookie=true");
11999
+ const url = (0, import_url_join.default)(this.datasetApiUrl, "security", "check?set_cookie=true");
12014
12000
  const headers2 = {
12015
12001
  Authorization: await this.authorizationHeader()
12016
12002
  };
@@ -12027,37 +12013,68 @@ var DataEndpoint = class extends Endpoint {
12027
12013
  return Promise.resolve(this);
12028
12014
  }
12029
12015
  async reconnect_ws() {
12016
+ if (this._ws_connecting) {
12017
+ return this._ws_connecting;
12018
+ }
12019
+ const connecting = this.open_ws();
12020
+ this._ws_connecting = connecting;
12021
+ try {
12022
+ await connecting;
12023
+ } finally {
12024
+ this._ws_connecting = null;
12025
+ }
12026
+ }
12027
+ async open_ws() {
12030
12028
  if (this._ws) {
12031
- this._ws.close();
12029
+ this.close_ws(this._ws, "unsubscribe");
12032
12030
  this._ws = null;
12033
12031
  }
12034
12032
  const baseUrl = this.datasetApiUrl?.replace("https://", "wss://").replace("http://", "ws://");
12035
12033
  if (!baseUrl) {
12036
12034
  return;
12037
12035
  }
12038
- const ws_url = urlJoin(baseUrl, "events");
12036
+ const ws_url = (0, import_url_join.default)(baseUrl, "events");
12039
12037
  this._requestLogger.debug("about to connect ws to: %s", ws_url);
12040
12038
  return new Promise((resolve, reject) => {
12039
+ let settled = false;
12040
+ const settle_ok = () => {
12041
+ settled = true;
12042
+ resolve();
12043
+ };
12044
+ const settle_err = (error) => {
12045
+ settled = true;
12046
+ reject(error);
12047
+ };
12041
12048
  const ws = createWebSocket(ws_url);
12042
12049
  if (!ws) {
12043
- return resolve();
12050
+ return settle_ok();
12044
12051
  }
12045
12052
  this._ws = ws;
12046
- ws.onopen = async () => {
12047
- const auth_header = await this.authorizationHeader();
12048
- let msg = JSON.stringify({ authorization: auth_header });
12049
- this._requestLogger.debug("ws send: %s", msg);
12050
- ws.send(msg);
12051
- msg = JSON.stringify({ subscribe: { account_uuid: this._accountId } });
12052
- this._requestLogger.debug("ws send: %s", msg);
12053
- ws.send(msg);
12054
- for (let dataset_uuid in this._dataset_uuid_to_event_handlers.keys()) {
12055
- const msg2 = JSON.stringify({ subscribe: { dataset_uuid } });
12056
- this._requestLogger.debug("ws send: %s", msg2);
12057
- ws.send(msg2);
12058
- }
12059
- this._ws_current_reconnect_delay = WS_INITIAL_RECONNECT_DELAY;
12060
- resolve();
12053
+ ws.onopen = () => {
12054
+ void this.authorizationHeader().then((auth_header) => {
12055
+ if (this._ws !== ws) {
12056
+ this.close_ws(ws, "unsubscribe");
12057
+ settle_ok();
12058
+ return;
12059
+ }
12060
+ let msg = JSON.stringify({ authorization: auth_header });
12061
+ this._requestLogger.debug("ws send: %s", msg);
12062
+ ws.send(msg);
12063
+ msg = JSON.stringify({ subscribe: { account_uuid: this._accountId } });
12064
+ this._requestLogger.debug("ws send: %s", msg);
12065
+ ws.send(msg);
12066
+ for (const dataset_uuid of this._dataset_uuid_to_event_handlers.keys()) {
12067
+ const msg2 = JSON.stringify({ subscribe: { dataset_uuid } });
12068
+ this._requestLogger.debug("ws send: %s", msg2);
12069
+ ws.send(msg2);
12070
+ }
12071
+ this._ws_current_reconnect_delay = WS_INITIAL_RECONNECT_DELAY;
12072
+ this._ws_reconnect_enabled = true;
12073
+ settle_ok();
12074
+ }).catch((error) => {
12075
+ this.close_ws(ws, "authorization failed", 1011);
12076
+ settle_err(error);
12077
+ });
12061
12078
  };
12062
12079
  ws.onmessage = (event) => {
12063
12080
  const data = JSON.parse(event.data);
@@ -12068,24 +12085,54 @@ var DataEndpoint = class extends Endpoint {
12068
12085
  ws.onclose = (event) => {
12069
12086
  const { code, reason } = event;
12070
12087
  this._requestLogger.debug("ws closed: %d %s", code, reason);
12071
- if (reason !== "unsubscribe") {
12072
- if (!this._ws_current_reconnect_delay) {
12073
- this._ws_current_reconnect_delay = WS_INITIAL_RECONNECT_DELAY;
12074
- } else if (this._ws_current_reconnect_delay < WS_MAX_RECONNECT_DELAY) {
12075
- this._ws_current_reconnect_delay *= 1.5;
12076
- }
12077
- setTimeout(async () => {
12078
- await this.reconnect_ws();
12079
- }, this._ws_current_reconnect_delay);
12088
+ if (!settled) {
12089
+ settle_err(new EyePopDataWebSocketError(ws_url, new Error(`closed before the connection was established: ${code} ${reason}`)));
12090
+ }
12091
+ if (this._ws !== ws) {
12092
+ return;
12080
12093
  }
12094
+ this._ws = null;
12095
+ this.schedule_ws_reconnect();
12081
12096
  };
12082
12097
  ws.onerror = (event) => {
12083
- this._logger.error(event);
12084
- reject(event);
12098
+ const error = new EyePopDataWebSocketError(ws_url, event);
12099
+ this._logger.error({ err: error }, "dataset event WebSocket connection failed");
12100
+ settle_err(error);
12085
12101
  return null;
12086
12102
  };
12087
12103
  });
12088
12104
  }
12105
+ close_ws(ws, reason, code = 1e3) {
12106
+ try {
12107
+ ws.close(code, reason);
12108
+ } catch (e) {
12109
+ this._logger.warn({ err: e }, "ignored exception closing the dataset event WebSocket");
12110
+ }
12111
+ }
12112
+ schedule_ws_reconnect() {
12113
+ if (!this._ws_reconnect_enabled || this._ws_reconnect_timeout) {
12114
+ return;
12115
+ }
12116
+ if (!this._ws_current_reconnect_delay) {
12117
+ this._ws_current_reconnect_delay = WS_INITIAL_RECONNECT_DELAY;
12118
+ } else if (this._ws_current_reconnect_delay < WS_MAX_RECONNECT_DELAY) {
12119
+ this._ws_current_reconnect_delay *= 1.5;
12120
+ }
12121
+ this._ws_reconnect_timeout = setTimeout(() => {
12122
+ if (!this._ws_reconnect_enabled) {
12123
+ this._ws_reconnect_timeout = null;
12124
+ return;
12125
+ }
12126
+ void this.reconnect_ws().catch((error) => {
12127
+ this._requestLogger.debug("dataset event WebSocket reconnect failed: %s", error);
12128
+ }).finally(() => {
12129
+ this._ws_reconnect_timeout = null;
12130
+ if (!this._ws) {
12131
+ this.schedule_ws_reconnect();
12132
+ }
12133
+ });
12134
+ }, this._ws_current_reconnect_delay);
12135
+ }
12089
12136
  options() {
12090
12137
  return this._options;
12091
12138
  }
@@ -12110,7 +12157,7 @@ var DataEndpoint = class extends Endpoint {
12110
12157
  body: options.body
12111
12158
  };
12112
12159
  this._requestLogger.debug("Request - " + ri.method + " " + path2 + " BODY: " + (ri.body ? ri.body : ""));
12113
- return await client.fetch(urlJoin(baseUrl ?? "", path2), ri);
12160
+ return await client.fetch((0, import_url_join.default)(baseUrl ?? "", path2), ri);
12114
12161
  });
12115
12162
  if (response.status === 204) {
12116
12163
  return null;
@@ -12757,6 +12804,97 @@ var DataEndpoint = class extends Endpoint {
12757
12804
  }
12758
12805
  };
12759
12806
 
12807
+ // depth.ts
12808
+ var isLittleEndianPlatform = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
12809
+ function base64ToBytes(base64) {
12810
+ if (typeof Buffer !== "undefined") {
12811
+ const buffer = Buffer.from(base64, "base64");
12812
+ return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
12813
+ }
12814
+ const binary = atob(base64);
12815
+ const bytes = new Uint8Array(binary.length);
12816
+ for (let i = 0; i < binary.length; i++) {
12817
+ bytes[i] = binary.charCodeAt(i);
12818
+ }
12819
+ return bytes;
12820
+ }
12821
+ var DepthMap = class {
12822
+ constructor(width, height, values) {
12823
+ this.width = width;
12824
+ this.height = height;
12825
+ this.values = values;
12826
+ }
12827
+ /**
12828
+ * The depth value at map pixel (x, y), or - when sourceWidth/sourceHeight
12829
+ * are given - at source frame coordinate (x, y) mapped proportionally.
12830
+ * Returns +Infinity for sky pixels.
12831
+ */
12832
+ at(x, y, sourceWidth, sourceHeight) {
12833
+ let mapX = x;
12834
+ let mapY = y;
12835
+ if (sourceWidth && sourceHeight) {
12836
+ mapX = x * this.width / sourceWidth;
12837
+ mapY = y * this.height / sourceHeight;
12838
+ }
12839
+ const clampedX = Math.min(Math.max(Math.floor(mapX), 0), this.width - 1);
12840
+ const clampedY = Math.min(Math.max(Math.floor(mapY), 0), this.height - 1);
12841
+ return this.values[clampedY * this.width + clampedX];
12842
+ }
12843
+ isSky(x, y, sourceWidth, sourceHeight) {
12844
+ return this.at(x, y, sourceWidth, sourceHeight) === Number.POSITIVE_INFINITY;
12845
+ }
12846
+ /** The smallest finite depth value, or undefined if the whole map is sky. */
12847
+ get finiteMin() {
12848
+ this.computeFiniteRange();
12849
+ return this._finiteMin;
12850
+ }
12851
+ /** The largest finite depth value, or undefined if the whole map is sky. */
12852
+ get finiteMax() {
12853
+ this.computeFiniteRange();
12854
+ return this._finiteMax;
12855
+ }
12856
+ computeFiniteRange() {
12857
+ if (this._finiteMin !== void 0 || this._finiteMax !== void 0) {
12858
+ return;
12859
+ }
12860
+ let min = Number.POSITIVE_INFINITY;
12861
+ let max = Number.NEGATIVE_INFINITY;
12862
+ for (let i = 0; i < this.values.length; i++) {
12863
+ const value = this.values[i];
12864
+ if (Number.isFinite(value)) {
12865
+ if (value < min) min = value;
12866
+ if (value > max) max = value;
12867
+ }
12868
+ }
12869
+ if (max >= min) {
12870
+ this._finiteMin = min;
12871
+ this._finiteMax = max;
12872
+ }
12873
+ }
12874
+ };
12875
+ function decodeDepthMap(depth) {
12876
+ if (!Number.isSafeInteger(depth.width) || depth.width <= 0 || !Number.isSafeInteger(depth.height) || depth.height <= 0 || !Number.isSafeInteger(depth.width * depth.height * 4)) {
12877
+ throw new Error(`invalid depth dimensions: ${depth.width}x${depth.height}`);
12878
+ }
12879
+ const bytes = base64ToBytes(depth.values);
12880
+ const count = depth.width * depth.height;
12881
+ if (bytes.byteLength !== count * 4) {
12882
+ throw new Error(`depth values hold ${bytes.byteLength} bytes, expected ${count * 4} for ${depth.width}x${depth.height} float32`);
12883
+ }
12884
+ let values;
12885
+ if (isLittleEndianPlatform) {
12886
+ const aligned = new Uint8Array(bytes);
12887
+ values = new Float32Array(aligned.buffer, 0, count);
12888
+ } else {
12889
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
12890
+ values = new Float32Array(count);
12891
+ for (let i = 0; i < count; i++) {
12892
+ values[i] = view.getFloat32(i * 4, true);
12893
+ }
12894
+ }
12895
+ return new DepthMap(depth.width, depth.height, values);
12896
+ }
12897
+
12760
12898
  // worker/webrtc_whep.ts
12761
12899
  var WebrtcWhep = class extends WebrtcBase {
12762
12900
  constructor(ingressId, getSession, client, requestLogger) {
@@ -12991,11 +13129,13 @@ var index_default = EyePop;
12991
13129
  DEFAULT_PREDICTION_VERSION,
12992
13130
  DataApiType,
12993
13131
  DataEndpoint,
13132
+ DepthMap,
12994
13133
  Endpoint,
12995
13134
  EndpointState,
12996
13135
  EvaluationStatus,
12997
13136
  ExportedBy,
12998
13137
  EyePop,
13138
+ EyePopDataWebSocketError,
12999
13139
  EyepopLineDecoder,
13000
13140
  ForwardOperatorType,
13001
13141
  InferenceType,
@@ -13031,6 +13171,7 @@ var index_default = EyePop;
13031
13171
  WorkflowPhase,
13032
13172
  accessTokenCredential,
13033
13173
  apiKeyCredential,
13174
+ decodeDepthMap,
13034
13175
  encodeMultipartFormData,
13035
13176
  getBaseUrl,
13036
13177
  randomMultipartBoundary,