@eyepop.ai/eyepop 0.17.0 → 0.18.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.
@@ -9792,6 +9792,7 @@ var Endpoint = class {
9792
9792
  this._expire_token_time = null;
9793
9793
  this._client = null;
9794
9794
  this._state = "Idle" /* Idle */;
9795
+ this._pipeline = null;
9795
9796
  this._stateChangeHandler = null;
9796
9797
  this._ingressEventHandler = null;
9797
9798
  this._ingressEventWs = null;
@@ -9821,6 +9822,44 @@ var Endpoint = class {
9821
9822
  popName() {
9822
9823
  return this._popName;
9823
9824
  }
9825
+ popComp() {
9826
+ if (this._pipeline) {
9827
+ return this._pipeline.inferPipeline;
9828
+ } else {
9829
+ return null;
9830
+ }
9831
+ }
9832
+ async changePopComp(popComp) {
9833
+ const client = this._client;
9834
+ const baseUrl = this._baseUrl;
9835
+ if (!baseUrl || !client) {
9836
+ return Promise.reject("endpoint not connected, use connect() before changePopComp()");
9837
+ }
9838
+ const patch_url = `${this._baseUrl}/pipelines/${this._pipelineId}/inferencePipeline`;
9839
+ const body = {
9840
+ "pipeline": popComp
9841
+ };
9842
+ this._requestLogger.debug("before PATCH %s", patch_url);
9843
+ let response = await this.fetchWithRetry(async () => {
9844
+ let headers = {
9845
+ "Authorization": await this.authorizationHeader(),
9846
+ "Content-Type": "application/json"
9847
+ };
9848
+ return client.fetch(patch_url, {
9849
+ method: "PATCH",
9850
+ body: JSON.stringify(body),
9851
+ headers
9852
+ });
9853
+ });
9854
+ if (response.status != 204) {
9855
+ const message = await response.text();
9856
+ return Promise.reject(`Unexpected status ${response.status}: ${message}`);
9857
+ }
9858
+ this._requestLogger.debug("after PATCH %s", patch_url);
9859
+ if (this._pipeline) {
9860
+ this._pipeline.inferPipeline = popComp;
9861
+ }
9862
+ }
9824
9863
  popId() {
9825
9864
  return this._options.popId || null;
9826
9865
  }
@@ -9859,19 +9898,22 @@ var Endpoint = class {
9859
9898
  return Promise.reject("option secretKey or environment variable EYEPOP_SECRET_KEY is required");
9860
9899
  }
9861
9900
  this._client = await createHttpClient();
9901
+ const client = this._client;
9862
9902
  let result = await this.reconnect();
9863
9903
  if (this._baseUrl && this._options.stopJobs) {
9864
9904
  const stop_url = `${this._baseUrl}/pipelines/${this._pipelineId}/source?mode=preempt&processing=sync`;
9865
9905
  const body = { "sourceType": "NONE" };
9866
- const headers = {
9867
- "Authorization": await this.authorizationHeader(),
9868
- "Content-Type": "application/json"
9869
- };
9870
9906
  this._requestLogger.debug("before PATCH %s", stop_url);
9871
- let response = await this._client.fetch(stop_url, {
9872
- method: "PATCH",
9873
- headers,
9874
- body: JSON.stringify(body)
9907
+ let response = await this.fetchWithRetry(async () => {
9908
+ const headers = {
9909
+ "Authorization": await this.authorizationHeader(),
9910
+ "Content-Type": "application/json"
9911
+ };
9912
+ return client.fetch(stop_url, {
9913
+ method: "PATCH",
9914
+ headers,
9915
+ body: JSON.stringify(body)
9916
+ });
9875
9917
  });
9876
9918
  if (response.status >= 300) {
9877
9919
  const message = await response.text();
@@ -9952,25 +9994,19 @@ var Endpoint = class {
9952
9994
  }
9953
9995
  }
9954
9996
  async startIngressWs() {
9955
- if (this._ingressEventWs || !this._baseUrl || !this._client) {
9997
+ const client = this._client;
9998
+ if (this._ingressEventWs || !this._baseUrl || !client) {
9956
9999
  return;
9957
10000
  }
9958
10001
  try {
9959
10002
  const getTokenUrl = `${this._baseUrl}/liveIngress/events/token`;
9960
- const headers = {
9961
- "Authorization": await this.authorizationHeader()
9962
- };
9963
10003
  this._requestLogger.debug("before GET %s", getTokenUrl);
9964
- let response = await this._client.fetch(getTokenUrl, { headers });
9965
- if (response.status == 401) {
9966
- this._requestLogger.debug("after GET %s: 401, about to retry with fresh access token", getTokenUrl);
9967
- this._token = null;
9968
- const headers2 = {
10004
+ let response = await this.fetchWithRetry(async () => {
10005
+ const headers = {
9969
10006
  "Authorization": await this.authorizationHeader()
9970
10007
  };
9971
- this.updateState("FetchConfig" /* FetchConfig */);
9972
- response = await this._client.fetch(getTokenUrl, { headers: headers2 });
9973
- }
10008
+ return client.fetch(getTokenUrl, { headers });
10009
+ });
9974
10010
  if (response.status != 200) {
9975
10011
  const message = await response.text();
9976
10012
  return Promise.reject(`Unexpected status ${response.status}: ${message}`);
@@ -10116,11 +10152,49 @@ var Endpoint = class {
10116
10152
  this._expire_token_time = null;
10117
10153
  }
10118
10154
  }
10155
+ async fetchWithRetry(fetcher, retries = 1) {
10156
+ while (true) {
10157
+ try {
10158
+ const response = await fetcher();
10159
+ if (response.status == 401) {
10160
+ this._token = null;
10161
+ this._expire_token_time = null;
10162
+ if (retries--) {
10163
+ this._requestLogger.info("received 401 response, attempt to reauthorize and retry");
10164
+ } else {
10165
+ return Promise.reject(`response ${response.status}: ${response.statusText}`);
10166
+ }
10167
+ } else if (response.status == 404) {
10168
+ this._pipelineId = null;
10169
+ this._baseUrl = null;
10170
+ if (retries--) {
10171
+ this._requestLogger.info("received 404 response, attempt to restart pop and retry");
10172
+ } else {
10173
+ return Promise.reject(`response ${response.status}: ${response.statusText}`);
10174
+ }
10175
+ } else {
10176
+ return response;
10177
+ }
10178
+ } catch (error) {
10179
+ this._pipelineId = null;
10180
+ this._baseUrl = null;
10181
+ if (retries--) {
10182
+ this._requestLogger.info("unknown, attempt to restart pop (as if we received 404)", error);
10183
+ return Promise.reject(error);
10184
+ }
10185
+ }
10186
+ }
10187
+ }
10119
10188
  async reconnect() {
10120
10189
  if (!this._client) {
10121
10190
  return Promise.reject("endpoint not initialized");
10122
10191
  }
10123
- const config_url = `${this.eyepopUrl()}/pops/${this._options.popId}/config?auto_start=false`;
10192
+ let config_url;
10193
+ if (this._options.popId == "transient" /* Transient */) {
10194
+ config_url = `${this.eyepopUrl()}/workers/config`;
10195
+ } else {
10196
+ config_url = `${this.eyepopUrl()}/pops/${this._options.popId}/config?auto_start=false`;
10197
+ }
10124
10198
  const headers = {
10125
10199
  "Authorization": await this.authorizationHeader()
10126
10200
  };
@@ -10136,7 +10210,6 @@ var Endpoint = class {
10136
10210
  this.updateState("FetchConfig" /* FetchConfig */);
10137
10211
  response = await this._client.fetch(config_url, {
10138
10212
  headers: headers2
10139
- // @ts-ignore
10140
10213
  });
10141
10214
  }
10142
10215
  if (response.status != 200) {
@@ -10154,7 +10227,6 @@ var Endpoint = class {
10154
10227
  this.updateState("StartingPop" /* StartingPop */);
10155
10228
  response = await this._client.fetch(auto_start_config_url, {
10156
10229
  headers: headers2
10157
- // @ts-ignore
10158
10230
  });
10159
10231
  if (response.status != 200) {
10160
10232
  this.updateState("Error" /* Error */);
@@ -10165,13 +10237,35 @@ var Endpoint = class {
10165
10237
  }
10166
10238
  const baseUrl = new URL(config.base_url, this.eyepopUrl());
10167
10239
  this._baseUrl = baseUrl.toString();
10168
- this._pipelineId = config.pipeline_id;
10169
- this._popName = config.name;
10240
+ if (this._options.popId == "transient" /* Transient */) {
10241
+ this._pipelineId = await this.startPopLessPipeline();
10242
+ this._popName = this._options.popId;
10243
+ } else {
10244
+ this._pipelineId = config.pipeline_id;
10245
+ this._popName = config.name;
10246
+ }
10170
10247
  this._requestLogger.debug("after GET %s: %s / %s", config_url, this._baseUrl, this._pipelineId);
10171
10248
  if (!this._pipelineId || !this._baseUrl) {
10172
10249
  return Promise.reject(`Pop not started`);
10173
10250
  }
10174
10251
  this._baseUrl = this._baseUrl.replace(/\/+$/, "");
10252
+ if (this._baseUrl) {
10253
+ const get_url = `${this._baseUrl}/pipelines/${this._pipelineId}`;
10254
+ const headers2 = {
10255
+ "Authorization": await this.authorizationHeader()
10256
+ };
10257
+ this._requestLogger.debug("before GET %s", get_url);
10258
+ let response2 = await this._client.fetch(get_url, {
10259
+ method: "GET",
10260
+ headers: headers2
10261
+ });
10262
+ if (response2.status > 200) {
10263
+ const message = await response2.text();
10264
+ return Promise.reject(`Unexpected status ${response2.status}: ${message}`);
10265
+ }
10266
+ this._requestLogger.debug("after GET %s", get_url);
10267
+ this._pipeline = await response2.json();
10268
+ }
10175
10269
  this.updateState();
10176
10270
  return Promise.resolve(this);
10177
10271
  }
@@ -10226,6 +10320,60 @@ var Endpoint = class {
10226
10320
  this._logger.debug("using access token, valid for at least %d seconds", this._expire_token_time - now);
10227
10321
  return this._token;
10228
10322
  }
10323
+ async startPopLessPipeline() {
10324
+ if (this._client == null || this._baseUrl == null) {
10325
+ return Promise.reject("endpoint not initialized");
10326
+ }
10327
+ this.updateState("StartingPop" /* StartingPop */);
10328
+ let pipeline;
10329
+ if (this._pipeline) {
10330
+ pipeline = this._pipeline.inferPipeline;
10331
+ } else {
10332
+ pipeline = "identity";
10333
+ }
10334
+ const body = {
10335
+ "inferPipelineDef": {
10336
+ "pipeline": pipeline
10337
+ },
10338
+ "source": {
10339
+ "sourceType": "NONE"
10340
+ },
10341
+ "idleTimeoutSeconds": 30,
10342
+ "logging": ["out_meta"],
10343
+ "videoOutput": "no_output"
10344
+ };
10345
+ const post_url = `${this._baseUrl.replace(/\/+$/, "")}/pipelines`;
10346
+ let headers = {
10347
+ "Content-Type": "application/json",
10348
+ "Authorization": await this.authorizationHeader()
10349
+ };
10350
+ this._requestLogger.debug("before POST %s", post_url);
10351
+ let response = await this._client.fetch(post_url, {
10352
+ method: "POST",
10353
+ headers,
10354
+ body: JSON.stringify(body)
10355
+ });
10356
+ if (response.status == 401) {
10357
+ this._requestLogger.debug("after GET %s: 401, about to retry with fresh access token", post_url);
10358
+ this._token = null;
10359
+ headers = {
10360
+ "Content-Type": "application/json",
10361
+ "Authorization": await this.authorizationHeader()
10362
+ };
10363
+ response = await this._client.fetch(post_url, {
10364
+ method: "POST",
10365
+ headers,
10366
+ body: JSON.stringify(body)
10367
+ });
10368
+ }
10369
+ if (response.status != 200) {
10370
+ const message = await response.text();
10371
+ return Promise.reject(`Unexpected status ${response.status}: ${message}`);
10372
+ }
10373
+ this._requestLogger.debug("after POST %s", post_url);
10374
+ const pipelineId = (await response.json())["id"];
10375
+ return pipelineId;
10376
+ }
10229
10377
  };
10230
10378
 
10231
10379
  // index.ts