@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.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
|
|
8911
|
-
constructor(
|
|
8900
|
+
var AbstractJob = class {
|
|
8901
|
+
constructor(getSession, client, requestLogger) {
|
|
8912
8902
|
this._responseStream = null;
|
|
8913
8903
|
this._controller = new AbortController();
|
|
8914
|
-
this.
|
|
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
|
-
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
|
|
8936
|
-
|
|
8937
|
-
|
|
8938
|
-
|
|
8939
|
-
|
|
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
|
-
}
|
|
8961
|
+
} catch (reason) {
|
|
8942
8962
|
reject(reason);
|
|
8943
|
-
}
|
|
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
|
-
|
|
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,
|
|
8960
|
-
super(
|
|
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":
|
|
8986
|
+
"Authorization": `Bearer ${session.accessToken}`,
|
|
8967
8987
|
"Accept": "application/jsonl",
|
|
8968
8988
|
"Content-Type": this._mimeType
|
|
8969
8989
|
};
|
|
8970
|
-
const postUrl = `${
|
|
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,
|
|
8987
|
-
super(
|
|
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":
|
|
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": "
|
|
9001
|
-
"
|
|
9048
|
+
"sourceType": "LIVE_INGRESS",
|
|
9049
|
+
"liveIngressId": this._ingressId
|
|
9002
9050
|
};
|
|
9003
|
-
const
|
|
9004
|
-
|
|
9005
|
-
|
|
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",
|
|
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 =
|
|
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 =
|
|
9207
|
-
const 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.
|
|
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
|
-
|
|
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:
|
|
9750
|
+
validUntil: this._expire_token_time * 1e3,
|
|
9751
|
+
baseUrl: this._baseUrl,
|
|
9752
|
+
pipelineId: this._pipelineId
|
|
9259
9753
|
};
|
|
9260
|
-
|
|
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
|
|
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
|
-
|
|
9272
|
-
|
|
9273
|
-
|
|
9274
|
-
|
|
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.
|
|
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
|
|
9785
|
+
throw new Error("endpoint not connected, use connect() before loadFrom()");
|
|
9287
9786
|
}
|
|
9288
9787
|
await this._limit.acquire();
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
this.
|
|
9292
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
9323
|
-
|
|
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
|
-
|
|
9345
|
-
|
|
9346
|
-
|
|
9347
|
-
|
|
9348
|
-
|
|
9349
|
-
|
|
9350
|
-
|
|
9351
|
-
|
|
9352
|
-
|
|
9353
|
-
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
9553
|
-
session,
|
|
9554
|
-
|
|
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
|
-
|
|
9569
|
-
|
|
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
|
-
|
|
10192
|
+
EndpointState,
|
|
10193
|
+
EyePopSdk,
|
|
10194
|
+
src_default as default
|
|
9576
10195
|
};
|
|
9577
10196
|
/*! Bundled license information:
|
|
9578
10197
|
|