@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.
@@ -152,12 +152,15 @@ interface OAuth2Auth {
152
152
  oAuth2: true | Auth0Options;
153
153
  }
154
154
  type Authentication = undefined | SecretKeyAuth | SessionAuth | OAuth2Auth;
155
+ declare enum TransientPopId {
156
+ Transient = "transient"
157
+ }
155
158
  interface Options {
156
159
  auth?: Authentication | undefined;
157
160
  /**
158
161
  * Defaults to process.env['EYEPOP_POP_ID'].
159
162
  */
160
- popId?: string | undefined;
163
+ popId?: string | TransientPopId | undefined;
161
164
  /**
162
165
  * Override the default base URL for the API, e.g., "https://api.eyepop.ai/"
163
166
  *
@@ -177,6 +180,7 @@ declare class Endpoint {
177
180
  private _baseUrl;
178
181
  private _pipelineId;
179
182
  private _popName;
183
+ private _pipeline;
180
184
  private _client;
181
185
  private _limit;
182
186
  private _state;
@@ -190,6 +194,8 @@ declare class Endpoint {
190
194
  state(): EndpointState;
191
195
  pendingJobs(): number;
192
196
  popName(): string | null;
197
+ popComp(): string | null;
198
+ changePopComp(popComp: string): Promise<void>;
193
199
  popId(): string | null;
194
200
  onStateChanged(handler: (fromState: EndpointState, toState: EndpointState) => void): Endpoint;
195
201
  onIngressEvent(handler: (event: IngressEvent) => void): Endpoint;
@@ -208,9 +214,11 @@ declare class Endpoint {
208
214
  private jobDone;
209
215
  private updateState;
210
216
  private jobStatus;
217
+ private fetchWithRetry;
211
218
  private reconnect;
212
219
  private authorizationHeader;
213
220
  private currentAccessToken;
221
+ private startPopLessPipeline;
214
222
  }
215
223
 
216
224
  declare namespace EyePop {
@@ -152,12 +152,15 @@ interface OAuth2Auth {
152
152
  oAuth2: true | Auth0Options;
153
153
  }
154
154
  type Authentication = undefined | SecretKeyAuth | SessionAuth | OAuth2Auth;
155
+ declare enum TransientPopId {
156
+ Transient = "transient"
157
+ }
155
158
  interface Options {
156
159
  auth?: Authentication | undefined;
157
160
  /**
158
161
  * Defaults to process.env['EYEPOP_POP_ID'].
159
162
  */
160
- popId?: string | undefined;
163
+ popId?: string | TransientPopId | undefined;
161
164
  /**
162
165
  * Override the default base URL for the API, e.g., "https://api.eyepop.ai/"
163
166
  *
@@ -177,6 +180,7 @@ declare class Endpoint {
177
180
  private _baseUrl;
178
181
  private _pipelineId;
179
182
  private _popName;
183
+ private _pipeline;
180
184
  private _client;
181
185
  private _limit;
182
186
  private _state;
@@ -190,6 +194,8 @@ declare class Endpoint {
190
194
  state(): EndpointState;
191
195
  pendingJobs(): number;
192
196
  popName(): string | null;
197
+ popComp(): string | null;
198
+ changePopComp(popComp: string): Promise<void>;
193
199
  popId(): string | null;
194
200
  onStateChanged(handler: (fromState: EndpointState, toState: EndpointState) => void): Endpoint;
195
201
  onIngressEvent(handler: (event: IngressEvent) => void): Endpoint;
@@ -208,9 +214,11 @@ declare class Endpoint {
208
214
  private jobDone;
209
215
  private updateState;
210
216
  private jobStatus;
217
+ private fetchWithRetry;
211
218
  private reconnect;
212
219
  private authorizationHeader;
213
220
  private currentAccessToken;
221
+ private startPopLessPipeline;
214
222
  }
215
223
 
216
224
  declare namespace EyePop {
@@ -9821,6 +9821,7 @@ var Endpoint = class {
9821
9821
  this._expire_token_time = null;
9822
9822
  this._client = null;
9823
9823
  this._state = "Idle" /* Idle */;
9824
+ this._pipeline = null;
9824
9825
  this._stateChangeHandler = null;
9825
9826
  this._ingressEventHandler = null;
9826
9827
  this._ingressEventWs = null;
@@ -9850,6 +9851,44 @@ var Endpoint = class {
9850
9851
  popName() {
9851
9852
  return this._popName;
9852
9853
  }
9854
+ popComp() {
9855
+ if (this._pipeline) {
9856
+ return this._pipeline.inferPipeline;
9857
+ } else {
9858
+ return null;
9859
+ }
9860
+ }
9861
+ async changePopComp(popComp) {
9862
+ const client = this._client;
9863
+ const baseUrl = this._baseUrl;
9864
+ if (!baseUrl || !client) {
9865
+ return Promise.reject("endpoint not connected, use connect() before changePopComp()");
9866
+ }
9867
+ const patch_url = `${this._baseUrl}/pipelines/${this._pipelineId}/inferencePipeline`;
9868
+ const body = {
9869
+ "pipeline": popComp
9870
+ };
9871
+ this._requestLogger.debug("before PATCH %s", patch_url);
9872
+ let response = await this.fetchWithRetry(async () => {
9873
+ let headers = {
9874
+ "Authorization": await this.authorizationHeader(),
9875
+ "Content-Type": "application/json"
9876
+ };
9877
+ return client.fetch(patch_url, {
9878
+ method: "PATCH",
9879
+ body: JSON.stringify(body),
9880
+ headers
9881
+ });
9882
+ });
9883
+ if (response.status != 204) {
9884
+ const message = await response.text();
9885
+ return Promise.reject(`Unexpected status ${response.status}: ${message}`);
9886
+ }
9887
+ this._requestLogger.debug("after PATCH %s", patch_url);
9888
+ if (this._pipeline) {
9889
+ this._pipeline.inferPipeline = popComp;
9890
+ }
9891
+ }
9853
9892
  popId() {
9854
9893
  return this._options.popId || null;
9855
9894
  }
@@ -9888,19 +9927,22 @@ var Endpoint = class {
9888
9927
  return Promise.reject("option secretKey or environment variable EYEPOP_SECRET_KEY is required");
9889
9928
  }
9890
9929
  this._client = await createHttpClient();
9930
+ const client = this._client;
9891
9931
  let result = await this.reconnect();
9892
9932
  if (this._baseUrl && this._options.stopJobs) {
9893
9933
  const stop_url = `${this._baseUrl}/pipelines/${this._pipelineId}/source?mode=preempt&processing=sync`;
9894
9934
  const body = { "sourceType": "NONE" };
9895
- const headers = {
9896
- "Authorization": await this.authorizationHeader(),
9897
- "Content-Type": "application/json"
9898
- };
9899
9935
  this._requestLogger.debug("before PATCH %s", stop_url);
9900
- let response = await this._client.fetch(stop_url, {
9901
- method: "PATCH",
9902
- headers,
9903
- body: JSON.stringify(body)
9936
+ let response = await this.fetchWithRetry(async () => {
9937
+ const headers = {
9938
+ "Authorization": await this.authorizationHeader(),
9939
+ "Content-Type": "application/json"
9940
+ };
9941
+ return client.fetch(stop_url, {
9942
+ method: "PATCH",
9943
+ headers,
9944
+ body: JSON.stringify(body)
9945
+ });
9904
9946
  });
9905
9947
  if (response.status >= 300) {
9906
9948
  const message = await response.text();
@@ -9981,25 +10023,19 @@ var Endpoint = class {
9981
10023
  }
9982
10024
  }
9983
10025
  async startIngressWs() {
9984
- if (this._ingressEventWs || !this._baseUrl || !this._client) {
10026
+ const client = this._client;
10027
+ if (this._ingressEventWs || !this._baseUrl || !client) {
9985
10028
  return;
9986
10029
  }
9987
10030
  try {
9988
10031
  const getTokenUrl = `${this._baseUrl}/liveIngress/events/token`;
9989
- const headers = {
9990
- "Authorization": await this.authorizationHeader()
9991
- };
9992
10032
  this._requestLogger.debug("before GET %s", getTokenUrl);
9993
- let response = await this._client.fetch(getTokenUrl, { headers });
9994
- if (response.status == 401) {
9995
- this._requestLogger.debug("after GET %s: 401, about to retry with fresh access token", getTokenUrl);
9996
- this._token = null;
9997
- const headers2 = {
10033
+ let response = await this.fetchWithRetry(async () => {
10034
+ const headers = {
9998
10035
  "Authorization": await this.authorizationHeader()
9999
10036
  };
10000
- this.updateState("FetchConfig" /* FetchConfig */);
10001
- response = await this._client.fetch(getTokenUrl, { headers: headers2 });
10002
- }
10037
+ return client.fetch(getTokenUrl, { headers });
10038
+ });
10003
10039
  if (response.status != 200) {
10004
10040
  const message = await response.text();
10005
10041
  return Promise.reject(`Unexpected status ${response.status}: ${message}`);
@@ -10145,11 +10181,49 @@ var Endpoint = class {
10145
10181
  this._expire_token_time = null;
10146
10182
  }
10147
10183
  }
10184
+ async fetchWithRetry(fetcher, retries = 1) {
10185
+ while (true) {
10186
+ try {
10187
+ const response = await fetcher();
10188
+ if (response.status == 401) {
10189
+ this._token = null;
10190
+ this._expire_token_time = null;
10191
+ if (retries--) {
10192
+ this._requestLogger.info("received 401 response, attempt to reauthorize and retry");
10193
+ } else {
10194
+ return Promise.reject(`response ${response.status}: ${response.statusText}`);
10195
+ }
10196
+ } else if (response.status == 404) {
10197
+ this._pipelineId = null;
10198
+ this._baseUrl = null;
10199
+ if (retries--) {
10200
+ this._requestLogger.info("received 404 response, attempt to restart pop and retry");
10201
+ } else {
10202
+ return Promise.reject(`response ${response.status}: ${response.statusText}`);
10203
+ }
10204
+ } else {
10205
+ return response;
10206
+ }
10207
+ } catch (error) {
10208
+ this._pipelineId = null;
10209
+ this._baseUrl = null;
10210
+ if (retries--) {
10211
+ this._requestLogger.info("unknown, attempt to restart pop (as if we received 404)", error);
10212
+ return Promise.reject(error);
10213
+ }
10214
+ }
10215
+ }
10216
+ }
10148
10217
  async reconnect() {
10149
10218
  if (!this._client) {
10150
10219
  return Promise.reject("endpoint not initialized");
10151
10220
  }
10152
- const config_url = `${this.eyepopUrl()}/pops/${this._options.popId}/config?auto_start=false`;
10221
+ let config_url;
10222
+ if (this._options.popId == "transient" /* Transient */) {
10223
+ config_url = `${this.eyepopUrl()}/workers/config`;
10224
+ } else {
10225
+ config_url = `${this.eyepopUrl()}/pops/${this._options.popId}/config?auto_start=false`;
10226
+ }
10153
10227
  const headers = {
10154
10228
  "Authorization": await this.authorizationHeader()
10155
10229
  };
@@ -10165,7 +10239,6 @@ var Endpoint = class {
10165
10239
  this.updateState("FetchConfig" /* FetchConfig */);
10166
10240
  response = await this._client.fetch(config_url, {
10167
10241
  headers: headers2
10168
- // @ts-ignore
10169
10242
  });
10170
10243
  }
10171
10244
  if (response.status != 200) {
@@ -10183,7 +10256,6 @@ var Endpoint = class {
10183
10256
  this.updateState("StartingPop" /* StartingPop */);
10184
10257
  response = await this._client.fetch(auto_start_config_url, {
10185
10258
  headers: headers2
10186
- // @ts-ignore
10187
10259
  });
10188
10260
  if (response.status != 200) {
10189
10261
  this.updateState("Error" /* Error */);
@@ -10194,13 +10266,35 @@ var Endpoint = class {
10194
10266
  }
10195
10267
  const baseUrl = new URL(config.base_url, this.eyepopUrl());
10196
10268
  this._baseUrl = baseUrl.toString();
10197
- this._pipelineId = config.pipeline_id;
10198
- this._popName = config.name;
10269
+ if (this._options.popId == "transient" /* Transient */) {
10270
+ this._pipelineId = await this.startPopLessPipeline();
10271
+ this._popName = this._options.popId;
10272
+ } else {
10273
+ this._pipelineId = config.pipeline_id;
10274
+ this._popName = config.name;
10275
+ }
10199
10276
  this._requestLogger.debug("after GET %s: %s / %s", config_url, this._baseUrl, this._pipelineId);
10200
10277
  if (!this._pipelineId || !this._baseUrl) {
10201
10278
  return Promise.reject(`Pop not started`);
10202
10279
  }
10203
10280
  this._baseUrl = this._baseUrl.replace(/\/+$/, "");
10281
+ if (this._baseUrl) {
10282
+ const get_url = `${this._baseUrl}/pipelines/${this._pipelineId}`;
10283
+ const headers2 = {
10284
+ "Authorization": await this.authorizationHeader()
10285
+ };
10286
+ this._requestLogger.debug("before GET %s", get_url);
10287
+ let response2 = await this._client.fetch(get_url, {
10288
+ method: "GET",
10289
+ headers: headers2
10290
+ });
10291
+ if (response2.status > 200) {
10292
+ const message = await response2.text();
10293
+ return Promise.reject(`Unexpected status ${response2.status}: ${message}`);
10294
+ }
10295
+ this._requestLogger.debug("after GET %s", get_url);
10296
+ this._pipeline = await response2.json();
10297
+ }
10204
10298
  this.updateState();
10205
10299
  return Promise.resolve(this);
10206
10300
  }
@@ -10255,6 +10349,60 @@ var Endpoint = class {
10255
10349
  this._logger.debug("using access token, valid for at least %d seconds", this._expire_token_time - now);
10256
10350
  return this._token;
10257
10351
  }
10352
+ async startPopLessPipeline() {
10353
+ if (this._client == null || this._baseUrl == null) {
10354
+ return Promise.reject("endpoint not initialized");
10355
+ }
10356
+ this.updateState("StartingPop" /* StartingPop */);
10357
+ let pipeline;
10358
+ if (this._pipeline) {
10359
+ pipeline = this._pipeline.inferPipeline;
10360
+ } else {
10361
+ pipeline = "identity";
10362
+ }
10363
+ const body = {
10364
+ "inferPipelineDef": {
10365
+ "pipeline": pipeline
10366
+ },
10367
+ "source": {
10368
+ "sourceType": "NONE"
10369
+ },
10370
+ "idleTimeoutSeconds": 30,
10371
+ "logging": ["out_meta"],
10372
+ "videoOutput": "no_output"
10373
+ };
10374
+ const post_url = `${this._baseUrl.replace(/\/+$/, "")}/pipelines`;
10375
+ let headers = {
10376
+ "Content-Type": "application/json",
10377
+ "Authorization": await this.authorizationHeader()
10378
+ };
10379
+ this._requestLogger.debug("before POST %s", post_url);
10380
+ let response = await this._client.fetch(post_url, {
10381
+ method: "POST",
10382
+ headers,
10383
+ body: JSON.stringify(body)
10384
+ });
10385
+ if (response.status == 401) {
10386
+ this._requestLogger.debug("after GET %s: 401, about to retry with fresh access token", post_url);
10387
+ this._token = null;
10388
+ headers = {
10389
+ "Content-Type": "application/json",
10390
+ "Authorization": await this.authorizationHeader()
10391
+ };
10392
+ response = await this._client.fetch(post_url, {
10393
+ method: "POST",
10394
+ headers,
10395
+ body: JSON.stringify(body)
10396
+ });
10397
+ }
10398
+ if (response.status != 200) {
10399
+ const message = await response.text();
10400
+ return Promise.reject(`Unexpected status ${response.status}: ${message}`);
10401
+ }
10402
+ this._requestLogger.debug("after POST %s", post_url);
10403
+ const pipelineId = (await response.json())["id"];
10404
+ return pipelineId;
10405
+ }
10258
10406
  };
10259
10407
 
10260
10408
  // index.ts