@eyepop.ai/eyepop 0.9.2 → 0.11.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.mjs CHANGED
@@ -1,9 +1,4 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
1
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
2
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
3
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
4
  }) : x)(function(x) {
@@ -14,22 +9,6 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
14
9
  var __commonJS = (cb, mod) => function __require2() {
15
10
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
11
  };
17
- var __copyProps = (to, from, except, desc) => {
18
- if (from && typeof from === "object" || typeof from === "function") {
19
- for (let key of __getOwnPropNames(from))
20
- if (!__hasOwnProp.call(to, key) && key !== except)
21
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
22
- }
23
- return to;
24
- };
25
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
26
- // If the importer is in node compatibility mode or this is not an ESM
27
- // file that has been converted to a CommonJS file using a Babel-
28
- // compatible transform (i.e. "__esModule" has not been set), then set
29
- // "default" to the CommonJS "module.exports" for node compatibility.
30
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
31
- mod
32
- ));
33
12
 
34
13
  // node_modules/mime-db/db.json
35
14
  var require_db = __commonJS({
@@ -8655,6 +8634,17 @@ var require_mime_types = __commonJS({
8655
8634
  }
8656
8635
  });
8657
8636
 
8637
+ // src/types.ts
8638
+ var EndpointState = /* @__PURE__ */ ((EndpointState2) => {
8639
+ EndpointState2["Idle"] = "Idle";
8640
+ EndpointState2["Busy"] = "Busy";
8641
+ EndpointState2["Authenticating"] = "Authenticating";
8642
+ EndpointState2["FetchConfig"] = "FetchConfig";
8643
+ EndpointState2["StartingPop"] = "StartingPop";
8644
+ EndpointState2["Error"] = "Error";
8645
+ return EndpointState2;
8646
+ })(EndpointState || {});
8647
+
8658
8648
  // src/streaming.ts
8659
8649
  var Stream = class _Stream {
8660
8650
  constructor(iterator, controller) {
@@ -8907,16 +8897,13 @@ function readableStreamAsyncIterable(stream) {
8907
8897
  }
8908
8898
 
8909
8899
  // src/jobs.ts
8910
- var _AbstractJob = class _AbstractJob {
8911
- constructor(baseUrl, pipelineId, authorizationHeader, client, requestLogger) {
8900
+ var AbstractJob = class {
8901
+ constructor(getSession, client, requestLogger) {
8912
8902
  this._responseStream = null;
8913
8903
  this._controller = new AbortController();
8914
- this._baseUrl = baseUrl.replace(/\/+$/, "");
8915
- this._pipelineId = pipelineId;
8916
- this._authorizationHeader = authorizationHeader;
8904
+ this._getSession = getSession;
8917
8905
  this._client = client;
8918
8906
  this._requestLogger = requestLogger;
8919
- this.i = _AbstractJob.n++;
8920
8907
  }
8921
8908
  [Symbol.asyncIterator]() {
8922
8909
  if (!this._responseStream) {
@@ -8927,22 +8914,55 @@ var _AbstractJob = class _AbstractJob {
8927
8914
  async startJob() {
8928
8915
  return Promise.reject("abstract class");
8929
8916
  }
8930
- start(done) {
8931
- this._responseStream = new Promise((resolve2, reject) => {
8932
- const request = this.startJob();
8933
- request.then((response) => {
8934
- if (response.status != 200) {
8935
- reject(`upload error ${response.status}: ${response.text()}`);
8936
- } else if (!response.body) {
8937
- reject(`response body is empty`);
8938
- } else {
8939
- resolve2(response.body);
8917
+ start(done, status) {
8918
+ this._responseStream = new Promise(async (resolve2, reject) => {
8919
+ try {
8920
+ let retries = 1;
8921
+ while (true) {
8922
+ try {
8923
+ const response = await this.startJob();
8924
+ if (response.status == 401) {
8925
+ status(response.status);
8926
+ if (retries--) {
8927
+ this._requestLogger.info("received 401 response, attempt to reauthorize once");
8928
+ } else {
8929
+ reject(`response ${response.status}: ${response.statusText}`);
8930
+ break;
8931
+ }
8932
+ } else if (response.status == 404) {
8933
+ status(response.status);
8934
+ if (retries--) {
8935
+ this._requestLogger.info("received 404 response, attempt to restart pop");
8936
+ } else {
8937
+ reject(`response ${response.status}: ${response.statusText}`);
8938
+ break;
8939
+ }
8940
+ } else if (response.status != 200) {
8941
+ reject(`upload error ${response.status}: ${await response.text()}`);
8942
+ break;
8943
+ } else if (!response.body) {
8944
+ reject(`response body is empty`);
8945
+ break;
8946
+ } else {
8947
+ resolve2(response.body);
8948
+ break;
8949
+ }
8950
+ } catch (error) {
8951
+ if (retries--) {
8952
+ this._requestLogger.info("unknown, attempt to restart pop (as if we received 404)", error);
8953
+ status(404);
8954
+ } else {
8955
+ status(500);
8956
+ reject(error);
8957
+ break;
8958
+ }
8959
+ }
8940
8960
  }
8941
- }).catch((reason) => {
8961
+ } catch (reason) {
8942
8962
  reject(reason);
8943
- }).finally(() => {
8963
+ } finally {
8944
8964
  done();
8945
- });
8965
+ }
8946
8966
  });
8947
8967
  return this;
8948
8968
  }
@@ -8950,24 +8970,24 @@ var _AbstractJob = class _AbstractJob {
8950
8970
  this._controller.abort("cancelled");
8951
8971
  }
8952
8972
  };
8953
- _AbstractJob.n = 0;
8954
- var AbstractJob = _AbstractJob;
8973
+ AbstractJob.n = 0;
8955
8974
  var UploadJob = class extends AbstractJob {
8956
8975
  get [Symbol.toStringTag]() {
8957
8976
  return "uploadJob";
8958
8977
  }
8959
- constructor(stream, mimeType, baseUrl, pipelineId, authorizationHeader, client, requestLogger) {
8960
- super(baseUrl, pipelineId, authorizationHeader, client, requestLogger);
8978
+ constructor(stream, mimeType, getSession, client, requestLogger) {
8979
+ super(getSession, client, requestLogger);
8961
8980
  this._uploadStream = stream;
8962
8981
  this._mimeType = mimeType;
8963
8982
  }
8964
8983
  async startJob() {
8984
+ const session = await this._getSession();
8965
8985
  const headers = {
8966
- "Authorization": this._authorizationHeader,
8986
+ "Authorization": `Bearer ${session.accessToken}`,
8967
8987
  "Accept": "application/jsonl",
8968
8988
  "Content-Type": this._mimeType
8969
8989
  };
8970
- const postUrl = `${this._baseUrl}/pipelines/${this._pipelineId}/source?mode=queue&processing=sync`;
8990
+ const postUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
8971
8991
  this._requestLogger.debug("before POST %s with stream as body");
8972
8992
  const response = await this._client.fetch(postUrl, {
8973
8993
  headers,
@@ -8983,26 +9003,60 @@ var UploadJob = class extends AbstractJob {
8983
9003
  }
8984
9004
  };
8985
9005
  var LoadFromJob = class extends AbstractJob {
8986
- constructor(location, baseUrl, pipelineId, authorizationHeader, client, requestLogger) {
8987
- super(baseUrl, pipelineId, authorizationHeader, client, requestLogger);
9006
+ constructor(location, getSession, client, requestLogger) {
9007
+ super(getSession, client, requestLogger);
8988
9008
  this._location = location;
8989
9009
  }
8990
9010
  get [Symbol.toStringTag]() {
8991
9011
  return "loadFromJob";
8992
9012
  }
8993
9013
  async startJob() {
9014
+ const body = {
9015
+ "sourceType": "URL",
9016
+ "url": this._location
9017
+ };
9018
+ const session = await this._getSession();
8994
9019
  const headers = {
8995
- "Authorization": this._authorizationHeader,
9020
+ "Authorization": `Bearer ${session.accessToken}`,
8996
9021
  "Accept": "application/jsonl",
8997
9022
  "Content-Type": "application/json"
8998
9023
  };
9024
+ const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
9025
+ this._requestLogger.debug("before PATCH %s with url %s as source", patchUrl, this._location);
9026
+ const response = await this._client.fetch(patchUrl, {
9027
+ headers,
9028
+ method: "PATCH",
9029
+ body: JSON.stringify(body),
9030
+ signal: this._controller.signal,
9031
+ // @ts-ignore
9032
+ dispatcher: this._dispatcher
9033
+ });
9034
+ this._requestLogger.debug("after PATCH %s with url %s as source", patchUrl, this._location);
9035
+ return response;
9036
+ }
9037
+ };
9038
+ var LoadLiveIngressJob = class extends AbstractJob {
9039
+ constructor(ingressId, getSession, client, requestLogger) {
9040
+ super(getSession, client, requestLogger);
9041
+ this._ingressId = ingressId;
9042
+ }
9043
+ get [Symbol.toStringTag]() {
9044
+ return "loadLiveIngressJob";
9045
+ }
9046
+ async startJob() {
8999
9047
  const body = {
9000
- "sourceType": "URL",
9001
- "url": this._location
9048
+ "sourceType": "LIVE_INGRESS",
9049
+ "liveIngressId": this._ingressId
9002
9050
  };
9003
- const postUrl = `${this._baseUrl}/pipelines/${this._pipelineId}/source?mode=queue&processing=sync`;
9004
- this._requestLogger.debug("before PATCH %s with url %s as source", postUrl, this._location);
9005
- const response = await this._client.fetch(postUrl, {
9051
+ const session = await this._getSession();
9052
+ const headers = {
9053
+ "Authorization": `Bearer ${session.accessToken}`,
9054
+ "Accept": "application/jsonl",
9055
+ "Content-Type": "application/json"
9056
+ };
9057
+ const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
9058
+ this._requestLogger.debug("before PATCH %s with url %s as source", patchUrl, this._ingressId);
9059
+ const response = await this._client.fetch(patchUrl, {
9006
9060
  headers,
9007
9061
  method: "PATCH",
9008
9062
  body: JSON.stringify(body),
@@ -9010,7 +9064,7 @@ var LoadFromJob = class extends AbstractJob {
9010
9064
  // @ts-ignore
9011
9065
  dispatcher: this._dispatcher
9012
9066
  });
9013
- this._requestLogger.debug("after PATCH %s with url %s as source", postUrl, this._location);
9067
+ this._requestLogger.debug("after PATCH %s with url %s as source", patchUrl, this._ingressId);
9014
9068
  return response;
9015
9069
  }
9016
9070
  };
@@ -9045,7 +9099,7 @@ if ("document" in globalThis && "implementation" in globalThis.document) {
9045
9099
  }
9046
9100
  }
9047
9101
  createHttpClient = async () => {
9048
- const undici = await import("undici");
9102
+ const undici = __require("undici");
9049
9103
  const agent = new undici.Agent({
9050
9104
  keepAliveTimeout: 1e4,
9051
9105
  connections: 5
@@ -9182,6 +9236,374 @@ var Semaphore = class {
9182
9236
  }
9183
9237
  };
9184
9238
 
9239
+ // node_modules/uuid/dist/esm-node/rng.js
9240
+ import crypto from "crypto";
9241
+ var rnds8Pool = new Uint8Array(256);
9242
+ var poolPtr = rnds8Pool.length;
9243
+ function rng() {
9244
+ if (poolPtr > rnds8Pool.length - 16) {
9245
+ crypto.randomFillSync(rnds8Pool);
9246
+ poolPtr = 0;
9247
+ }
9248
+ return rnds8Pool.slice(poolPtr, poolPtr += 16);
9249
+ }
9250
+
9251
+ // node_modules/uuid/dist/esm-node/stringify.js
9252
+ var byteToHex = [];
9253
+ for (let i = 0; i < 256; ++i) {
9254
+ byteToHex.push((i + 256).toString(16).slice(1));
9255
+ }
9256
+ function unsafeStringify(arr, offset = 0) {
9257
+ return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
9258
+ }
9259
+
9260
+ // node_modules/uuid/dist/esm-node/native.js
9261
+ import crypto2 from "crypto";
9262
+ var native_default = {
9263
+ randomUUID: crypto2.randomUUID
9264
+ };
9265
+
9266
+ // node_modules/uuid/dist/esm-node/v4.js
9267
+ function v4(options, buf, offset) {
9268
+ if (native_default.randomUUID && !buf && !options) {
9269
+ return native_default.randomUUID();
9270
+ }
9271
+ options = options || {};
9272
+ const rnds = options.random || (options.rng || rng)();
9273
+ rnds[6] = rnds[6] & 15 | 64;
9274
+ rnds[8] = rnds[8] & 63 | 128;
9275
+ if (buf) {
9276
+ offset = offset || 0;
9277
+ for (let i = 0; i < 16; ++i) {
9278
+ buf[offset + i] = rnds[i];
9279
+ }
9280
+ return buf;
9281
+ }
9282
+ return unsafeStringify(rnds);
9283
+ }
9284
+ var v4_default = v4;
9285
+
9286
+ // src/web_rtc_base.ts
9287
+ var WebRtcBase = class {
9288
+ constructor(getSession, client, requestLogger) {
9289
+ this._pc = null;
9290
+ this._getSession = getSession;
9291
+ this._client = client;
9292
+ this._requestLogger = requestLogger;
9293
+ this._eTag = "";
9294
+ this._queuedCandidates = [];
9295
+ this._offerData = null;
9296
+ }
9297
+ static linkToIceServers(links) {
9298
+ const servers = links !== null ? links.split(", ").map((link) => {
9299
+ const m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i);
9300
+ if (!m) {
9301
+ return null;
9302
+ }
9303
+ const iceServer = {
9304
+ urls: [m[1]],
9305
+ username: Whip.unquoteCredential(m[3]),
9306
+ credential: Whip.unquoteCredential(m[4])
9307
+ // credentialType: m[3]? "password" : undefined
9308
+ };
9309
+ return iceServer;
9310
+ }) : [];
9311
+ return servers.filter(function(el) {
9312
+ return el != null;
9313
+ });
9314
+ }
9315
+ static editAnswer(answer, videoCodec, audioCodec, videoBitrate, audioBitrate, audioVoice) {
9316
+ const sections = answer.split("m=");
9317
+ for (let i = 0; i < sections.length; i++) {
9318
+ const section = sections[i];
9319
+ if (section.startsWith("video")) {
9320
+ sections[i] = Whip.setVideoBitrate(Whip.setCodec(section, videoCodec), videoBitrate);
9321
+ } else if (section.startsWith("audio")) {
9322
+ sections[i] = Whip.setAudioBitrate(Whip.setCodec(section, audioCodec), audioBitrate, audioVoice);
9323
+ }
9324
+ }
9325
+ return sections.join("m=");
9326
+ }
9327
+ static setCodec(section, codec) {
9328
+ const lines = section.split("\r\n");
9329
+ const lines2 = [];
9330
+ const payloadFormats = [];
9331
+ for (const line of lines) {
9332
+ if (!line.startsWith("a=rtpmap:")) {
9333
+ lines2.push(line);
9334
+ } else {
9335
+ if (codec && line.toLowerCase().includes(codec)) {
9336
+ payloadFormats.push(line.slice("a=rtpmap:".length).split(" ")[0]);
9337
+ lines2.push(line);
9338
+ }
9339
+ }
9340
+ }
9341
+ const lines3 = [];
9342
+ for (const line of lines2) {
9343
+ if (line.startsWith("a=fmtp:")) {
9344
+ if (payloadFormats.includes(line.slice("a=fmtp:".length).split(" ")[0])) {
9345
+ lines3.push(line);
9346
+ }
9347
+ } else if (line.startsWith("a=rtcp-fb:")) {
9348
+ if (payloadFormats.includes(line.slice("a=rtcp-fb:".length).split(" ")[0])) {
9349
+ lines3.push(line);
9350
+ }
9351
+ } else {
9352
+ lines3.push(line);
9353
+ }
9354
+ }
9355
+ return lines3.join("\r\n");
9356
+ }
9357
+ static setVideoBitrate(section, bitrate) {
9358
+ let lines = section.split("\r\n");
9359
+ for (let i = 0; i < lines.length; i++) {
9360
+ if (lines[i].startsWith("c=")) {
9361
+ lines = [...lines.slice(0, i + 1), "b=TIAS:" + (bitrate * 1024).toString(), ...lines.slice(i + 1)];
9362
+ break;
9363
+ }
9364
+ }
9365
+ return lines.join("\r\n");
9366
+ }
9367
+ static setAudioBitrate(section, bitrate, voice) {
9368
+ let opusPayloadFormat = "";
9369
+ let lines = section.split("\r\n");
9370
+ for (let i = 0; i < lines.length; i++) {
9371
+ if (lines[i].startsWith("a=rtpmap:") && lines[i].toLowerCase().includes("opus/")) {
9372
+ opusPayloadFormat = lines[i].slice("a=rtpmap:".length).split(" ")[0];
9373
+ break;
9374
+ }
9375
+ }
9376
+ if (opusPayloadFormat === "") {
9377
+ return section;
9378
+ }
9379
+ for (let i = 0; i < lines.length; i++) {
9380
+ if (lines[i].startsWith("a=fmtp:" + opusPayloadFormat + " ")) {
9381
+ if (voice) {
9382
+ lines[i] = "a=fmtp:" + opusPayloadFormat + " minptime=10;useinbandfec=1;maxaveragebitrate=" + ((bitrate ?? 0) * 1024).toString();
9383
+ } else {
9384
+ lines[i] = "a=fmtp:" + opusPayloadFormat + " maxplaybackrate=48000;stereo=1;sprop-stereo=1;maxaveragebitrate" + ((bitrate ?? 0) * 1024).toString();
9385
+ }
9386
+ }
9387
+ }
9388
+ return lines.join("\r\n");
9389
+ }
9390
+ static parseOffer(offer) {
9391
+ let medias = [];
9392
+ let iceUfrag = "";
9393
+ let icePwd = "";
9394
+ for (const line of offer.split("\r\n")) {
9395
+ if (line.startsWith("m=")) {
9396
+ medias.push(line.slice("m=".length));
9397
+ } else if (iceUfrag === "" && line.startsWith("a=ice-ufrag:")) {
9398
+ iceUfrag = line.slice("a=ice-ufrag:".length);
9399
+ } else if (icePwd === "" && line.startsWith("a=ice-pwd:")) {
9400
+ icePwd = line.slice("a=ice-pwd:".length);
9401
+ }
9402
+ }
9403
+ return {
9404
+ iceUfrag,
9405
+ icePwd,
9406
+ medias
9407
+ };
9408
+ }
9409
+ static generateSdpFragment(offerData, candidates) {
9410
+ const candidatesByMedia = /* @__PURE__ */ new Map();
9411
+ for (const candidate of candidates) {
9412
+ if (candidate.sdpMLineIndex !== null) {
9413
+ const mid2 = candidate.sdpMLineIndex;
9414
+ let matched = candidatesByMedia.get(mid2);
9415
+ if (matched === void 0) {
9416
+ matched = [];
9417
+ candidatesByMedia.set(mid2, matched);
9418
+ }
9419
+ matched.push(candidate);
9420
+ }
9421
+ }
9422
+ let frag = "a=ice-ufrag:" + offerData.iceUfrag + "\r\na=ice-pwd:" + offerData.icePwd + "\r\n";
9423
+ let mid = 0;
9424
+ for (const media of offerData.medias) {
9425
+ let matched = candidatesByMedia.get(mid);
9426
+ if (matched !== void 0) {
9427
+ frag += "m=" + media + "\r\na=mid:" + mid + "\r\n";
9428
+ for (const candidate of matched) {
9429
+ frag += "a=" + candidate.candidate + "\r\n";
9430
+ }
9431
+ }
9432
+ mid++;
9433
+ }
9434
+ return frag;
9435
+ }
9436
+ static unquoteCredential(v) {
9437
+ if (!v) {
9438
+ return "";
9439
+ }
9440
+ return JSON.parse(`"${v}"`);
9441
+ }
9442
+ };
9443
+
9444
+ // src/whip.ts
9445
+ var Whip = class _Whip extends WebRtcBase {
9446
+ constructor(stream, getSession, client, requestLogger) {
9447
+ super(getSession, client, requestLogger);
9448
+ this._ingressId = v4_default().toString();
9449
+ this._stream = stream;
9450
+ }
9451
+ ingressId() {
9452
+ if (!this._ingressId) {
9453
+ throw new Error("not initialized");
9454
+ }
9455
+ return this._ingressId;
9456
+ }
9457
+ async start() {
9458
+ const session = await this._getSession();
9459
+ const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
9460
+ this._requestLogger.debug("before GET: %s", ingressUrl);
9461
+ const headers = {
9462
+ "Authorization": `Bearer ${session.accessToken}`
9463
+ };
9464
+ const response = await this._client.fetch(ingressUrl, {
9465
+ headers,
9466
+ method: "GET"
9467
+ });
9468
+ if (response.status >= 300) {
9469
+ return Promise.reject(`unknown status code for GET '${ingressUrl}': ${response.status} (${response.statusText})`);
9470
+ }
9471
+ return this.onIceServers(response);
9472
+ }
9473
+ async onIceServers(response) {
9474
+ if (!this._stream) {
9475
+ throw new Error("onIceServers no stream");
9476
+ }
9477
+ const stream = this._stream;
9478
+ const pc = new RTCPeerConnection({
9479
+ iceServers: _Whip.linkToIceServers(response.headers.get("Link"))
9480
+ });
9481
+ this._pc = pc;
9482
+ pc.onicecandidate = (evt) => this.onLocalCandidate(evt);
9483
+ return new Promise(async (resolve2, reject) => {
9484
+ pc.oniceconnectionstatechange = () => {
9485
+ switch (pc.iceConnectionState) {
9486
+ case "failed":
9487
+ case "disconnected":
9488
+ reject(`peer connection: ${pc.iceConnectionState}`);
9489
+ break;
9490
+ case "connected":
9491
+ resolve2(this);
9492
+ break;
9493
+ }
9494
+ };
9495
+ stream.getTracks().forEach((track) => {
9496
+ this._requestLogger.debug("onIceServers our stream has track: %s", track);
9497
+ pc.addTrack(track, stream);
9498
+ });
9499
+ stream.addEventListener("addtrack", (trackEvent) => {
9500
+ this._requestLogger.debug("onIceServers got lazy track: ", trackEvent.track);
9501
+ pc.addTrack(trackEvent.track, stream);
9502
+ });
9503
+ await this.onLocalOffer(await pc.createOffer());
9504
+ });
9505
+ }
9506
+ async onLocalCandidate(evt) {
9507
+ if (evt.candidate !== null) {
9508
+ if (this._eTag === "") {
9509
+ this._queuedCandidates.push(evt.candidate);
9510
+ } else {
9511
+ await this.sendLocalCandidates([evt.candidate]);
9512
+ }
9513
+ }
9514
+ return this;
9515
+ }
9516
+ async onLocalOffer(offer) {
9517
+ if (!this._pc) {
9518
+ throw new Error("onLocalOffer no peer connection");
9519
+ }
9520
+ if (!offer.sdp) {
9521
+ throw new Error("onLocalOffer no sdp");
9522
+ }
9523
+ this._offerData = _Whip.parseOffer(offer.sdp);
9524
+ await this._pc.setLocalDescription(offer);
9525
+ const session = await this._getSession();
9526
+ const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
9527
+ this._requestLogger.debug("before GET: %s", ingressUrl);
9528
+ const headers = {
9529
+ "Authorization": `Bearer ${session.accessToken}`,
9530
+ "Content-Type": "application/sdp"
9531
+ };
9532
+ const response = await this._client.fetch(ingressUrl, {
9533
+ headers,
9534
+ method: "POST",
9535
+ body: offer.sdp
9536
+ });
9537
+ if (response.status != 201) {
9538
+ return Promise.reject(`unknown status code for POST '${ingressUrl}': ${response.status} (${response.statusText})`);
9539
+ }
9540
+ this._eTag = response.headers.get("ETag") ?? "";
9541
+ return this.onRemoteAnswer(new RTCSessionDescription({
9542
+ type: "answer",
9543
+ sdp: await response.text()
9544
+ }));
9545
+ }
9546
+ async onRemoteAnswer(answer) {
9547
+ if (!this._pc) {
9548
+ throw new Error("onLocalOffer no peer connection");
9549
+ }
9550
+ answer = new RTCSessionDescription({
9551
+ type: "answer",
9552
+ sdp: _Whip.editAnswer(
9553
+ answer.sdp,
9554
+ "h264/90000",
9555
+ void 0,
9556
+ 5e3,
9557
+ void 0,
9558
+ true
9559
+ )
9560
+ });
9561
+ await this._pc.setRemoteDescription(new RTCSessionDescription(answer));
9562
+ if (this._queuedCandidates.length !== 0) {
9563
+ await this.sendLocalCandidates(this._queuedCandidates);
9564
+ this._queuedCandidates = [];
9565
+ }
9566
+ return this;
9567
+ }
9568
+ async sendLocalCandidates(candidates) {
9569
+ if (!this._offerData) {
9570
+ throw new Error("sendLocalCandidates no offerData");
9571
+ }
9572
+ const session = await this._getSession();
9573
+ const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
9574
+ this._requestLogger.debug("before PATCH: %s", ingressUrl);
9575
+ const headers = {
9576
+ "Authorization": `Bearer ${session.accessToken}`,
9577
+ "Content-Type": "application/trickle-ice-sdpfrag",
9578
+ "If-Match": this._eTag
9579
+ };
9580
+ const response = await this._client.fetch(ingressUrl, {
9581
+ headers,
9582
+ method: "PATCH",
9583
+ body: _Whip.generateSdpFragment(this._offerData, candidates)
9584
+ });
9585
+ if (response.status != 204) {
9586
+ return Promise.reject(`unknown status code for PATCH '${ingressUrl}': ${response.status} (${response.statusText})`);
9587
+ }
9588
+ return this;
9589
+ }
9590
+ async close() {
9591
+ const pc = this._pc;
9592
+ const stream = this._stream;
9593
+ this._stream = null;
9594
+ this._pc = null;
9595
+ if (stream) {
9596
+ const tracks = stream.getTracks();
9597
+ tracks.forEach((track) => {
9598
+ track.stop();
9599
+ });
9600
+ }
9601
+ if (pc) {
9602
+ return pc.close();
9603
+ }
9604
+ }
9605
+ };
9606
+
9185
9607
  // src/shims/local_file.ts
9186
9608
  var resolve;
9187
9609
  if ("document" in globalThis && "implementation" in globalThis.document) {
@@ -9203,8 +9625,8 @@ if ("document" in globalThis && "implementation" in globalThis.document) {
9203
9625
  if (params.file) {
9204
9626
  return params;
9205
9627
  }
9206
- const mime = await Promise.resolve().then(() => __toESM(require_mime_types()));
9207
- const fs = await import("fs");
9628
+ const mime = require_mime_types();
9629
+ const fs = __require("fs");
9208
9630
  let mimeType;
9209
9631
  let stream;
9210
9632
  if (params.filePath) {
@@ -9235,7 +9657,11 @@ var Endpoint = class {
9235
9657
  this._token = null;
9236
9658
  this._expire_token_time = null;
9237
9659
  this._client = null;
9238
- this._limit = null;
9660
+ this._state = "Idle" /* Idle */;
9661
+ this._stateChangeHandler = null;
9662
+ this._ingressEventHandler = null;
9663
+ this._ingressEventWs = null;
9664
+ this._limit = new Semaphore(this._options.jobQueueLength ?? 1024);
9239
9665
  let rootLogger;
9240
9666
  if (options.logger) {
9241
9667
  rootLogger = options.logger;
@@ -9245,57 +9671,143 @@ var Endpoint = class {
9245
9671
  this._logger = rootLogger.child({ module: "eyepop" });
9246
9672
  this._requestLogger = this._logger.child({ module: "requests" });
9247
9673
  }
9674
+ onStateChanged(handler) {
9675
+ this._stateChangeHandler = handler;
9676
+ return this;
9677
+ }
9678
+ async startIngressWs() {
9679
+ if (this._ingressEventWs || !this._baseUrl || !this._client) {
9680
+ return;
9681
+ }
9682
+ try {
9683
+ const getTokenUrl = `${this._baseUrl}/liveIngress/events/token`;
9684
+ const headers = {
9685
+ "Authorization": await this.authorizationHeader()
9686
+ };
9687
+ this._requestLogger.debug("before GET %s", getTokenUrl);
9688
+ let response = await this._client.fetch(getTokenUrl, { headers });
9689
+ if (response.status == 401) {
9690
+ this._requestLogger.debug("after GET %s: 401, about to retry with fresh access token", getTokenUrl);
9691
+ this._token = null;
9692
+ const headers2 = {
9693
+ "Authorization": await this.authorizationHeader()
9694
+ };
9695
+ this.updateState("FetchConfig" /* FetchConfig */);
9696
+ response = await this._client.fetch(getTokenUrl, { headers: headers2 });
9697
+ }
9698
+ if (response.status != 200) {
9699
+ const message = await response.text();
9700
+ return Promise.reject(`Unexpected status ${response.status}: ${message}`);
9701
+ }
9702
+ const wsAuthToken = await response.json();
9703
+ const wsUrl = this._baseUrl.startsWith("https://") ? `${this._baseUrl.replace("https://", "wss://")}/liveIngress/events/${wsAuthToken.token}` : `${this._baseUrl.replace("http://", "ws://")}/liveIngress/events/${wsAuthToken.token}`;
9704
+ this._ingressEventWs = new WebSocket(wsUrl);
9705
+ this._ingressEventWs.addEventListener("message", (event) => {
9706
+ const ingressEvent = JSON.parse(event.data);
9707
+ if (this._ingressEventHandler) {
9708
+ this._ingressEventHandler(ingressEvent);
9709
+ }
9710
+ });
9711
+ } finally {
9712
+ this.updateState();
9713
+ }
9714
+ }
9715
+ onIngressEvent(handler) {
9716
+ this._ingressEventHandler = handler;
9717
+ this.startIngressWs().then(() => {
9718
+ }).catch((reason) => {
9719
+ this._logger.warn("unexpected error starting the ingress event handler: %s", reason);
9720
+ });
9721
+ return this;
9722
+ }
9723
+ state() {
9724
+ return this._state;
9725
+ }
9726
+ pendingJobs() {
9727
+ return (this._options.jobQueueLength ?? 1024) - this._limit.getPermits();
9728
+ }
9248
9729
  popName() {
9249
9730
  return this._popName;
9250
9731
  }
9732
+ popId() {
9733
+ return this._options.popId || null;
9734
+ }
9251
9735
  async session() {
9252
9736
  await this.currentAccessToken();
9253
9737
  if (this._token == null || this._expire_token_time == null) {
9254
9738
  return Promise.reject("endpoint not connected");
9255
9739
  }
9256
- const token = {
9740
+ if (this._baseUrl == null || this._pipelineId == null) {
9741
+ await this.reconnect();
9742
+ if (this._baseUrl == null || this._pipelineId == null) {
9743
+ return Promise.reject("endpoint not connected");
9744
+ }
9745
+ }
9746
+ return {
9747
+ eyepopUrl: this._options.eyepopUrl,
9748
+ popId: this._options.popId,
9257
9749
  accessToken: this._token,
9258
- validUntil: new Date(this._expire_token_time * 1e3)
9750
+ validUntil: this._expire_token_time * 1e3,
9751
+ baseUrl: this._baseUrl,
9752
+ pipelineId: this._pipelineId
9259
9753
  };
9260
- return token;
9754
+ }
9755
+ async liveIngress(stream) {
9756
+ if (!this._baseUrl || !this._client) {
9757
+ return Promise.reject("endpoint not connected, use connect() before ingress()");
9758
+ }
9759
+ const job = new Whip(stream, async () => {
9760
+ return this.session();
9761
+ }, this._client, this._requestLogger);
9762
+ return job.start();
9261
9763
  }
9262
9764
  async upload(params) {
9263
9765
  if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
9264
- return Promise.reject("endpoint not connected, use open() before upload()");
9766
+ return Promise.reject("endpoint not connected, use connect() before upload()");
9265
9767
  }
9266
9768
  params = await resolve(params);
9267
9769
  if (!params.mimeType) {
9268
9770
  return Promise.reject("upload for streams requires a mimeType");
9269
9771
  }
9270
9772
  await this._limit.acquire();
9271
- const job = new UploadJob(
9272
- params.file,
9273
- params.mimeType,
9274
- this._baseUrl,
9275
- this._pipelineId,
9276
- await this.authorizationHeader(),
9277
- this._client,
9278
- this._requestLogger
9279
- );
9773
+ this.updateState();
9774
+ const job = new UploadJob(params.file, params.mimeType, async () => {
9775
+ return this.session();
9776
+ }, this._client, this._requestLogger);
9280
9777
  return job.start(() => {
9281
- this._limit?.release();
9778
+ this.jobDone(job);
9779
+ }, (statusCode) => {
9780
+ this.jobStatus(job, statusCode);
9282
9781
  });
9283
9782
  }
9284
9783
  async loadFrom(location) {
9285
9784
  if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
9286
- throw new Error("endpoint not connected, use open() before loadFrom()");
9785
+ throw new Error("endpoint not connected, use connect() before loadFrom()");
9287
9786
  }
9288
9787
  await this._limit.acquire();
9289
- const job = new LoadFromJob(
9290
- location,
9291
- this._baseUrl,
9292
- this._pipelineId,
9293
- await this.authorizationHeader(),
9294
- this._client,
9295
- this._requestLogger
9296
- );
9788
+ this.updateState();
9789
+ const job = new LoadFromJob(location, async () => {
9790
+ return this.session();
9791
+ }, this._client, this._requestLogger);
9297
9792
  return job.start(() => {
9298
- this._limit?.release();
9793
+ this.jobDone(job);
9794
+ }, (statusCode) => {
9795
+ this.jobStatus(job, statusCode);
9796
+ });
9797
+ }
9798
+ async loadLiveIngress(ingressId) {
9799
+ if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
9800
+ throw new Error("endpoint not connected, use connect() before loadLiveIngress()");
9801
+ }
9802
+ await this._limit.acquire();
9803
+ this.updateState();
9804
+ const job = new LoadLiveIngressJob(ingressId, async () => {
9805
+ return this.session();
9806
+ }, this._client, this._requestLogger);
9807
+ return job.start(() => {
9808
+ this.jobDone(job);
9809
+ }, (statusCode) => {
9810
+ this.jobStatus(job, statusCode);
9299
9811
  });
9300
9812
  }
9301
9813
  // noinspection TypeScriptValidateTypes
@@ -9310,20 +9822,72 @@ var Endpoint = class {
9310
9822
  if (!this._options.popId) {
9311
9823
  return Promise.reject("option popId or environment variable EYEPOP_POP_ID is required");
9312
9824
  }
9313
- if (this._options.session) {
9314
- this._token = this._options.session.accessToken;
9315
- this._expire_token_time = this._options.session.validUntil.getTime() / 1e3;
9825
+ if (this._options.auth && this._options.auth.session) {
9826
+ this._token = this._options.auth.session.accessToken;
9827
+ this._expire_token_time = this._options.auth.session.validUntil / 1e3;
9316
9828
  } else {
9317
- if (!this._options.secretKey) {
9829
+ if (!this._options.auth || !this._options.auth.secretKey) {
9318
9830
  return Promise.reject("option secretKey or environment variable EYEPOP_SECRET_KEY is required");
9319
9831
  }
9320
9832
  }
9321
9833
  this._client = await createHttpClient();
9322
- this._limit = new Semaphore(this._options.jobQueueLength);
9323
- const config_url = `${this.eyepopUrl()}/pops/${this._options.popId}/config?auto_start=${this._options.autoStart}`;
9834
+ let result = await this.reconnect();
9835
+ if (this._baseUrl && this._options.stopJobs) {
9836
+ const stop_url = `${this._baseUrl}/pipelines/${this._pipelineId}/source?mode=preempt&processing=sync`;
9837
+ const body = { "sourceType": "NONE" };
9838
+ const headers = {
9839
+ "Authorization": await this.authorizationHeader(),
9840
+ "Content-Type": "application/json"
9841
+ };
9842
+ this._requestLogger.debug("before PATCH %s", stop_url);
9843
+ let response = await this._client.fetch(stop_url, { method: "PATCH", headers, body: JSON.stringify(body) });
9844
+ if (response.status >= 300) {
9845
+ const message = await response.text();
9846
+ return Promise.reject(`Unexpected status ${response.status}: ${message}`);
9847
+ }
9848
+ this._requestLogger.debug("after PATCH %s", stop_url);
9849
+ }
9850
+ if (!this._ingressEventWs && this._ingressEventHandler) {
9851
+ await this.startIngressWs();
9852
+ }
9853
+ return result;
9854
+ }
9855
+ jobDone(job) {
9856
+ this._limit?.release();
9857
+ this.updateState();
9858
+ }
9859
+ updateState(newState = void 0) {
9860
+ const fromState = this._state;
9861
+ if (newState == void 0) {
9862
+ if (this._limit.getPermits() == this._options.jobQueueLength) {
9863
+ newState = "Idle" /* Idle */;
9864
+ } else {
9865
+ newState = "Busy" /* Busy */;
9866
+ }
9867
+ }
9868
+ this._state = newState;
9869
+ if (this._stateChangeHandler) {
9870
+ this._stateChangeHandler(fromState, this._state);
9871
+ }
9872
+ }
9873
+ jobStatus(job, statusCode) {
9874
+ if (statusCode == 404) {
9875
+ this._pipelineId = null;
9876
+ this._baseUrl = null;
9877
+ } else if (statusCode == 401) {
9878
+ this._token = null;
9879
+ this._expire_token_time = null;
9880
+ }
9881
+ }
9882
+ async reconnect() {
9883
+ if (!this._client) {
9884
+ return Promise.reject("endpoint not initialized");
9885
+ }
9886
+ const config_url = `${this.eyepopUrl()}/pops/${this._options.popId}/config?auto_start=false`;
9324
9887
  const headers = {
9325
9888
  "Authorization": await this.authorizationHeader()
9326
9889
  };
9890
+ this.updateState("FetchConfig" /* FetchConfig */);
9327
9891
  this._requestLogger.debug("before GET %s", config_url);
9328
9892
  let response = await this._client.fetch(config_url, { headers });
9329
9893
  if (response.status == 401) {
@@ -9332,41 +9896,47 @@ var Endpoint = class {
9332
9896
  const headers2 = {
9333
9897
  "Authorization": await this.authorizationHeader()
9334
9898
  };
9899
+ this.updateState("FetchConfig" /* FetchConfig */);
9335
9900
  response = await this._client.fetch(config_url, {
9336
9901
  headers: headers2
9337
9902
  // @ts-ignore
9338
9903
  });
9339
9904
  }
9340
9905
  if (response.status != 200) {
9906
+ this.updateState("Error" /* Error */);
9341
9907
  const message = await response.text();
9342
9908
  return Promise.reject(`Unexpected status ${response.status}: ${message}`);
9343
- }
9344
- const data = await response.json();
9345
- const config = data;
9346
- this._baseUrl = config.base_url;
9347
- this._pipelineId = config.pipeline_id;
9348
- this._popName = config.name;
9349
- this._requestLogger.debug("after GET %s: %s / %s", config_url, this._baseUrl, this._pipelineId);
9350
- if (!this._pipelineId || !this._baseUrl) {
9351
- return Promise.reject(`Pop not started`);
9352
- }
9353
- this._baseUrl = this._baseUrl.replace(/\/+$/, "");
9354
- if (this._options.stopJobs) {
9355
- const stop_url = `${this._baseUrl}/pipelines/${this._pipelineId}/source?mode=preempt&processing=sync`;
9356
- const body = { "sourceType": "NONE" };
9357
- const headers2 = {
9358
- "Authorization": await this.authorizationHeader(),
9359
- "Content-Type": "application/json"
9360
- };
9361
- this._requestLogger.debug("before PATCH %s", stop_url);
9362
- let response2 = await this._client.fetch(stop_url, { method: "PATCH", headers: headers2, body: JSON.stringify(body) });
9363
- if (response2.status >= 300) {
9364
- const message = await response2.text();
9365
- return Promise.reject(`Unexpected status ${response2.status}: ${message}`);
9909
+ } else {
9910
+ let config = await response.json();
9911
+ if (!config.base_url && this._options.autoStart) {
9912
+ const auto_start_config_url = `${this.eyepopUrl()}/pops/${this._options.popId}/config?auto_start=true`;
9913
+ this._requestLogger.debug("pop was not running, trying to autostart with: %s", auto_start_config_url);
9914
+ const headers2 = {
9915
+ "Authorization": await this.authorizationHeader()
9916
+ };
9917
+ this.updateState("StartingPop" /* StartingPop */);
9918
+ response = await this._client.fetch(auto_start_config_url, {
9919
+ headers: headers2
9920
+ // @ts-ignore
9921
+ });
9922
+ if (response.status != 200) {
9923
+ this.updateState("Error" /* Error */);
9924
+ const message = await response.text();
9925
+ return Promise.reject(`Unexpected status ${response.status}: ${message}`);
9926
+ }
9927
+ config = await response.json();
9366
9928
  }
9367
- this._requestLogger.debug("after PATCH %s", stop_url);
9929
+ this._baseUrl = config.base_url;
9930
+ this._pipelineId = config.pipeline_id;
9931
+ this._popName = config.name;
9932
+ this._requestLogger.debug("after GET %s: %s / %s", config_url, this._baseUrl, this._pipelineId);
9933
+ if (!this._pipelineId || !this._baseUrl) {
9934
+ return Promise.reject(`Pop not started`);
9935
+ }
9936
+ this._baseUrl = this._baseUrl.replace(/\/+$/, "");
9937
+ this.updateState();
9938
+ return Promise.resolve(this);
9368
9939
  }
9369
- return this;
9370
9940
  }
9371
9941
  async disconnect(wait = true) {
9372
9942
  if (wait && this._limit) {
@@ -9374,13 +9944,13 @@ var Endpoint = class {
9374
9944
  await this._limit.acquire();
9375
9945
  }
9376
9946
  }
9947
+ this._limit = new Semaphore(this._options.jobQueueLength ?? 1024);
9377
9948
  if (this._client) {
9378
9949
  await this._client.close();
9379
9950
  this._client = null;
9380
9951
  }
9381
9952
  this._baseUrl = null;
9382
9953
  this._pipelineId = null;
9383
- this._limit = null;
9384
9954
  }
9385
9955
  async authorizationHeader() {
9386
9956
  return `Bearer ${await this.currentAccessToken()}`;
@@ -9388,12 +9958,13 @@ var Endpoint = class {
9388
9958
  async currentAccessToken() {
9389
9959
  const now = Date.now() / 1e3;
9390
9960
  if (!this._token || this._expire_token_time < now) {
9961
+ this.updateState("Authenticating" /* Authenticating */);
9391
9962
  if (!this._client) {
9392
9963
  return Promise.reject("endpoint not connected");
9393
- } else if (!this._options.secretKey) {
9964
+ } else if (!this._options.auth || !this._options.auth.secretKey) {
9394
9965
  return Promise.reject("temporary access token expired");
9395
9966
  }
9396
- const body = { "secret_key": this._options.secretKey };
9967
+ const body = { "secret_key": this._options.auth.secretKey };
9397
9968
  const headers = { "Content-Type": "application/json" };
9398
9969
  const post_url = `${this.eyepopUrl()}/authentication/token`;
9399
9970
  this._requestLogger.debug("before POST %s", post_url);
@@ -9411,6 +9982,7 @@ var Endpoint = class {
9411
9982
  const token = data;
9412
9983
  this._token = token.access_token;
9413
9984
  this._expire_token_time = now + token.expires_in - 60;
9985
+ this.updateState();
9414
9986
  }
9415
9987
  this._logger.debug("using access token, valid for at least %d seconds", this._expire_token_time - now);
9416
9988
  return this._token;
@@ -9433,17 +10005,19 @@ var _EyePopPlot = class _EyePopPlot {
9433
10005
  }
9434
10006
  prediction(p) {
9435
10007
  if (p && p.objects) {
10008
+ const x_scale = this._context.canvas.width / p.source_width;
10009
+ const y_scale = this._context.canvas.height / p.source_height;
9436
10010
  for (let i = 0; i < p.objects.length; i++) {
9437
- this.object(p.objects[i]);
10011
+ this.object(p.objects[i], x_scale, y_scale);
9438
10012
  }
9439
10013
  }
9440
10014
  }
9441
- object(obj) {
10015
+ object(obj, x_scale = 1, y_scale = 1) {
9442
10016
  const context = this._context;
9443
- const x = obj.x;
9444
- const y = obj.y;
9445
- const w = obj.width;
9446
- const h = obj.height;
10017
+ const x = obj.x * x_scale;
10018
+ const y = obj.y * y_scale;
10019
+ const w = obj.width * x_scale;
10020
+ const h = obj.height * y_scale;
9447
10021
  context.beginPath();
9448
10022
  context.rect(obj.x, obj.y, obj.width, obj.height);
9449
10023
  context.lineWidth = 1;
@@ -9535,11 +10109,50 @@ _EyePopPlot.colors = {
9535
10109
  };
9536
10110
  var EyePopPlot = _EyePopPlot;
9537
10111
 
10112
+ // src/shims/browser_session.ts
10113
+ var authenticateBrowserSession;
10114
+ if ("document" in globalThis && "implementation" in globalThis.document) {
10115
+ authenticateBrowserSession = (oauthUrl, eyepopUrl, popId) => {
10116
+ const queryString = window.location.search;
10117
+ const urlParams = new URLSearchParams(queryString);
10118
+ let token = urlParams.get("pop_token");
10119
+ if (token) {
10120
+ urlParams.delete("pop_token");
10121
+ const url = `${window.location.pathname}?${urlParams}`;
10122
+ window.history.replaceState({}, document.title, url);
10123
+ return {
10124
+ eyepopUrl,
10125
+ popId,
10126
+ accessToken: token,
10127
+ validUntil: Date.now() + 60 * 60 * 1e3
10128
+ };
10129
+ } else {
10130
+ const url = `${oauthUrl}?url=${encodeURIComponent(window.location.href)}`;
10131
+ window.location.replace(url);
10132
+ return {
10133
+ eyepopUrl,
10134
+ popId,
10135
+ accessToken: "in-progress",
10136
+ validUntil: 0
10137
+ };
10138
+ }
10139
+ };
10140
+ } else {
10141
+ authenticateBrowserSession = (oauthUrl, eyepopUrl, popId) => {
10142
+ return null;
10143
+ };
10144
+ }
10145
+
9538
10146
  // src/index.ts
10147
+ var readEnv = (env) => {
10148
+ if (typeof process !== "undefined") {
10149
+ return process.env?.[env] ?? void 0;
10150
+ }
10151
+ return void 0;
10152
+ };
9539
10153
  var EyePopSdk = class {
9540
10154
  static endpoint({
9541
- secretKey = readEnv("EYEPOP_SECRET_KEY"),
9542
- session = void 0,
10155
+ auth = this.defaultAuth,
9543
10156
  popId = readEnv("EYEPOP_POP_ID"),
9544
10157
  eyepopUrl = readEnv("EYEPOP_URL"),
9545
10158
  autoStart = true,
@@ -9548,11 +10161,17 @@ var EyePopSdk = class {
9548
10161
  logger,
9549
10162
  ...opts
9550
10163
  } = {}) {
10164
+ if (auth.oAuth && popId) {
10165
+ let oauthUrl = "https://dashboard.eyepop.ai/sdkauth";
10166
+ if (typeof auth.oAuth == "string") {
10167
+ oauthUrl = auth.oAuth;
10168
+ }
10169
+ auth.session = authenticateBrowserSession(oauthUrl, eyepopUrl ?? "https://api.eyepop.ai", popId) ?? void 0;
10170
+ }
9551
10171
  const options = {
9552
- secretKey,
9553
- session,
9554
- popId,
9555
- eyepopUrl: eyepopUrl ?? "https://api.eyepop.ai",
10172
+ auth,
10173
+ popId: auth.session ? auth.session.popId : popId,
10174
+ eyepopUrl: auth.session ? auth.session.eyepopUrl : eyepopUrl ?? "https://api.eyepop.ai",
9556
10175
  autoStart,
9557
10176
  stopJobs,
9558
10177
  jobQueueLength,
@@ -9565,14 +10184,14 @@ var EyePopSdk = class {
9565
10184
  return new EyePopPlot(context);
9566
10185
  }
9567
10186
  };
9568
- var readEnv = (env) => {
9569
- if (typeof process !== "undefined") {
9570
- return process.env?.[env] ?? void 0;
9571
- }
9572
- return void 0;
10187
+ EyePopSdk.defaultAuth = {
10188
+ secretKey: readEnv("EYEPOP_SECRET_KEY")
9573
10189
  };
10190
+ var src_default = EyePopSdk;
9574
10191
  export {
9575
- EyePopSdk
10192
+ EndpointState,
10193
+ EyePopSdk,
10194
+ src_default as default
9576
10195
  };
9577
10196
  /*! Bundled license information:
9578
10197