@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/README.md +49 -8
- package/dist/eyepop.min.js +2 -0
- package/dist/eyepop.min.js.LICENSE.txt +36 -0
- package/dist/index.d.mts +59 -11
- package/dist/index.d.ts +59 -11
- package/dist/index.js +755 -114
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +754 -135
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -3
package/dist/index.js
CHANGED
|
@@ -8657,10 +8657,23 @@ var require_mime_types = __commonJS({
|
|
|
8657
8657
|
// src/index.ts
|
|
8658
8658
|
var src_exports = {};
|
|
8659
8659
|
__export(src_exports, {
|
|
8660
|
-
|
|
8660
|
+
EndpointState: () => EndpointState,
|
|
8661
|
+
EyePopSdk: () => EyePopSdk,
|
|
8662
|
+
default: () => src_default
|
|
8661
8663
|
});
|
|
8662
8664
|
module.exports = __toCommonJS(src_exports);
|
|
8663
8665
|
|
|
8666
|
+
// src/types.ts
|
|
8667
|
+
var EndpointState = /* @__PURE__ */ ((EndpointState2) => {
|
|
8668
|
+
EndpointState2["Idle"] = "Idle";
|
|
8669
|
+
EndpointState2["Busy"] = "Busy";
|
|
8670
|
+
EndpointState2["Authenticating"] = "Authenticating";
|
|
8671
|
+
EndpointState2["FetchConfig"] = "FetchConfig";
|
|
8672
|
+
EndpointState2["StartingPop"] = "StartingPop";
|
|
8673
|
+
EndpointState2["Error"] = "Error";
|
|
8674
|
+
return EndpointState2;
|
|
8675
|
+
})(EndpointState || {});
|
|
8676
|
+
|
|
8664
8677
|
// src/streaming.ts
|
|
8665
8678
|
var Stream = class _Stream {
|
|
8666
8679
|
constructor(iterator, controller) {
|
|
@@ -8913,16 +8926,13 @@ function readableStreamAsyncIterable(stream) {
|
|
|
8913
8926
|
}
|
|
8914
8927
|
|
|
8915
8928
|
// src/jobs.ts
|
|
8916
|
-
var
|
|
8917
|
-
constructor(
|
|
8929
|
+
var AbstractJob = class {
|
|
8930
|
+
constructor(getSession, client, requestLogger) {
|
|
8918
8931
|
this._responseStream = null;
|
|
8919
8932
|
this._controller = new AbortController();
|
|
8920
|
-
this.
|
|
8921
|
-
this._pipelineId = pipelineId;
|
|
8922
|
-
this._authorizationHeader = authorizationHeader;
|
|
8933
|
+
this._getSession = getSession;
|
|
8923
8934
|
this._client = client;
|
|
8924
8935
|
this._requestLogger = requestLogger;
|
|
8925
|
-
this.i = _AbstractJob.n++;
|
|
8926
8936
|
}
|
|
8927
8937
|
[Symbol.asyncIterator]() {
|
|
8928
8938
|
if (!this._responseStream) {
|
|
@@ -8933,22 +8943,55 @@ var _AbstractJob = class _AbstractJob {
|
|
|
8933
8943
|
async startJob() {
|
|
8934
8944
|
return Promise.reject("abstract class");
|
|
8935
8945
|
}
|
|
8936
|
-
start(done) {
|
|
8937
|
-
this._responseStream = new Promise((resolve2, reject) => {
|
|
8938
|
-
|
|
8939
|
-
|
|
8940
|
-
|
|
8941
|
-
|
|
8942
|
-
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
+
start(done, status) {
|
|
8947
|
+
this._responseStream = new Promise(async (resolve2, reject) => {
|
|
8948
|
+
try {
|
|
8949
|
+
let retries = 1;
|
|
8950
|
+
while (true) {
|
|
8951
|
+
try {
|
|
8952
|
+
const response = await this.startJob();
|
|
8953
|
+
if (response.status == 401) {
|
|
8954
|
+
status(response.status);
|
|
8955
|
+
if (retries--) {
|
|
8956
|
+
this._requestLogger.info("received 401 response, attempt to reauthorize once");
|
|
8957
|
+
} else {
|
|
8958
|
+
reject(`response ${response.status}: ${response.statusText}`);
|
|
8959
|
+
break;
|
|
8960
|
+
}
|
|
8961
|
+
} else if (response.status == 404) {
|
|
8962
|
+
status(response.status);
|
|
8963
|
+
if (retries--) {
|
|
8964
|
+
this._requestLogger.info("received 404 response, attempt to restart pop");
|
|
8965
|
+
} else {
|
|
8966
|
+
reject(`response ${response.status}: ${response.statusText}`);
|
|
8967
|
+
break;
|
|
8968
|
+
}
|
|
8969
|
+
} else if (response.status != 200) {
|
|
8970
|
+
reject(`upload error ${response.status}: ${await response.text()}`);
|
|
8971
|
+
break;
|
|
8972
|
+
} else if (!response.body) {
|
|
8973
|
+
reject(`response body is empty`);
|
|
8974
|
+
break;
|
|
8975
|
+
} else {
|
|
8976
|
+
resolve2(response.body);
|
|
8977
|
+
break;
|
|
8978
|
+
}
|
|
8979
|
+
} catch (error) {
|
|
8980
|
+
if (retries--) {
|
|
8981
|
+
this._requestLogger.info("unknown, attempt to restart pop (as if we received 404)", error);
|
|
8982
|
+
status(404);
|
|
8983
|
+
} else {
|
|
8984
|
+
status(500);
|
|
8985
|
+
reject(error);
|
|
8986
|
+
break;
|
|
8987
|
+
}
|
|
8988
|
+
}
|
|
8946
8989
|
}
|
|
8947
|
-
}
|
|
8990
|
+
} catch (reason) {
|
|
8948
8991
|
reject(reason);
|
|
8949
|
-
}
|
|
8992
|
+
} finally {
|
|
8950
8993
|
done();
|
|
8951
|
-
}
|
|
8994
|
+
}
|
|
8952
8995
|
});
|
|
8953
8996
|
return this;
|
|
8954
8997
|
}
|
|
@@ -8956,24 +8999,24 @@ var _AbstractJob = class _AbstractJob {
|
|
|
8956
8999
|
this._controller.abort("cancelled");
|
|
8957
9000
|
}
|
|
8958
9001
|
};
|
|
8959
|
-
|
|
8960
|
-
var AbstractJob = _AbstractJob;
|
|
9002
|
+
AbstractJob.n = 0;
|
|
8961
9003
|
var UploadJob = class extends AbstractJob {
|
|
8962
9004
|
get [Symbol.toStringTag]() {
|
|
8963
9005
|
return "uploadJob";
|
|
8964
9006
|
}
|
|
8965
|
-
constructor(stream, mimeType,
|
|
8966
|
-
super(
|
|
9007
|
+
constructor(stream, mimeType, getSession, client, requestLogger) {
|
|
9008
|
+
super(getSession, client, requestLogger);
|
|
8967
9009
|
this._uploadStream = stream;
|
|
8968
9010
|
this._mimeType = mimeType;
|
|
8969
9011
|
}
|
|
8970
9012
|
async startJob() {
|
|
9013
|
+
const session = await this._getSession();
|
|
8971
9014
|
const headers = {
|
|
8972
|
-
"Authorization":
|
|
9015
|
+
"Authorization": `Bearer ${session.accessToken}`,
|
|
8973
9016
|
"Accept": "application/jsonl",
|
|
8974
9017
|
"Content-Type": this._mimeType
|
|
8975
9018
|
};
|
|
8976
|
-
const postUrl = `${
|
|
9019
|
+
const postUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
8977
9020
|
this._requestLogger.debug("before POST %s with stream as body");
|
|
8978
9021
|
const response = await this._client.fetch(postUrl, {
|
|
8979
9022
|
headers,
|
|
@@ -8989,26 +9032,60 @@ var UploadJob = class extends AbstractJob {
|
|
|
8989
9032
|
}
|
|
8990
9033
|
};
|
|
8991
9034
|
var LoadFromJob = class extends AbstractJob {
|
|
8992
|
-
constructor(location,
|
|
8993
|
-
super(
|
|
9035
|
+
constructor(location, getSession, client, requestLogger) {
|
|
9036
|
+
super(getSession, client, requestLogger);
|
|
8994
9037
|
this._location = location;
|
|
8995
9038
|
}
|
|
8996
9039
|
get [Symbol.toStringTag]() {
|
|
8997
9040
|
return "loadFromJob";
|
|
8998
9041
|
}
|
|
8999
9042
|
async startJob() {
|
|
9043
|
+
const body = {
|
|
9044
|
+
"sourceType": "URL",
|
|
9045
|
+
"url": this._location
|
|
9046
|
+
};
|
|
9047
|
+
const session = await this._getSession();
|
|
9000
9048
|
const headers = {
|
|
9001
|
-
"Authorization":
|
|
9049
|
+
"Authorization": `Bearer ${session.accessToken}`,
|
|
9002
9050
|
"Accept": "application/jsonl",
|
|
9003
9051
|
"Content-Type": "application/json"
|
|
9004
9052
|
};
|
|
9053
|
+
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
9054
|
+
this._requestLogger.debug("before PATCH %s with url %s as source", patchUrl, this._location);
|
|
9055
|
+
const response = await this._client.fetch(patchUrl, {
|
|
9056
|
+
headers,
|
|
9057
|
+
method: "PATCH",
|
|
9058
|
+
body: JSON.stringify(body),
|
|
9059
|
+
signal: this._controller.signal,
|
|
9060
|
+
// @ts-ignore
|
|
9061
|
+
dispatcher: this._dispatcher
|
|
9062
|
+
});
|
|
9063
|
+
this._requestLogger.debug("after PATCH %s with url %s as source", patchUrl, this._location);
|
|
9064
|
+
return response;
|
|
9065
|
+
}
|
|
9066
|
+
};
|
|
9067
|
+
var LoadLiveIngressJob = class extends AbstractJob {
|
|
9068
|
+
constructor(ingressId, getSession, client, requestLogger) {
|
|
9069
|
+
super(getSession, client, requestLogger);
|
|
9070
|
+
this._ingressId = ingressId;
|
|
9071
|
+
}
|
|
9072
|
+
get [Symbol.toStringTag]() {
|
|
9073
|
+
return "loadLiveIngressJob";
|
|
9074
|
+
}
|
|
9075
|
+
async startJob() {
|
|
9005
9076
|
const body = {
|
|
9006
|
-
"sourceType": "
|
|
9007
|
-
"
|
|
9077
|
+
"sourceType": "LIVE_INGRESS",
|
|
9078
|
+
"liveIngressId": this._ingressId
|
|
9008
9079
|
};
|
|
9009
|
-
const
|
|
9010
|
-
|
|
9011
|
-
|
|
9080
|
+
const session = await this._getSession();
|
|
9081
|
+
const headers = {
|
|
9082
|
+
"Authorization": `Bearer ${session.accessToken}`,
|
|
9083
|
+
"Accept": "application/jsonl",
|
|
9084
|
+
"Content-Type": "application/json"
|
|
9085
|
+
};
|
|
9086
|
+
const patchUrl = `${session.baseUrl.replace(/\/+$/, "")}/pipelines/${session.pipelineId}/source?mode=queue&processing=sync`;
|
|
9087
|
+
this._requestLogger.debug("before PATCH %s with url %s as source", patchUrl, this._ingressId);
|
|
9088
|
+
const response = await this._client.fetch(patchUrl, {
|
|
9012
9089
|
headers,
|
|
9013
9090
|
method: "PATCH",
|
|
9014
9091
|
body: JSON.stringify(body),
|
|
@@ -9016,7 +9093,7 @@ var LoadFromJob = class extends AbstractJob {
|
|
|
9016
9093
|
// @ts-ignore
|
|
9017
9094
|
dispatcher: this._dispatcher
|
|
9018
9095
|
});
|
|
9019
|
-
this._requestLogger.debug("after PATCH %s with url %s as source",
|
|
9096
|
+
this._requestLogger.debug("after PATCH %s with url %s as source", patchUrl, this._ingressId);
|
|
9020
9097
|
return response;
|
|
9021
9098
|
}
|
|
9022
9099
|
};
|
|
@@ -9051,7 +9128,7 @@ if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
|
9051
9128
|
}
|
|
9052
9129
|
}
|
|
9053
9130
|
createHttpClient = async () => {
|
|
9054
|
-
const undici =
|
|
9131
|
+
const undici = require("undici");
|
|
9055
9132
|
const agent = new undici.Agent({
|
|
9056
9133
|
keepAliveTimeout: 1e4,
|
|
9057
9134
|
connections: 5
|
|
@@ -9188,6 +9265,374 @@ var Semaphore = class {
|
|
|
9188
9265
|
}
|
|
9189
9266
|
};
|
|
9190
9267
|
|
|
9268
|
+
// node_modules/uuid/dist/esm-node/rng.js
|
|
9269
|
+
var import_crypto = __toESM(require("crypto"));
|
|
9270
|
+
var rnds8Pool = new Uint8Array(256);
|
|
9271
|
+
var poolPtr = rnds8Pool.length;
|
|
9272
|
+
function rng() {
|
|
9273
|
+
if (poolPtr > rnds8Pool.length - 16) {
|
|
9274
|
+
import_crypto.default.randomFillSync(rnds8Pool);
|
|
9275
|
+
poolPtr = 0;
|
|
9276
|
+
}
|
|
9277
|
+
return rnds8Pool.slice(poolPtr, poolPtr += 16);
|
|
9278
|
+
}
|
|
9279
|
+
|
|
9280
|
+
// node_modules/uuid/dist/esm-node/stringify.js
|
|
9281
|
+
var byteToHex = [];
|
|
9282
|
+
for (let i = 0; i < 256; ++i) {
|
|
9283
|
+
byteToHex.push((i + 256).toString(16).slice(1));
|
|
9284
|
+
}
|
|
9285
|
+
function unsafeStringify(arr, offset = 0) {
|
|
9286
|
+
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]];
|
|
9287
|
+
}
|
|
9288
|
+
|
|
9289
|
+
// node_modules/uuid/dist/esm-node/native.js
|
|
9290
|
+
var import_crypto2 = __toESM(require("crypto"));
|
|
9291
|
+
var native_default = {
|
|
9292
|
+
randomUUID: import_crypto2.default.randomUUID
|
|
9293
|
+
};
|
|
9294
|
+
|
|
9295
|
+
// node_modules/uuid/dist/esm-node/v4.js
|
|
9296
|
+
function v4(options, buf, offset) {
|
|
9297
|
+
if (native_default.randomUUID && !buf && !options) {
|
|
9298
|
+
return native_default.randomUUID();
|
|
9299
|
+
}
|
|
9300
|
+
options = options || {};
|
|
9301
|
+
const rnds = options.random || (options.rng || rng)();
|
|
9302
|
+
rnds[6] = rnds[6] & 15 | 64;
|
|
9303
|
+
rnds[8] = rnds[8] & 63 | 128;
|
|
9304
|
+
if (buf) {
|
|
9305
|
+
offset = offset || 0;
|
|
9306
|
+
for (let i = 0; i < 16; ++i) {
|
|
9307
|
+
buf[offset + i] = rnds[i];
|
|
9308
|
+
}
|
|
9309
|
+
return buf;
|
|
9310
|
+
}
|
|
9311
|
+
return unsafeStringify(rnds);
|
|
9312
|
+
}
|
|
9313
|
+
var v4_default = v4;
|
|
9314
|
+
|
|
9315
|
+
// src/web_rtc_base.ts
|
|
9316
|
+
var WebRtcBase = class {
|
|
9317
|
+
constructor(getSession, client, requestLogger) {
|
|
9318
|
+
this._pc = null;
|
|
9319
|
+
this._getSession = getSession;
|
|
9320
|
+
this._client = client;
|
|
9321
|
+
this._requestLogger = requestLogger;
|
|
9322
|
+
this._eTag = "";
|
|
9323
|
+
this._queuedCandidates = [];
|
|
9324
|
+
this._offerData = null;
|
|
9325
|
+
}
|
|
9326
|
+
static linkToIceServers(links) {
|
|
9327
|
+
const servers = links !== null ? links.split(", ").map((link) => {
|
|
9328
|
+
const m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i);
|
|
9329
|
+
if (!m) {
|
|
9330
|
+
return null;
|
|
9331
|
+
}
|
|
9332
|
+
const iceServer = {
|
|
9333
|
+
urls: [m[1]],
|
|
9334
|
+
username: Whip.unquoteCredential(m[3]),
|
|
9335
|
+
credential: Whip.unquoteCredential(m[4])
|
|
9336
|
+
// credentialType: m[3]? "password" : undefined
|
|
9337
|
+
};
|
|
9338
|
+
return iceServer;
|
|
9339
|
+
}) : [];
|
|
9340
|
+
return servers.filter(function(el) {
|
|
9341
|
+
return el != null;
|
|
9342
|
+
});
|
|
9343
|
+
}
|
|
9344
|
+
static editAnswer(answer, videoCodec, audioCodec, videoBitrate, audioBitrate, audioVoice) {
|
|
9345
|
+
const sections = answer.split("m=");
|
|
9346
|
+
for (let i = 0; i < sections.length; i++) {
|
|
9347
|
+
const section = sections[i];
|
|
9348
|
+
if (section.startsWith("video")) {
|
|
9349
|
+
sections[i] = Whip.setVideoBitrate(Whip.setCodec(section, videoCodec), videoBitrate);
|
|
9350
|
+
} else if (section.startsWith("audio")) {
|
|
9351
|
+
sections[i] = Whip.setAudioBitrate(Whip.setCodec(section, audioCodec), audioBitrate, audioVoice);
|
|
9352
|
+
}
|
|
9353
|
+
}
|
|
9354
|
+
return sections.join("m=");
|
|
9355
|
+
}
|
|
9356
|
+
static setCodec(section, codec) {
|
|
9357
|
+
const lines = section.split("\r\n");
|
|
9358
|
+
const lines2 = [];
|
|
9359
|
+
const payloadFormats = [];
|
|
9360
|
+
for (const line of lines) {
|
|
9361
|
+
if (!line.startsWith("a=rtpmap:")) {
|
|
9362
|
+
lines2.push(line);
|
|
9363
|
+
} else {
|
|
9364
|
+
if (codec && line.toLowerCase().includes(codec)) {
|
|
9365
|
+
payloadFormats.push(line.slice("a=rtpmap:".length).split(" ")[0]);
|
|
9366
|
+
lines2.push(line);
|
|
9367
|
+
}
|
|
9368
|
+
}
|
|
9369
|
+
}
|
|
9370
|
+
const lines3 = [];
|
|
9371
|
+
for (const line of lines2) {
|
|
9372
|
+
if (line.startsWith("a=fmtp:")) {
|
|
9373
|
+
if (payloadFormats.includes(line.slice("a=fmtp:".length).split(" ")[0])) {
|
|
9374
|
+
lines3.push(line);
|
|
9375
|
+
}
|
|
9376
|
+
} else if (line.startsWith("a=rtcp-fb:")) {
|
|
9377
|
+
if (payloadFormats.includes(line.slice("a=rtcp-fb:".length).split(" ")[0])) {
|
|
9378
|
+
lines3.push(line);
|
|
9379
|
+
}
|
|
9380
|
+
} else {
|
|
9381
|
+
lines3.push(line);
|
|
9382
|
+
}
|
|
9383
|
+
}
|
|
9384
|
+
return lines3.join("\r\n");
|
|
9385
|
+
}
|
|
9386
|
+
static setVideoBitrate(section, bitrate) {
|
|
9387
|
+
let lines = section.split("\r\n");
|
|
9388
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9389
|
+
if (lines[i].startsWith("c=")) {
|
|
9390
|
+
lines = [...lines.slice(0, i + 1), "b=TIAS:" + (bitrate * 1024).toString(), ...lines.slice(i + 1)];
|
|
9391
|
+
break;
|
|
9392
|
+
}
|
|
9393
|
+
}
|
|
9394
|
+
return lines.join("\r\n");
|
|
9395
|
+
}
|
|
9396
|
+
static setAudioBitrate(section, bitrate, voice) {
|
|
9397
|
+
let opusPayloadFormat = "";
|
|
9398
|
+
let lines = section.split("\r\n");
|
|
9399
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9400
|
+
if (lines[i].startsWith("a=rtpmap:") && lines[i].toLowerCase().includes("opus/")) {
|
|
9401
|
+
opusPayloadFormat = lines[i].slice("a=rtpmap:".length).split(" ")[0];
|
|
9402
|
+
break;
|
|
9403
|
+
}
|
|
9404
|
+
}
|
|
9405
|
+
if (opusPayloadFormat === "") {
|
|
9406
|
+
return section;
|
|
9407
|
+
}
|
|
9408
|
+
for (let i = 0; i < lines.length; i++) {
|
|
9409
|
+
if (lines[i].startsWith("a=fmtp:" + opusPayloadFormat + " ")) {
|
|
9410
|
+
if (voice) {
|
|
9411
|
+
lines[i] = "a=fmtp:" + opusPayloadFormat + " minptime=10;useinbandfec=1;maxaveragebitrate=" + ((bitrate ?? 0) * 1024).toString();
|
|
9412
|
+
} else {
|
|
9413
|
+
lines[i] = "a=fmtp:" + opusPayloadFormat + " maxplaybackrate=48000;stereo=1;sprop-stereo=1;maxaveragebitrate" + ((bitrate ?? 0) * 1024).toString();
|
|
9414
|
+
}
|
|
9415
|
+
}
|
|
9416
|
+
}
|
|
9417
|
+
return lines.join("\r\n");
|
|
9418
|
+
}
|
|
9419
|
+
static parseOffer(offer) {
|
|
9420
|
+
let medias = [];
|
|
9421
|
+
let iceUfrag = "";
|
|
9422
|
+
let icePwd = "";
|
|
9423
|
+
for (const line of offer.split("\r\n")) {
|
|
9424
|
+
if (line.startsWith("m=")) {
|
|
9425
|
+
medias.push(line.slice("m=".length));
|
|
9426
|
+
} else if (iceUfrag === "" && line.startsWith("a=ice-ufrag:")) {
|
|
9427
|
+
iceUfrag = line.slice("a=ice-ufrag:".length);
|
|
9428
|
+
} else if (icePwd === "" && line.startsWith("a=ice-pwd:")) {
|
|
9429
|
+
icePwd = line.slice("a=ice-pwd:".length);
|
|
9430
|
+
}
|
|
9431
|
+
}
|
|
9432
|
+
return {
|
|
9433
|
+
iceUfrag,
|
|
9434
|
+
icePwd,
|
|
9435
|
+
medias
|
|
9436
|
+
};
|
|
9437
|
+
}
|
|
9438
|
+
static generateSdpFragment(offerData, candidates) {
|
|
9439
|
+
const candidatesByMedia = /* @__PURE__ */ new Map();
|
|
9440
|
+
for (const candidate of candidates) {
|
|
9441
|
+
if (candidate.sdpMLineIndex !== null) {
|
|
9442
|
+
const mid2 = candidate.sdpMLineIndex;
|
|
9443
|
+
let matched = candidatesByMedia.get(mid2);
|
|
9444
|
+
if (matched === void 0) {
|
|
9445
|
+
matched = [];
|
|
9446
|
+
candidatesByMedia.set(mid2, matched);
|
|
9447
|
+
}
|
|
9448
|
+
matched.push(candidate);
|
|
9449
|
+
}
|
|
9450
|
+
}
|
|
9451
|
+
let frag = "a=ice-ufrag:" + offerData.iceUfrag + "\r\na=ice-pwd:" + offerData.icePwd + "\r\n";
|
|
9452
|
+
let mid = 0;
|
|
9453
|
+
for (const media of offerData.medias) {
|
|
9454
|
+
let matched = candidatesByMedia.get(mid);
|
|
9455
|
+
if (matched !== void 0) {
|
|
9456
|
+
frag += "m=" + media + "\r\na=mid:" + mid + "\r\n";
|
|
9457
|
+
for (const candidate of matched) {
|
|
9458
|
+
frag += "a=" + candidate.candidate + "\r\n";
|
|
9459
|
+
}
|
|
9460
|
+
}
|
|
9461
|
+
mid++;
|
|
9462
|
+
}
|
|
9463
|
+
return frag;
|
|
9464
|
+
}
|
|
9465
|
+
static unquoteCredential(v) {
|
|
9466
|
+
if (!v) {
|
|
9467
|
+
return "";
|
|
9468
|
+
}
|
|
9469
|
+
return JSON.parse(`"${v}"`);
|
|
9470
|
+
}
|
|
9471
|
+
};
|
|
9472
|
+
|
|
9473
|
+
// src/whip.ts
|
|
9474
|
+
var Whip = class _Whip extends WebRtcBase {
|
|
9475
|
+
constructor(stream, getSession, client, requestLogger) {
|
|
9476
|
+
super(getSession, client, requestLogger);
|
|
9477
|
+
this._ingressId = v4_default().toString();
|
|
9478
|
+
this._stream = stream;
|
|
9479
|
+
}
|
|
9480
|
+
ingressId() {
|
|
9481
|
+
if (!this._ingressId) {
|
|
9482
|
+
throw new Error("not initialized");
|
|
9483
|
+
}
|
|
9484
|
+
return this._ingressId;
|
|
9485
|
+
}
|
|
9486
|
+
async start() {
|
|
9487
|
+
const session = await this._getSession();
|
|
9488
|
+
const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
|
|
9489
|
+
this._requestLogger.debug("before GET: %s", ingressUrl);
|
|
9490
|
+
const headers = {
|
|
9491
|
+
"Authorization": `Bearer ${session.accessToken}`
|
|
9492
|
+
};
|
|
9493
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9494
|
+
headers,
|
|
9495
|
+
method: "GET"
|
|
9496
|
+
});
|
|
9497
|
+
if (response.status >= 300) {
|
|
9498
|
+
return Promise.reject(`unknown status code for GET '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9499
|
+
}
|
|
9500
|
+
return this.onIceServers(response);
|
|
9501
|
+
}
|
|
9502
|
+
async onIceServers(response) {
|
|
9503
|
+
if (!this._stream) {
|
|
9504
|
+
throw new Error("onIceServers no stream");
|
|
9505
|
+
}
|
|
9506
|
+
const stream = this._stream;
|
|
9507
|
+
const pc = new RTCPeerConnection({
|
|
9508
|
+
iceServers: _Whip.linkToIceServers(response.headers.get("Link"))
|
|
9509
|
+
});
|
|
9510
|
+
this._pc = pc;
|
|
9511
|
+
pc.onicecandidate = (evt) => this.onLocalCandidate(evt);
|
|
9512
|
+
return new Promise(async (resolve2, reject) => {
|
|
9513
|
+
pc.oniceconnectionstatechange = () => {
|
|
9514
|
+
switch (pc.iceConnectionState) {
|
|
9515
|
+
case "failed":
|
|
9516
|
+
case "disconnected":
|
|
9517
|
+
reject(`peer connection: ${pc.iceConnectionState}`);
|
|
9518
|
+
break;
|
|
9519
|
+
case "connected":
|
|
9520
|
+
resolve2(this);
|
|
9521
|
+
break;
|
|
9522
|
+
}
|
|
9523
|
+
};
|
|
9524
|
+
stream.getTracks().forEach((track) => {
|
|
9525
|
+
this._requestLogger.debug("onIceServers our stream has track: %s", track);
|
|
9526
|
+
pc.addTrack(track, stream);
|
|
9527
|
+
});
|
|
9528
|
+
stream.addEventListener("addtrack", (trackEvent) => {
|
|
9529
|
+
this._requestLogger.debug("onIceServers got lazy track: ", trackEvent.track);
|
|
9530
|
+
pc.addTrack(trackEvent.track, stream);
|
|
9531
|
+
});
|
|
9532
|
+
await this.onLocalOffer(await pc.createOffer());
|
|
9533
|
+
});
|
|
9534
|
+
}
|
|
9535
|
+
async onLocalCandidate(evt) {
|
|
9536
|
+
if (evt.candidate !== null) {
|
|
9537
|
+
if (this._eTag === "") {
|
|
9538
|
+
this._queuedCandidates.push(evt.candidate);
|
|
9539
|
+
} else {
|
|
9540
|
+
await this.sendLocalCandidates([evt.candidate]);
|
|
9541
|
+
}
|
|
9542
|
+
}
|
|
9543
|
+
return this;
|
|
9544
|
+
}
|
|
9545
|
+
async onLocalOffer(offer) {
|
|
9546
|
+
if (!this._pc) {
|
|
9547
|
+
throw new Error("onLocalOffer no peer connection");
|
|
9548
|
+
}
|
|
9549
|
+
if (!offer.sdp) {
|
|
9550
|
+
throw new Error("onLocalOffer no sdp");
|
|
9551
|
+
}
|
|
9552
|
+
this._offerData = _Whip.parseOffer(offer.sdp);
|
|
9553
|
+
await this._pc.setLocalDescription(offer);
|
|
9554
|
+
const session = await this._getSession();
|
|
9555
|
+
const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
|
|
9556
|
+
this._requestLogger.debug("before GET: %s", ingressUrl);
|
|
9557
|
+
const headers = {
|
|
9558
|
+
"Authorization": `Bearer ${session.accessToken}`,
|
|
9559
|
+
"Content-Type": "application/sdp"
|
|
9560
|
+
};
|
|
9561
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9562
|
+
headers,
|
|
9563
|
+
method: "POST",
|
|
9564
|
+
body: offer.sdp
|
|
9565
|
+
});
|
|
9566
|
+
if (response.status != 201) {
|
|
9567
|
+
return Promise.reject(`unknown status code for POST '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9568
|
+
}
|
|
9569
|
+
this._eTag = response.headers.get("ETag") ?? "";
|
|
9570
|
+
return this.onRemoteAnswer(new RTCSessionDescription({
|
|
9571
|
+
type: "answer",
|
|
9572
|
+
sdp: await response.text()
|
|
9573
|
+
}));
|
|
9574
|
+
}
|
|
9575
|
+
async onRemoteAnswer(answer) {
|
|
9576
|
+
if (!this._pc) {
|
|
9577
|
+
throw new Error("onLocalOffer no peer connection");
|
|
9578
|
+
}
|
|
9579
|
+
answer = new RTCSessionDescription({
|
|
9580
|
+
type: "answer",
|
|
9581
|
+
sdp: _Whip.editAnswer(
|
|
9582
|
+
answer.sdp,
|
|
9583
|
+
"h264/90000",
|
|
9584
|
+
void 0,
|
|
9585
|
+
5e3,
|
|
9586
|
+
void 0,
|
|
9587
|
+
true
|
|
9588
|
+
)
|
|
9589
|
+
});
|
|
9590
|
+
await this._pc.setRemoteDescription(new RTCSessionDescription(answer));
|
|
9591
|
+
if (this._queuedCandidates.length !== 0) {
|
|
9592
|
+
await this.sendLocalCandidates(this._queuedCandidates);
|
|
9593
|
+
this._queuedCandidates = [];
|
|
9594
|
+
}
|
|
9595
|
+
return this;
|
|
9596
|
+
}
|
|
9597
|
+
async sendLocalCandidates(candidates) {
|
|
9598
|
+
if (!this._offerData) {
|
|
9599
|
+
throw new Error("sendLocalCandidates no offerData");
|
|
9600
|
+
}
|
|
9601
|
+
const session = await this._getSession();
|
|
9602
|
+
const ingressUrl = new URL("/liveIngress/whip/" + this._ingressId, session.baseUrl);
|
|
9603
|
+
this._requestLogger.debug("before PATCH: %s", ingressUrl);
|
|
9604
|
+
const headers = {
|
|
9605
|
+
"Authorization": `Bearer ${session.accessToken}`,
|
|
9606
|
+
"Content-Type": "application/trickle-ice-sdpfrag",
|
|
9607
|
+
"If-Match": this._eTag
|
|
9608
|
+
};
|
|
9609
|
+
const response = await this._client.fetch(ingressUrl, {
|
|
9610
|
+
headers,
|
|
9611
|
+
method: "PATCH",
|
|
9612
|
+
body: _Whip.generateSdpFragment(this._offerData, candidates)
|
|
9613
|
+
});
|
|
9614
|
+
if (response.status != 204) {
|
|
9615
|
+
return Promise.reject(`unknown status code for PATCH '${ingressUrl}': ${response.status} (${response.statusText})`);
|
|
9616
|
+
}
|
|
9617
|
+
return this;
|
|
9618
|
+
}
|
|
9619
|
+
async close() {
|
|
9620
|
+
const pc = this._pc;
|
|
9621
|
+
const stream = this._stream;
|
|
9622
|
+
this._stream = null;
|
|
9623
|
+
this._pc = null;
|
|
9624
|
+
if (stream) {
|
|
9625
|
+
const tracks = stream.getTracks();
|
|
9626
|
+
tracks.forEach((track) => {
|
|
9627
|
+
track.stop();
|
|
9628
|
+
});
|
|
9629
|
+
}
|
|
9630
|
+
if (pc) {
|
|
9631
|
+
return pc.close();
|
|
9632
|
+
}
|
|
9633
|
+
}
|
|
9634
|
+
};
|
|
9635
|
+
|
|
9191
9636
|
// src/shims/local_file.ts
|
|
9192
9637
|
var resolve;
|
|
9193
9638
|
if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
@@ -9209,8 +9654,8 @@ if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
|
9209
9654
|
if (params.file) {
|
|
9210
9655
|
return params;
|
|
9211
9656
|
}
|
|
9212
|
-
const mime =
|
|
9213
|
-
const fs =
|
|
9657
|
+
const mime = require_mime_types();
|
|
9658
|
+
const fs = require("fs");
|
|
9214
9659
|
let mimeType;
|
|
9215
9660
|
let stream;
|
|
9216
9661
|
if (params.filePath) {
|
|
@@ -9241,7 +9686,11 @@ var Endpoint = class {
|
|
|
9241
9686
|
this._token = null;
|
|
9242
9687
|
this._expire_token_time = null;
|
|
9243
9688
|
this._client = null;
|
|
9244
|
-
this.
|
|
9689
|
+
this._state = "Idle" /* Idle */;
|
|
9690
|
+
this._stateChangeHandler = null;
|
|
9691
|
+
this._ingressEventHandler = null;
|
|
9692
|
+
this._ingressEventWs = null;
|
|
9693
|
+
this._limit = new Semaphore(this._options.jobQueueLength ?? 1024);
|
|
9245
9694
|
let rootLogger;
|
|
9246
9695
|
if (options.logger) {
|
|
9247
9696
|
rootLogger = options.logger;
|
|
@@ -9251,57 +9700,143 @@ var Endpoint = class {
|
|
|
9251
9700
|
this._logger = rootLogger.child({ module: "eyepop" });
|
|
9252
9701
|
this._requestLogger = this._logger.child({ module: "requests" });
|
|
9253
9702
|
}
|
|
9703
|
+
onStateChanged(handler) {
|
|
9704
|
+
this._stateChangeHandler = handler;
|
|
9705
|
+
return this;
|
|
9706
|
+
}
|
|
9707
|
+
async startIngressWs() {
|
|
9708
|
+
if (this._ingressEventWs || !this._baseUrl || !this._client) {
|
|
9709
|
+
return;
|
|
9710
|
+
}
|
|
9711
|
+
try {
|
|
9712
|
+
const getTokenUrl = `${this._baseUrl}/liveIngress/events/token`;
|
|
9713
|
+
const headers = {
|
|
9714
|
+
"Authorization": await this.authorizationHeader()
|
|
9715
|
+
};
|
|
9716
|
+
this._requestLogger.debug("before GET %s", getTokenUrl);
|
|
9717
|
+
let response = await this._client.fetch(getTokenUrl, { headers });
|
|
9718
|
+
if (response.status == 401) {
|
|
9719
|
+
this._requestLogger.debug("after GET %s: 401, about to retry with fresh access token", getTokenUrl);
|
|
9720
|
+
this._token = null;
|
|
9721
|
+
const headers2 = {
|
|
9722
|
+
"Authorization": await this.authorizationHeader()
|
|
9723
|
+
};
|
|
9724
|
+
this.updateState("FetchConfig" /* FetchConfig */);
|
|
9725
|
+
response = await this._client.fetch(getTokenUrl, { headers: headers2 });
|
|
9726
|
+
}
|
|
9727
|
+
if (response.status != 200) {
|
|
9728
|
+
const message = await response.text();
|
|
9729
|
+
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
9730
|
+
}
|
|
9731
|
+
const wsAuthToken = await response.json();
|
|
9732
|
+
const wsUrl = this._baseUrl.startsWith("https://") ? `${this._baseUrl.replace("https://", "wss://")}/liveIngress/events/${wsAuthToken.token}` : `${this._baseUrl.replace("http://", "ws://")}/liveIngress/events/${wsAuthToken.token}`;
|
|
9733
|
+
this._ingressEventWs = new WebSocket(wsUrl);
|
|
9734
|
+
this._ingressEventWs.addEventListener("message", (event) => {
|
|
9735
|
+
const ingressEvent = JSON.parse(event.data);
|
|
9736
|
+
if (this._ingressEventHandler) {
|
|
9737
|
+
this._ingressEventHandler(ingressEvent);
|
|
9738
|
+
}
|
|
9739
|
+
});
|
|
9740
|
+
} finally {
|
|
9741
|
+
this.updateState();
|
|
9742
|
+
}
|
|
9743
|
+
}
|
|
9744
|
+
onIngressEvent(handler) {
|
|
9745
|
+
this._ingressEventHandler = handler;
|
|
9746
|
+
this.startIngressWs().then(() => {
|
|
9747
|
+
}).catch((reason) => {
|
|
9748
|
+
this._logger.warn("unexpected error starting the ingress event handler: %s", reason);
|
|
9749
|
+
});
|
|
9750
|
+
return this;
|
|
9751
|
+
}
|
|
9752
|
+
state() {
|
|
9753
|
+
return this._state;
|
|
9754
|
+
}
|
|
9755
|
+
pendingJobs() {
|
|
9756
|
+
return (this._options.jobQueueLength ?? 1024) - this._limit.getPermits();
|
|
9757
|
+
}
|
|
9254
9758
|
popName() {
|
|
9255
9759
|
return this._popName;
|
|
9256
9760
|
}
|
|
9761
|
+
popId() {
|
|
9762
|
+
return this._options.popId || null;
|
|
9763
|
+
}
|
|
9257
9764
|
async session() {
|
|
9258
9765
|
await this.currentAccessToken();
|
|
9259
9766
|
if (this._token == null || this._expire_token_time == null) {
|
|
9260
9767
|
return Promise.reject("endpoint not connected");
|
|
9261
9768
|
}
|
|
9262
|
-
|
|
9769
|
+
if (this._baseUrl == null || this._pipelineId == null) {
|
|
9770
|
+
await this.reconnect();
|
|
9771
|
+
if (this._baseUrl == null || this._pipelineId == null) {
|
|
9772
|
+
return Promise.reject("endpoint not connected");
|
|
9773
|
+
}
|
|
9774
|
+
}
|
|
9775
|
+
return {
|
|
9776
|
+
eyepopUrl: this._options.eyepopUrl,
|
|
9777
|
+
popId: this._options.popId,
|
|
9263
9778
|
accessToken: this._token,
|
|
9264
|
-
validUntil:
|
|
9779
|
+
validUntil: this._expire_token_time * 1e3,
|
|
9780
|
+
baseUrl: this._baseUrl,
|
|
9781
|
+
pipelineId: this._pipelineId
|
|
9265
9782
|
};
|
|
9266
|
-
|
|
9783
|
+
}
|
|
9784
|
+
async liveIngress(stream) {
|
|
9785
|
+
if (!this._baseUrl || !this._client) {
|
|
9786
|
+
return Promise.reject("endpoint not connected, use connect() before ingress()");
|
|
9787
|
+
}
|
|
9788
|
+
const job = new Whip(stream, async () => {
|
|
9789
|
+
return this.session();
|
|
9790
|
+
}, this._client, this._requestLogger);
|
|
9791
|
+
return job.start();
|
|
9267
9792
|
}
|
|
9268
9793
|
async upload(params) {
|
|
9269
9794
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
9270
|
-
return Promise.reject("endpoint not connected, use
|
|
9795
|
+
return Promise.reject("endpoint not connected, use connect() before upload()");
|
|
9271
9796
|
}
|
|
9272
9797
|
params = await resolve(params);
|
|
9273
9798
|
if (!params.mimeType) {
|
|
9274
9799
|
return Promise.reject("upload for streams requires a mimeType");
|
|
9275
9800
|
}
|
|
9276
9801
|
await this._limit.acquire();
|
|
9277
|
-
|
|
9278
|
-
|
|
9279
|
-
|
|
9280
|
-
|
|
9281
|
-
this._pipelineId,
|
|
9282
|
-
await this.authorizationHeader(),
|
|
9283
|
-
this._client,
|
|
9284
|
-
this._requestLogger
|
|
9285
|
-
);
|
|
9802
|
+
this.updateState();
|
|
9803
|
+
const job = new UploadJob(params.file, params.mimeType, async () => {
|
|
9804
|
+
return this.session();
|
|
9805
|
+
}, this._client, this._requestLogger);
|
|
9286
9806
|
return job.start(() => {
|
|
9287
|
-
this.
|
|
9807
|
+
this.jobDone(job);
|
|
9808
|
+
}, (statusCode) => {
|
|
9809
|
+
this.jobStatus(job, statusCode);
|
|
9288
9810
|
});
|
|
9289
9811
|
}
|
|
9290
9812
|
async loadFrom(location) {
|
|
9291
9813
|
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
9292
|
-
throw new Error("endpoint not connected, use
|
|
9814
|
+
throw new Error("endpoint not connected, use connect() before loadFrom()");
|
|
9293
9815
|
}
|
|
9294
9816
|
await this._limit.acquire();
|
|
9295
|
-
|
|
9296
|
-
|
|
9297
|
-
this.
|
|
9298
|
-
|
|
9299
|
-
await this.authorizationHeader(),
|
|
9300
|
-
this._client,
|
|
9301
|
-
this._requestLogger
|
|
9302
|
-
);
|
|
9817
|
+
this.updateState();
|
|
9818
|
+
const job = new LoadFromJob(location, async () => {
|
|
9819
|
+
return this.session();
|
|
9820
|
+
}, this._client, this._requestLogger);
|
|
9303
9821
|
return job.start(() => {
|
|
9304
|
-
this.
|
|
9822
|
+
this.jobDone(job);
|
|
9823
|
+
}, (statusCode) => {
|
|
9824
|
+
this.jobStatus(job, statusCode);
|
|
9825
|
+
});
|
|
9826
|
+
}
|
|
9827
|
+
async loadLiveIngress(ingressId) {
|
|
9828
|
+
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
9829
|
+
throw new Error("endpoint not connected, use connect() before loadLiveIngress()");
|
|
9830
|
+
}
|
|
9831
|
+
await this._limit.acquire();
|
|
9832
|
+
this.updateState();
|
|
9833
|
+
const job = new LoadLiveIngressJob(ingressId, async () => {
|
|
9834
|
+
return this.session();
|
|
9835
|
+
}, this._client, this._requestLogger);
|
|
9836
|
+
return job.start(() => {
|
|
9837
|
+
this.jobDone(job);
|
|
9838
|
+
}, (statusCode) => {
|
|
9839
|
+
this.jobStatus(job, statusCode);
|
|
9305
9840
|
});
|
|
9306
9841
|
}
|
|
9307
9842
|
// noinspection TypeScriptValidateTypes
|
|
@@ -9316,20 +9851,72 @@ var Endpoint = class {
|
|
|
9316
9851
|
if (!this._options.popId) {
|
|
9317
9852
|
return Promise.reject("option popId or environment variable EYEPOP_POP_ID is required");
|
|
9318
9853
|
}
|
|
9319
|
-
if (this._options.session) {
|
|
9320
|
-
this._token = this._options.session.accessToken;
|
|
9321
|
-
this._expire_token_time = this._options.session.validUntil
|
|
9854
|
+
if (this._options.auth && this._options.auth.session) {
|
|
9855
|
+
this._token = this._options.auth.session.accessToken;
|
|
9856
|
+
this._expire_token_time = this._options.auth.session.validUntil / 1e3;
|
|
9322
9857
|
} else {
|
|
9323
|
-
if (!this._options.secretKey) {
|
|
9858
|
+
if (!this._options.auth || !this._options.auth.secretKey) {
|
|
9324
9859
|
return Promise.reject("option secretKey or environment variable EYEPOP_SECRET_KEY is required");
|
|
9325
9860
|
}
|
|
9326
9861
|
}
|
|
9327
9862
|
this._client = await createHttpClient();
|
|
9328
|
-
|
|
9329
|
-
|
|
9863
|
+
let result = await this.reconnect();
|
|
9864
|
+
if (this._baseUrl && this._options.stopJobs) {
|
|
9865
|
+
const stop_url = `${this._baseUrl}/pipelines/${this._pipelineId}/source?mode=preempt&processing=sync`;
|
|
9866
|
+
const body = { "sourceType": "NONE" };
|
|
9867
|
+
const headers = {
|
|
9868
|
+
"Authorization": await this.authorizationHeader(),
|
|
9869
|
+
"Content-Type": "application/json"
|
|
9870
|
+
};
|
|
9871
|
+
this._requestLogger.debug("before PATCH %s", stop_url);
|
|
9872
|
+
let response = await this._client.fetch(stop_url, { method: "PATCH", headers, body: JSON.stringify(body) });
|
|
9873
|
+
if (response.status >= 300) {
|
|
9874
|
+
const message = await response.text();
|
|
9875
|
+
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
9876
|
+
}
|
|
9877
|
+
this._requestLogger.debug("after PATCH %s", stop_url);
|
|
9878
|
+
}
|
|
9879
|
+
if (!this._ingressEventWs && this._ingressEventHandler) {
|
|
9880
|
+
await this.startIngressWs();
|
|
9881
|
+
}
|
|
9882
|
+
return result;
|
|
9883
|
+
}
|
|
9884
|
+
jobDone(job) {
|
|
9885
|
+
this._limit?.release();
|
|
9886
|
+
this.updateState();
|
|
9887
|
+
}
|
|
9888
|
+
updateState(newState = void 0) {
|
|
9889
|
+
const fromState = this._state;
|
|
9890
|
+
if (newState == void 0) {
|
|
9891
|
+
if (this._limit.getPermits() == this._options.jobQueueLength) {
|
|
9892
|
+
newState = "Idle" /* Idle */;
|
|
9893
|
+
} else {
|
|
9894
|
+
newState = "Busy" /* Busy */;
|
|
9895
|
+
}
|
|
9896
|
+
}
|
|
9897
|
+
this._state = newState;
|
|
9898
|
+
if (this._stateChangeHandler) {
|
|
9899
|
+
this._stateChangeHandler(fromState, this._state);
|
|
9900
|
+
}
|
|
9901
|
+
}
|
|
9902
|
+
jobStatus(job, statusCode) {
|
|
9903
|
+
if (statusCode == 404) {
|
|
9904
|
+
this._pipelineId = null;
|
|
9905
|
+
this._baseUrl = null;
|
|
9906
|
+
} else if (statusCode == 401) {
|
|
9907
|
+
this._token = null;
|
|
9908
|
+
this._expire_token_time = null;
|
|
9909
|
+
}
|
|
9910
|
+
}
|
|
9911
|
+
async reconnect() {
|
|
9912
|
+
if (!this._client) {
|
|
9913
|
+
return Promise.reject("endpoint not initialized");
|
|
9914
|
+
}
|
|
9915
|
+
const config_url = `${this.eyepopUrl()}/pops/${this._options.popId}/config?auto_start=false`;
|
|
9330
9916
|
const headers = {
|
|
9331
9917
|
"Authorization": await this.authorizationHeader()
|
|
9332
9918
|
};
|
|
9919
|
+
this.updateState("FetchConfig" /* FetchConfig */);
|
|
9333
9920
|
this._requestLogger.debug("before GET %s", config_url);
|
|
9334
9921
|
let response = await this._client.fetch(config_url, { headers });
|
|
9335
9922
|
if (response.status == 401) {
|
|
@@ -9338,41 +9925,47 @@ var Endpoint = class {
|
|
|
9338
9925
|
const headers2 = {
|
|
9339
9926
|
"Authorization": await this.authorizationHeader()
|
|
9340
9927
|
};
|
|
9928
|
+
this.updateState("FetchConfig" /* FetchConfig */);
|
|
9341
9929
|
response = await this._client.fetch(config_url, {
|
|
9342
9930
|
headers: headers2
|
|
9343
9931
|
// @ts-ignore
|
|
9344
9932
|
});
|
|
9345
9933
|
}
|
|
9346
9934
|
if (response.status != 200) {
|
|
9935
|
+
this.updateState("Error" /* Error */);
|
|
9347
9936
|
const message = await response.text();
|
|
9348
9937
|
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
9349
|
-
}
|
|
9350
|
-
|
|
9351
|
-
|
|
9352
|
-
|
|
9353
|
-
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
|
|
9362
|
-
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
let response2 = await this._client.fetch(stop_url, { method: "PATCH", headers: headers2, body: JSON.stringify(body) });
|
|
9369
|
-
if (response2.status >= 300) {
|
|
9370
|
-
const message = await response2.text();
|
|
9371
|
-
return Promise.reject(`Unexpected status ${response2.status}: ${message}`);
|
|
9938
|
+
} else {
|
|
9939
|
+
let config = await response.json();
|
|
9940
|
+
if (!config.base_url && this._options.autoStart) {
|
|
9941
|
+
const auto_start_config_url = `${this.eyepopUrl()}/pops/${this._options.popId}/config?auto_start=true`;
|
|
9942
|
+
this._requestLogger.debug("pop was not running, trying to autostart with: %s", auto_start_config_url);
|
|
9943
|
+
const headers2 = {
|
|
9944
|
+
"Authorization": await this.authorizationHeader()
|
|
9945
|
+
};
|
|
9946
|
+
this.updateState("StartingPop" /* StartingPop */);
|
|
9947
|
+
response = await this._client.fetch(auto_start_config_url, {
|
|
9948
|
+
headers: headers2
|
|
9949
|
+
// @ts-ignore
|
|
9950
|
+
});
|
|
9951
|
+
if (response.status != 200) {
|
|
9952
|
+
this.updateState("Error" /* Error */);
|
|
9953
|
+
const message = await response.text();
|
|
9954
|
+
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
9955
|
+
}
|
|
9956
|
+
config = await response.json();
|
|
9372
9957
|
}
|
|
9373
|
-
this.
|
|
9958
|
+
this._baseUrl = config.base_url;
|
|
9959
|
+
this._pipelineId = config.pipeline_id;
|
|
9960
|
+
this._popName = config.name;
|
|
9961
|
+
this._requestLogger.debug("after GET %s: %s / %s", config_url, this._baseUrl, this._pipelineId);
|
|
9962
|
+
if (!this._pipelineId || !this._baseUrl) {
|
|
9963
|
+
return Promise.reject(`Pop not started`);
|
|
9964
|
+
}
|
|
9965
|
+
this._baseUrl = this._baseUrl.replace(/\/+$/, "");
|
|
9966
|
+
this.updateState();
|
|
9967
|
+
return Promise.resolve(this);
|
|
9374
9968
|
}
|
|
9375
|
-
return this;
|
|
9376
9969
|
}
|
|
9377
9970
|
async disconnect(wait = true) {
|
|
9378
9971
|
if (wait && this._limit) {
|
|
@@ -9380,13 +9973,13 @@ var Endpoint = class {
|
|
|
9380
9973
|
await this._limit.acquire();
|
|
9381
9974
|
}
|
|
9382
9975
|
}
|
|
9976
|
+
this._limit = new Semaphore(this._options.jobQueueLength ?? 1024);
|
|
9383
9977
|
if (this._client) {
|
|
9384
9978
|
await this._client.close();
|
|
9385
9979
|
this._client = null;
|
|
9386
9980
|
}
|
|
9387
9981
|
this._baseUrl = null;
|
|
9388
9982
|
this._pipelineId = null;
|
|
9389
|
-
this._limit = null;
|
|
9390
9983
|
}
|
|
9391
9984
|
async authorizationHeader() {
|
|
9392
9985
|
return `Bearer ${await this.currentAccessToken()}`;
|
|
@@ -9394,12 +9987,13 @@ var Endpoint = class {
|
|
|
9394
9987
|
async currentAccessToken() {
|
|
9395
9988
|
const now = Date.now() / 1e3;
|
|
9396
9989
|
if (!this._token || this._expire_token_time < now) {
|
|
9990
|
+
this.updateState("Authenticating" /* Authenticating */);
|
|
9397
9991
|
if (!this._client) {
|
|
9398
9992
|
return Promise.reject("endpoint not connected");
|
|
9399
|
-
} else if (!this._options.secretKey) {
|
|
9993
|
+
} else if (!this._options.auth || !this._options.auth.secretKey) {
|
|
9400
9994
|
return Promise.reject("temporary access token expired");
|
|
9401
9995
|
}
|
|
9402
|
-
const body = { "secret_key": this._options.secretKey };
|
|
9996
|
+
const body = { "secret_key": this._options.auth.secretKey };
|
|
9403
9997
|
const headers = { "Content-Type": "application/json" };
|
|
9404
9998
|
const post_url = `${this.eyepopUrl()}/authentication/token`;
|
|
9405
9999
|
this._requestLogger.debug("before POST %s", post_url);
|
|
@@ -9417,6 +10011,7 @@ var Endpoint = class {
|
|
|
9417
10011
|
const token = data;
|
|
9418
10012
|
this._token = token.access_token;
|
|
9419
10013
|
this._expire_token_time = now + token.expires_in - 60;
|
|
10014
|
+
this.updateState();
|
|
9420
10015
|
}
|
|
9421
10016
|
this._logger.debug("using access token, valid for at least %d seconds", this._expire_token_time - now);
|
|
9422
10017
|
return this._token;
|
|
@@ -9439,17 +10034,19 @@ var _EyePopPlot = class _EyePopPlot {
|
|
|
9439
10034
|
}
|
|
9440
10035
|
prediction(p) {
|
|
9441
10036
|
if (p && p.objects) {
|
|
10037
|
+
const x_scale = this._context.canvas.width / p.source_width;
|
|
10038
|
+
const y_scale = this._context.canvas.height / p.source_height;
|
|
9442
10039
|
for (let i = 0; i < p.objects.length; i++) {
|
|
9443
|
-
this.object(p.objects[i]);
|
|
10040
|
+
this.object(p.objects[i], x_scale, y_scale);
|
|
9444
10041
|
}
|
|
9445
10042
|
}
|
|
9446
10043
|
}
|
|
9447
|
-
object(obj) {
|
|
10044
|
+
object(obj, x_scale = 1, y_scale = 1) {
|
|
9448
10045
|
const context = this._context;
|
|
9449
|
-
const x = obj.x;
|
|
9450
|
-
const y = obj.y;
|
|
9451
|
-
const w = obj.width;
|
|
9452
|
-
const h = obj.height;
|
|
10046
|
+
const x = obj.x * x_scale;
|
|
10047
|
+
const y = obj.y * y_scale;
|
|
10048
|
+
const w = obj.width * x_scale;
|
|
10049
|
+
const h = obj.height * y_scale;
|
|
9453
10050
|
context.beginPath();
|
|
9454
10051
|
context.rect(obj.x, obj.y, obj.width, obj.height);
|
|
9455
10052
|
context.lineWidth = 1;
|
|
@@ -9541,11 +10138,50 @@ _EyePopPlot.colors = {
|
|
|
9541
10138
|
};
|
|
9542
10139
|
var EyePopPlot = _EyePopPlot;
|
|
9543
10140
|
|
|
10141
|
+
// src/shims/browser_session.ts
|
|
10142
|
+
var authenticateBrowserSession;
|
|
10143
|
+
if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
10144
|
+
authenticateBrowserSession = (oauthUrl, eyepopUrl, popId) => {
|
|
10145
|
+
const queryString = window.location.search;
|
|
10146
|
+
const urlParams = new URLSearchParams(queryString);
|
|
10147
|
+
let token = urlParams.get("pop_token");
|
|
10148
|
+
if (token) {
|
|
10149
|
+
urlParams.delete("pop_token");
|
|
10150
|
+
const url = `${window.location.pathname}?${urlParams}`;
|
|
10151
|
+
window.history.replaceState({}, document.title, url);
|
|
10152
|
+
return {
|
|
10153
|
+
eyepopUrl,
|
|
10154
|
+
popId,
|
|
10155
|
+
accessToken: token,
|
|
10156
|
+
validUntil: Date.now() + 60 * 60 * 1e3
|
|
10157
|
+
};
|
|
10158
|
+
} else {
|
|
10159
|
+
const url = `${oauthUrl}?url=${encodeURIComponent(window.location.href)}`;
|
|
10160
|
+
window.location.replace(url);
|
|
10161
|
+
return {
|
|
10162
|
+
eyepopUrl,
|
|
10163
|
+
popId,
|
|
10164
|
+
accessToken: "in-progress",
|
|
10165
|
+
validUntil: 0
|
|
10166
|
+
};
|
|
10167
|
+
}
|
|
10168
|
+
};
|
|
10169
|
+
} else {
|
|
10170
|
+
authenticateBrowserSession = (oauthUrl, eyepopUrl, popId) => {
|
|
10171
|
+
return null;
|
|
10172
|
+
};
|
|
10173
|
+
}
|
|
10174
|
+
|
|
9544
10175
|
// src/index.ts
|
|
10176
|
+
var readEnv = (env) => {
|
|
10177
|
+
if (typeof process !== "undefined") {
|
|
10178
|
+
return process.env?.[env] ?? void 0;
|
|
10179
|
+
}
|
|
10180
|
+
return void 0;
|
|
10181
|
+
};
|
|
9545
10182
|
var EyePopSdk = class {
|
|
9546
10183
|
static endpoint({
|
|
9547
|
-
|
|
9548
|
-
session = void 0,
|
|
10184
|
+
auth = this.defaultAuth,
|
|
9549
10185
|
popId = readEnv("EYEPOP_POP_ID"),
|
|
9550
10186
|
eyepopUrl = readEnv("EYEPOP_URL"),
|
|
9551
10187
|
autoStart = true,
|
|
@@ -9554,11 +10190,17 @@ var EyePopSdk = class {
|
|
|
9554
10190
|
logger,
|
|
9555
10191
|
...opts
|
|
9556
10192
|
} = {}) {
|
|
10193
|
+
if (auth.oAuth && popId) {
|
|
10194
|
+
let oauthUrl = "https://dashboard.eyepop.ai/sdkauth";
|
|
10195
|
+
if (typeof auth.oAuth == "string") {
|
|
10196
|
+
oauthUrl = auth.oAuth;
|
|
10197
|
+
}
|
|
10198
|
+
auth.session = authenticateBrowserSession(oauthUrl, eyepopUrl ?? "https://api.eyepop.ai", popId) ?? void 0;
|
|
10199
|
+
}
|
|
9557
10200
|
const options = {
|
|
9558
|
-
|
|
9559
|
-
session,
|
|
9560
|
-
|
|
9561
|
-
eyepopUrl: eyepopUrl ?? "https://api.eyepop.ai",
|
|
10201
|
+
auth,
|
|
10202
|
+
popId: auth.session ? auth.session.popId : popId,
|
|
10203
|
+
eyepopUrl: auth.session ? auth.session.eyepopUrl : eyepopUrl ?? "https://api.eyepop.ai",
|
|
9562
10204
|
autoStart,
|
|
9563
10205
|
stopJobs,
|
|
9564
10206
|
jobQueueLength,
|
|
@@ -9571,14 +10213,13 @@ var EyePopSdk = class {
|
|
|
9571
10213
|
return new EyePopPlot(context);
|
|
9572
10214
|
}
|
|
9573
10215
|
};
|
|
9574
|
-
|
|
9575
|
-
|
|
9576
|
-
return process.env?.[env] ?? void 0;
|
|
9577
|
-
}
|
|
9578
|
-
return void 0;
|
|
10216
|
+
EyePopSdk.defaultAuth = {
|
|
10217
|
+
secretKey: readEnv("EYEPOP_SECRET_KEY")
|
|
9579
10218
|
};
|
|
10219
|
+
var src_default = EyePopSdk;
|
|
9580
10220
|
// Annotate the CommonJS export names for ESM import in node:
|
|
9581
10221
|
0 && (module.exports = {
|
|
10222
|
+
EndpointState,
|
|
9582
10223
|
EyePopSdk
|
|
9583
10224
|
});
|
|
9584
10225
|
/*! Bundled license information:
|