@eyepop.ai/eyepop 3.23.0 → 3.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/eyepop.index.d.mts +294 -41
- package/dist/eyepop.index.d.ts +294 -41
- package/dist/eyepop.index.js +2227 -1330
- package/dist/eyepop.index.js.map +1 -1
- package/dist/eyepop.index.mjs +2216 -1330
- package/dist/eyepop.index.mjs.map +1 -1
- package/dist/eyepop.min.js +1 -1
- package/package.json +1 -1
package/dist/eyepop.index.mjs
CHANGED
|
@@ -8666,6 +8666,667 @@ function accessTokenCredential(auth) {
|
|
|
8666
8666
|
return nonEmptyCredential(auth.accessToken);
|
|
8667
8667
|
}
|
|
8668
8668
|
|
|
8669
|
+
// types.ts
|
|
8670
|
+
var EndpointState = /* @__PURE__ */ ((EndpointState2) => {
|
|
8671
|
+
EndpointState2["Idle"] = "Idle";
|
|
8672
|
+
EndpointState2["Busy"] = "Busy";
|
|
8673
|
+
EndpointState2["Authenticating"] = "Authenticating";
|
|
8674
|
+
EndpointState2["FetchConfig"] = "FetchConfig";
|
|
8675
|
+
EndpointState2["Error"] = "Error";
|
|
8676
|
+
EndpointState2["NotAvailable"] = "NotAvailable";
|
|
8677
|
+
return EndpointState2;
|
|
8678
|
+
})(EndpointState || {});
|
|
8679
|
+
|
|
8680
|
+
// shims/http_client.ts
|
|
8681
|
+
var createHttpClient;
|
|
8682
|
+
function logLineFromRequest(input, init) {
|
|
8683
|
+
const url = input instanceof Request ? input.url : input;
|
|
8684
|
+
const method = input instanceof Request ? input.method : init?.method || (init?.body !== void 0 ? "POST" : "GET");
|
|
8685
|
+
return `${method} ${url}`;
|
|
8686
|
+
}
|
|
8687
|
+
if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
8688
|
+
class BrowserHttpClient {
|
|
8689
|
+
constructor(logger) {
|
|
8690
|
+
this._logger = logger;
|
|
8691
|
+
}
|
|
8692
|
+
async fetch(input, init) {
|
|
8693
|
+
const logLine = logLineFromRequest(input, init);
|
|
8694
|
+
this._logger.debug(`Browser fetch() BEFORE ${logLine}`);
|
|
8695
|
+
const response = await fetch(input, init);
|
|
8696
|
+
this._logger.debug(`AFTER ${logLine} -> ${response.status}`);
|
|
8697
|
+
return response;
|
|
8698
|
+
}
|
|
8699
|
+
async close() {
|
|
8700
|
+
}
|
|
8701
|
+
isFullDuplex() {
|
|
8702
|
+
return false;
|
|
8703
|
+
}
|
|
8704
|
+
}
|
|
8705
|
+
createHttpClient = async (logger) => {
|
|
8706
|
+
return new BrowserHttpClient(logger);
|
|
8707
|
+
};
|
|
8708
|
+
} else {
|
|
8709
|
+
class NodeHttpClient {
|
|
8710
|
+
constructor(agent, fetchFn, logger) {
|
|
8711
|
+
this._agent = agent;
|
|
8712
|
+
this._fetch = fetchFn;
|
|
8713
|
+
this._logger = logger;
|
|
8714
|
+
}
|
|
8715
|
+
async fetch(input, init) {
|
|
8716
|
+
init || (init = {});
|
|
8717
|
+
init.dispatcher = this._agent;
|
|
8718
|
+
const logLine = logLineFromRequest(input, init);
|
|
8719
|
+
this._logger.debug(`Node fetch() BEFORE ${logLine}`);
|
|
8720
|
+
const response = await this._fetch(input, init);
|
|
8721
|
+
this._logger.debug(`AFTER ${logLine} -> ${response.status}`);
|
|
8722
|
+
return response;
|
|
8723
|
+
}
|
|
8724
|
+
async close() {
|
|
8725
|
+
return this._agent.close();
|
|
8726
|
+
}
|
|
8727
|
+
isFullDuplex() {
|
|
8728
|
+
return false;
|
|
8729
|
+
}
|
|
8730
|
+
}
|
|
8731
|
+
createHttpClient = async (logger) => {
|
|
8732
|
+
const undici = __require("undici");
|
|
8733
|
+
const agent = new undici.Agent({
|
|
8734
|
+
keepAliveTimeout: 1e4,
|
|
8735
|
+
connections: 5,
|
|
8736
|
+
// two parallel streaming requests to the same host seem to deadlock with pipelining > 0
|
|
8737
|
+
pipelining: 0
|
|
8738
|
+
});
|
|
8739
|
+
logger.debug("Using node fetch with undici agent as http client");
|
|
8740
|
+
return new NodeHttpClient(agent, undici.fetch, logger);
|
|
8741
|
+
};
|
|
8742
|
+
}
|
|
8743
|
+
|
|
8744
|
+
// semaphore.ts
|
|
8745
|
+
var Semaphore = class {
|
|
8746
|
+
/**
|
|
8747
|
+
* Creates a semaphore.
|
|
8748
|
+
* @param permits The number of permits, i.e. strands of execution being allowed
|
|
8749
|
+
* to run in parallel.
|
|
8750
|
+
* This number can be initialized with a negative integer.
|
|
8751
|
+
*/
|
|
8752
|
+
constructor(permits) {
|
|
8753
|
+
this.promiseResolverQueue = [];
|
|
8754
|
+
this.permits = permits;
|
|
8755
|
+
}
|
|
8756
|
+
/**
|
|
8757
|
+
* Returns the number of available permits.
|
|
8758
|
+
* @returns The number of available permits.
|
|
8759
|
+
*/
|
|
8760
|
+
getPermits() {
|
|
8761
|
+
return this.permits;
|
|
8762
|
+
}
|
|
8763
|
+
/**
|
|
8764
|
+
* Returns a promise used to wait for a permit to become available. This method should be awaited on.
|
|
8765
|
+
* @returns A promise that gets resolved when execution is allowed to proceed.
|
|
8766
|
+
*/
|
|
8767
|
+
async wait() {
|
|
8768
|
+
if (this.permits > 0) {
|
|
8769
|
+
this.permits -= 1;
|
|
8770
|
+
return Promise.resolve(true);
|
|
8771
|
+
}
|
|
8772
|
+
return new Promise((resolver) => this.promiseResolverQueue.push(resolver));
|
|
8773
|
+
}
|
|
8774
|
+
/**
|
|
8775
|
+
* Alias for {@linkcode Semaphore.wait}.
|
|
8776
|
+
* @returns A promise that gets resolved when execution is allowed to proceed.
|
|
8777
|
+
*/
|
|
8778
|
+
async acquire() {
|
|
8779
|
+
return this.wait();
|
|
8780
|
+
}
|
|
8781
|
+
/**
|
|
8782
|
+
* Same as {@linkcode Semaphore.wait} except the promise returned gets resolved with false if no
|
|
8783
|
+
* permit becomes available in time.
|
|
8784
|
+
* @param milliseconds The time spent waiting before the wait is aborted. This is a lower bound,
|
|
8785
|
+
* you shouldn't rely on it being precise.
|
|
8786
|
+
* @returns A promise that gets resolved to true when execution is allowed to proceed or
|
|
8787
|
+
* false if the time given elapses before a permit becomes available.
|
|
8788
|
+
*/
|
|
8789
|
+
async waitFor(milliseconds) {
|
|
8790
|
+
if (this.permits > 0) {
|
|
8791
|
+
this.permits -= 1;
|
|
8792
|
+
return Promise.resolve(true);
|
|
8793
|
+
}
|
|
8794
|
+
let resolver = (_) => void 0;
|
|
8795
|
+
const promise = new Promise((r) => {
|
|
8796
|
+
resolver = r;
|
|
8797
|
+
});
|
|
8798
|
+
this.promiseResolverQueue.push(resolver);
|
|
8799
|
+
setTimeout(() => {
|
|
8800
|
+
const index = this.promiseResolverQueue.indexOf(resolver);
|
|
8801
|
+
if (index !== -1) {
|
|
8802
|
+
this.promiseResolverQueue.splice(index, 1);
|
|
8803
|
+
} else {
|
|
8804
|
+
console.warn(`Semaphore.waitFor couldn't find its promise resolver in the queue`);
|
|
8805
|
+
}
|
|
8806
|
+
resolver(false);
|
|
8807
|
+
}, milliseconds);
|
|
8808
|
+
return promise;
|
|
8809
|
+
}
|
|
8810
|
+
/**
|
|
8811
|
+
* Synchronous function that tries to acquire a permit and returns true if successful, false otherwise.
|
|
8812
|
+
* @returns Whether a permit could be acquired.
|
|
8813
|
+
*/
|
|
8814
|
+
tryAcquire() {
|
|
8815
|
+
if (this.permits > 0) {
|
|
8816
|
+
this.permits -= 1;
|
|
8817
|
+
return true;
|
|
8818
|
+
}
|
|
8819
|
+
return false;
|
|
8820
|
+
}
|
|
8821
|
+
/**
|
|
8822
|
+
* Acquires all permits that are currently available and returns the number of acquired permits.
|
|
8823
|
+
* @returns Number of acquired permits.
|
|
8824
|
+
*/
|
|
8825
|
+
drainPermits() {
|
|
8826
|
+
if (this.permits > 0) {
|
|
8827
|
+
const permitCount = this.permits;
|
|
8828
|
+
this.permits = 0;
|
|
8829
|
+
return permitCount;
|
|
8830
|
+
}
|
|
8831
|
+
return 0;
|
|
8832
|
+
}
|
|
8833
|
+
/**
|
|
8834
|
+
* Increases the number of permits by one. If there are other functions waiting, one of them will
|
|
8835
|
+
* continue to execute in a future iteration of the event loop.
|
|
8836
|
+
*/
|
|
8837
|
+
signal() {
|
|
8838
|
+
this.permits += 1;
|
|
8839
|
+
if (this.permits > 1 && this.promiseResolverQueue.length > 0) {
|
|
8840
|
+
console.warn("Semaphore.permits should never be > 0 when there is someone waiting.");
|
|
8841
|
+
} else if (this.permits === 1 && this.promiseResolverQueue.length > 0) {
|
|
8842
|
+
this.permits -= 1;
|
|
8843
|
+
const nextResolver = this.promiseResolverQueue.shift();
|
|
8844
|
+
if (nextResolver) {
|
|
8845
|
+
nextResolver(true);
|
|
8846
|
+
}
|
|
8847
|
+
}
|
|
8848
|
+
}
|
|
8849
|
+
/**
|
|
8850
|
+
* Alias for {@linkcode Semaphore.signal}.
|
|
8851
|
+
*/
|
|
8852
|
+
release() {
|
|
8853
|
+
this.signal();
|
|
8854
|
+
}
|
|
8855
|
+
/**
|
|
8856
|
+
* Schedules func to be called once a permit becomes available.
|
|
8857
|
+
* Returns a promise that resolves to the return value of func.
|
|
8858
|
+
* @typeparam T The return type of func.
|
|
8859
|
+
* @param func The function to be executed.
|
|
8860
|
+
* @return A promise that gets resolved with the return value of the function.
|
|
8861
|
+
*/
|
|
8862
|
+
async execute(func) {
|
|
8863
|
+
await this.wait();
|
|
8864
|
+
try {
|
|
8865
|
+
return await func();
|
|
8866
|
+
} finally {
|
|
8867
|
+
this.signal();
|
|
8868
|
+
}
|
|
8869
|
+
}
|
|
8870
|
+
};
|
|
8871
|
+
|
|
8872
|
+
// endpoint.ts
|
|
8873
|
+
import { pino } from "pino";
|
|
8874
|
+
|
|
8875
|
+
// shims/browser_session.ts
|
|
8876
|
+
import { createAuth0Client } from "@auth0/auth0-spa-js";
|
|
8877
|
+
var authenticateBrowserSession;
|
|
8878
|
+
if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
8879
|
+
authenticateBrowserSession = async (auth0, options) => {
|
|
8880
|
+
if (options.eyepopUrl == null) {
|
|
8881
|
+
return Promise.reject("options.eyepopUrl cannot be null");
|
|
8882
|
+
}
|
|
8883
|
+
const auth0ClientOptions = {
|
|
8884
|
+
clientId: auth0.clientId,
|
|
8885
|
+
domain: auth0.domain,
|
|
8886
|
+
authorizationParams: {
|
|
8887
|
+
scope: auth0.scope,
|
|
8888
|
+
audience: auth0.audience
|
|
8889
|
+
}
|
|
8890
|
+
};
|
|
8891
|
+
const auth0Client = await createAuth0Client(auth0ClientOptions);
|
|
8892
|
+
if (!await auth0Client.isAuthenticated()) {
|
|
8893
|
+
await auth0Client.loginWithPopup();
|
|
8894
|
+
}
|
|
8895
|
+
const accessToken = await auth0Client.getTokenSilently();
|
|
8896
|
+
if (!accessToken) {
|
|
8897
|
+
return Promise.reject("auth0 login failed");
|
|
8898
|
+
}
|
|
8899
|
+
let session;
|
|
8900
|
+
const workerOptions = options;
|
|
8901
|
+
if (typeof workerOptions.popId != "undefined") {
|
|
8902
|
+
const workerSession = {
|
|
8903
|
+
eyepopUrl: options.eyepopUrl,
|
|
8904
|
+
accessToken,
|
|
8905
|
+
validUntil: Date.now() + 60 * 60 * 1e3,
|
|
8906
|
+
popId: workerOptions.popId,
|
|
8907
|
+
baseUrl: void 0,
|
|
8908
|
+
pipelineId: void 0,
|
|
8909
|
+
isPipelineMode: workerOptions.isPipelineMode,
|
|
8910
|
+
authenticationHeaders: () => {
|
|
8911
|
+
return { Authorization: `Bearer ${accessToken}` };
|
|
8912
|
+
}
|
|
8913
|
+
};
|
|
8914
|
+
session = workerSession;
|
|
8915
|
+
} else {
|
|
8916
|
+
session = {
|
|
8917
|
+
eyepopUrl: options.eyepopUrl,
|
|
8918
|
+
accessToken,
|
|
8919
|
+
validUntil: Date.now() + 60 * 60 * 1e3
|
|
8920
|
+
};
|
|
8921
|
+
}
|
|
8922
|
+
return session;
|
|
8923
|
+
};
|
|
8924
|
+
} else {
|
|
8925
|
+
authenticateBrowserSession = (_auth0, _options) => {
|
|
8926
|
+
return Promise.reject("auth0 login not supported server-side");
|
|
8927
|
+
};
|
|
8928
|
+
}
|
|
8929
|
+
|
|
8930
|
+
// endpoint.ts
|
|
8931
|
+
var Endpoint = class {
|
|
8932
|
+
constructor(options) {
|
|
8933
|
+
this._options = options;
|
|
8934
|
+
this._token = null;
|
|
8935
|
+
this._expire_token_time = null;
|
|
8936
|
+
this._client = null;
|
|
8937
|
+
this._statusRetryHandlers = /* @__PURE__ */ new Map();
|
|
8938
|
+
this._statusRetryHandlers.set(401, this.statusHandler401);
|
|
8939
|
+
this._limit = new Semaphore(this._options.jobQueueLength ?? 1024);
|
|
8940
|
+
this._state = "Idle" /* Idle */;
|
|
8941
|
+
this._message = null;
|
|
8942
|
+
this._stateChangeHandler = null;
|
|
8943
|
+
let rootLogger;
|
|
8944
|
+
if (options.logger) {
|
|
8945
|
+
rootLogger = options.logger;
|
|
8946
|
+
} else {
|
|
8947
|
+
rootLogger = pino();
|
|
8948
|
+
}
|
|
8949
|
+
this._logger = rootLogger.child({ module: "eyepop" });
|
|
8950
|
+
this._requestLogger = this._logger.child({ module: "requests" });
|
|
8951
|
+
}
|
|
8952
|
+
setStatusRetryHandlers(statusRetryHandlers = void 0) {
|
|
8953
|
+
this._statusRetryHandlers = new Map(statusRetryHandlers);
|
|
8954
|
+
this._statusRetryHandlers.set(401, this.statusHandler401);
|
|
8955
|
+
}
|
|
8956
|
+
eyepopUrl() {
|
|
8957
|
+
if (this._options.eyepopUrl) {
|
|
8958
|
+
return this._options.eyepopUrl.replace(/\/+$/, "");
|
|
8959
|
+
} else {
|
|
8960
|
+
return "https://compute.eyepop.ai";
|
|
8961
|
+
}
|
|
8962
|
+
}
|
|
8963
|
+
// TODO: deprecated Web API endpoint needed for POP_ID support
|
|
8964
|
+
eyepopWebApiUrl() {
|
|
8965
|
+
if (this._options.eyepopUrl) {
|
|
8966
|
+
return this._options.eyepopUrl.replace(/\/+$/, "").replace(/compute\./, "web-api.");
|
|
8967
|
+
} else {
|
|
8968
|
+
return "https://api.eyepop.ai";
|
|
8969
|
+
}
|
|
8970
|
+
}
|
|
8971
|
+
pendingJobs() {
|
|
8972
|
+
return (this._options.jobQueueLength ?? 1024) - this._limit.getPermits();
|
|
8973
|
+
}
|
|
8974
|
+
state() {
|
|
8975
|
+
return this._state;
|
|
8976
|
+
}
|
|
8977
|
+
lastMessage() {
|
|
8978
|
+
return this._message;
|
|
8979
|
+
}
|
|
8980
|
+
onStateChanged(handler) {
|
|
8981
|
+
this._stateChangeHandler = handler;
|
|
8982
|
+
return this;
|
|
8983
|
+
}
|
|
8984
|
+
updateState(newState = void 0, message = void 0) {
|
|
8985
|
+
const fromState = this._state;
|
|
8986
|
+
if (newState == void 0) {
|
|
8987
|
+
if (this._limit.getPermits() == this._options.jobQueueLength) {
|
|
8988
|
+
newState = "Idle" /* Idle */;
|
|
8989
|
+
} else {
|
|
8990
|
+
newState = "Busy" /* Busy */;
|
|
8991
|
+
}
|
|
8992
|
+
}
|
|
8993
|
+
this._state = newState;
|
|
8994
|
+
this._message = message ? message : null;
|
|
8995
|
+
if (this._stateChangeHandler) {
|
|
8996
|
+
this._stateChangeHandler(fromState, this._state);
|
|
8997
|
+
}
|
|
8998
|
+
}
|
|
8999
|
+
async connect() {
|
|
9000
|
+
if (this._client) {
|
|
9001
|
+
this._logger.warn("endpoint already connected");
|
|
9002
|
+
return this;
|
|
9003
|
+
}
|
|
9004
|
+
if (!this._options.eyepopUrl) {
|
|
9005
|
+
return Promise.reject("option eyepopUrl or environment variable EYEPOP_URL is required");
|
|
9006
|
+
}
|
|
9007
|
+
const auth = resolveAuth(this._options);
|
|
9008
|
+
if (auth === void 0) {
|
|
9009
|
+
return Promise.reject("cannot connect without defined auth option");
|
|
9010
|
+
}
|
|
9011
|
+
if (auth.session !== void 0) {
|
|
9012
|
+
this._token = auth.session.accessToken;
|
|
9013
|
+
this._expire_token_time = auth.session.validUntil / 1e3;
|
|
9014
|
+
} else if (auth.oAuth2 !== void 0) {
|
|
9015
|
+
} else if (accessTokenCredential(auth) !== void 0) {
|
|
9016
|
+
} else if (apiKeyCredential(auth) !== void 0) {
|
|
9017
|
+
} else if (auth.isLocal !== void 0) {
|
|
9018
|
+
} else {
|
|
9019
|
+
return Promise.reject("option apiKey/accessToken or environment variable EYEPOP_API_KEY is required");
|
|
9020
|
+
}
|
|
9021
|
+
if (this._options.platformSupport?.createHttpClient !== void 0) {
|
|
9022
|
+
this._client = await this._options.platformSupport.createHttpClient(this._requestLogger);
|
|
9023
|
+
} else {
|
|
9024
|
+
this._client = await createHttpClient(this._requestLogger);
|
|
9025
|
+
}
|
|
9026
|
+
return await this.reconnect();
|
|
9027
|
+
}
|
|
9028
|
+
async disconnect(wait = true) {
|
|
9029
|
+
if (wait && this._limit) {
|
|
9030
|
+
for (let j = 0; j < this._options.jobQueueLength; j++) {
|
|
9031
|
+
await this._limit.acquire();
|
|
9032
|
+
}
|
|
9033
|
+
}
|
|
9034
|
+
this._limit = new Semaphore(this._options.jobQueueLength ?? 1024);
|
|
9035
|
+
if (this._client) {
|
|
9036
|
+
await this._client.close();
|
|
9037
|
+
this._client = null;
|
|
9038
|
+
}
|
|
9039
|
+
}
|
|
9040
|
+
async session() {
|
|
9041
|
+
await this.currentAccessToken();
|
|
9042
|
+
if (this._token == null || this._expire_token_time == null) {
|
|
9043
|
+
return Promise.reject("endpoint not connected");
|
|
9044
|
+
}
|
|
9045
|
+
return {
|
|
9046
|
+
eyepopUrl: this._options.eyepopUrl,
|
|
9047
|
+
accessToken: this._token,
|
|
9048
|
+
validUntil: this._expire_token_time * 1e3
|
|
9049
|
+
};
|
|
9050
|
+
}
|
|
9051
|
+
statusHandler401(_statusCode) {
|
|
9052
|
+
this._token = null;
|
|
9053
|
+
this._expire_token_time = null;
|
|
9054
|
+
}
|
|
9055
|
+
async fetchWithRetry(fetcher, retries = 1) {
|
|
9056
|
+
while (true) {
|
|
9057
|
+
try {
|
|
9058
|
+
const response = await fetcher();
|
|
9059
|
+
if (response.ok) {
|
|
9060
|
+
return response;
|
|
9061
|
+
} else {
|
|
9062
|
+
const handler = this._statusRetryHandlers.get(response.status);
|
|
9063
|
+
if (handler != null) {
|
|
9064
|
+
handler(response.status);
|
|
9065
|
+
if (retries--) {
|
|
9066
|
+
this._requestLogger.info("received %d response, retry", response.status);
|
|
9067
|
+
} else {
|
|
9068
|
+
return response;
|
|
9069
|
+
}
|
|
9070
|
+
} else {
|
|
9071
|
+
return response;
|
|
9072
|
+
}
|
|
9073
|
+
}
|
|
9074
|
+
} catch (error) {
|
|
9075
|
+
const handler = this._statusRetryHandlers.get(404);
|
|
9076
|
+
if (handler != null) {
|
|
9077
|
+
handler(error);
|
|
9078
|
+
if (retries--) {
|
|
9079
|
+
this._requestLogger.info("error %s, retry", error);
|
|
9080
|
+
} else {
|
|
9081
|
+
return Promise.reject(`error ${error}`);
|
|
9082
|
+
}
|
|
9083
|
+
} else {
|
|
9084
|
+
return Promise.reject(`error ${error}`);
|
|
9085
|
+
}
|
|
9086
|
+
}
|
|
9087
|
+
}
|
|
9088
|
+
}
|
|
9089
|
+
async reconnect() {
|
|
9090
|
+
throw new Error("reconnect() not implemented");
|
|
9091
|
+
}
|
|
9092
|
+
async authorizationHeader() {
|
|
9093
|
+
if (resolveAuth(this._options)?.isLocal !== void 0) {
|
|
9094
|
+
return `Implicit`;
|
|
9095
|
+
}
|
|
9096
|
+
return `Bearer ${await this.currentAccessToken()}`;
|
|
9097
|
+
}
|
|
9098
|
+
async currentAccessToken() {
|
|
9099
|
+
const now = Date.now() / 1e3;
|
|
9100
|
+
if (!this._token || this._expire_token_time < now) {
|
|
9101
|
+
this.updateState("Authenticating" /* Authenticating */);
|
|
9102
|
+
try {
|
|
9103
|
+
const auth = resolveAuth(this._options);
|
|
9104
|
+
if (!this._client) {
|
|
9105
|
+
return Promise.reject("endpoint not connected");
|
|
9106
|
+
} else if (auth?.isLocal !== void 0) {
|
|
9107
|
+
this._token = "implicit";
|
|
9108
|
+
this._expire_token_time = Number.MAX_VALUE;
|
|
9109
|
+
} else if (auth?.session !== void 0) {
|
|
9110
|
+
return Promise.reject("temporary access token expired");
|
|
9111
|
+
} else if (auth?.oAuth2 !== void 0 && this._options.eyepopUrl) {
|
|
9112
|
+
const session = await authenticateBrowserSession(auth.oAuth2, this._options);
|
|
9113
|
+
this._token = session.accessToken;
|
|
9114
|
+
this._expire_token_time = session.validUntil / 1e3;
|
|
9115
|
+
} else if (accessTokenCredential(auth) !== void 0) {
|
|
9116
|
+
this._token = accessTokenCredential(auth);
|
|
9117
|
+
this._expire_token_time = Number.MAX_VALUE;
|
|
9118
|
+
} else if (this._options.eyepopUrl) {
|
|
9119
|
+
const credential = apiKeyCredential(auth);
|
|
9120
|
+
if (credential === void 0) {
|
|
9121
|
+
return Promise.reject("no valid auth option");
|
|
9122
|
+
}
|
|
9123
|
+
const headers = { Authorization: `Bearer ${credential}` };
|
|
9124
|
+
const post_url = `${this.eyepopUrl()}/v1/auth/authenticate`;
|
|
9125
|
+
const response = await this._client.fetch(post_url, {
|
|
9126
|
+
method: "POST",
|
|
9127
|
+
headers
|
|
9128
|
+
});
|
|
9129
|
+
if (response.status != 200) {
|
|
9130
|
+
const message = await response.text();
|
|
9131
|
+
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
9132
|
+
}
|
|
9133
|
+
const data = await response.json();
|
|
9134
|
+
const token = data;
|
|
9135
|
+
this._token = token.access_token;
|
|
9136
|
+
this._expire_token_time = now + token.expires_in - 60;
|
|
9137
|
+
} else {
|
|
9138
|
+
return Promise.reject("no valid auth option");
|
|
9139
|
+
}
|
|
9140
|
+
} finally {
|
|
9141
|
+
this.updateState();
|
|
9142
|
+
}
|
|
9143
|
+
}
|
|
9144
|
+
this._logger.debug("using access token, valid for at least %d seconds", this._expire_token_time - now);
|
|
9145
|
+
return this._token;
|
|
9146
|
+
}
|
|
9147
|
+
};
|
|
9148
|
+
|
|
9149
|
+
// camera.ts
|
|
9150
|
+
var QUATERNION_TOLERANCE = 1e-3;
|
|
9151
|
+
function isFinite_(value) {
|
|
9152
|
+
return value === void 0 || Number.isFinite(value);
|
|
9153
|
+
}
|
|
9154
|
+
function validateCamera(camera) {
|
|
9155
|
+
if (camera.intrinsics !== void 0 && camera.hfovDegrees !== void 0) {
|
|
9156
|
+
throw new Error("camera.intrinsics and camera.hfovDegrees are alternatives, supply one");
|
|
9157
|
+
}
|
|
9158
|
+
if (camera.intrinsics === void 0 && camera.hfovDegrees === void 0) {
|
|
9159
|
+
throw new Error("camera requires either camera.intrinsics or camera.hfovDegrees");
|
|
9160
|
+
}
|
|
9161
|
+
if (camera.hfovDegrees !== void 0) {
|
|
9162
|
+
if (!(camera.hfovDegrees > 0 && camera.hfovDegrees < 180)) {
|
|
9163
|
+
throw new Error("camera.hfovDegrees must be a horizontal field of view in (0, 180) degrees");
|
|
9164
|
+
}
|
|
9165
|
+
} else {
|
|
9166
|
+
const intrinsics = camera.intrinsics;
|
|
9167
|
+
for (const [name, focal] of [
|
|
9168
|
+
["fx", intrinsics.fx],
|
|
9169
|
+
["fy", intrinsics.fy]
|
|
9170
|
+
]) {
|
|
9171
|
+
if (!(focal > 0) || !Number.isFinite(focal)) {
|
|
9172
|
+
throw new Error(`camera.intrinsics.${name} must be a positive, finite focal length`);
|
|
9173
|
+
}
|
|
9174
|
+
}
|
|
9175
|
+
for (const [name, principal, extent] of [
|
|
9176
|
+
["cx", intrinsics.cx, "width"],
|
|
9177
|
+
["cy", intrinsics.cy, "height"]
|
|
9178
|
+
]) {
|
|
9179
|
+
if (!(principal >= 0 && principal <= 1)) {
|
|
9180
|
+
throw new Error(`camera.intrinsics.${name} must be within [0, 1] of the frame ${extent}`);
|
|
9181
|
+
}
|
|
9182
|
+
}
|
|
9183
|
+
}
|
|
9184
|
+
if (camera.distortion !== void 0) {
|
|
9185
|
+
for (const name of ["k1", "k2", "p1", "p2", "k3"]) {
|
|
9186
|
+
if (!isFinite_(camera.distortion[name])) {
|
|
9187
|
+
throw new Error(`camera.distortion.${name} must be a finite number`);
|
|
9188
|
+
}
|
|
9189
|
+
}
|
|
9190
|
+
}
|
|
9191
|
+
if (camera.extrinsics !== void 0) {
|
|
9192
|
+
const translation = camera.extrinsics.translation;
|
|
9193
|
+
if (translation !== void 0) {
|
|
9194
|
+
for (const axis of ["x", "y", "z"]) {
|
|
9195
|
+
if (!Number.isFinite(translation[axis])) {
|
|
9196
|
+
throw new Error(`camera.extrinsics.translation.${axis} must be a finite number`);
|
|
9197
|
+
}
|
|
9198
|
+
}
|
|
9199
|
+
}
|
|
9200
|
+
const rotation = camera.extrinsics.rotation;
|
|
9201
|
+
if (rotation !== void 0) {
|
|
9202
|
+
const norm = Math.sqrt(rotation.w ** 2 + rotation.x ** 2 + rotation.y ** 2 + rotation.z ** 2);
|
|
9203
|
+
if (!(Math.abs(norm - 1) <= QUATERNION_TOLERANCE)) {
|
|
9204
|
+
throw new Error("camera.extrinsics.rotation must be a unit quaternion");
|
|
9205
|
+
}
|
|
9206
|
+
}
|
|
9207
|
+
}
|
|
9208
|
+
}
|
|
9209
|
+
|
|
9210
|
+
// worker/worker_types.ts
|
|
9211
|
+
var PredictionVersion = /* @__PURE__ */ ((PredictionVersion3) => {
|
|
9212
|
+
PredictionVersion3[PredictionVersion3["V1"] = 1] = "V1";
|
|
9213
|
+
PredictionVersion3[PredictionVersion3["V2"] = 2] = "V2";
|
|
9214
|
+
PredictionVersion3[PredictionVersion3["V3"] = 3] = "V3";
|
|
9215
|
+
return PredictionVersion3;
|
|
9216
|
+
})(PredictionVersion || {});
|
|
9217
|
+
var DEFAULT_PREDICTION_VERSION = 2 /* V2 */;
|
|
9218
|
+
var VideoMode = /* @__PURE__ */ ((VideoMode2) => {
|
|
9219
|
+
VideoMode2["STREAM"] = "stream";
|
|
9220
|
+
VideoMode2["BUFFER"] = "buffer";
|
|
9221
|
+
return VideoMode2;
|
|
9222
|
+
})(VideoMode || {});
|
|
9223
|
+
var PopComponentType = /* @__PURE__ */ ((PopComponentType2) => {
|
|
9224
|
+
PopComponentType2["FORWARD"] = "forward";
|
|
9225
|
+
PopComponentType2["INFERENCE"] = "inference";
|
|
9226
|
+
PopComponentType2["TRACKING"] = "tracking";
|
|
9227
|
+
PopComponentType2["CONTOUR_FINDER"] = "contour_finder";
|
|
9228
|
+
PopComponentType2["COMPONENT_FINDER"] = "component_finder";
|
|
9229
|
+
return PopComponentType2;
|
|
9230
|
+
})(PopComponentType || {});
|
|
9231
|
+
var ForwardOperatorType = /* @__PURE__ */ ((ForwardOperatorType2) => {
|
|
9232
|
+
ForwardOperatorType2["FULL"] = "full";
|
|
9233
|
+
ForwardOperatorType2["CROP"] = "crop";
|
|
9234
|
+
ForwardOperatorType2["CROP_WITH_FULL_FALLBACK"] = "crop_with_full_fallback";
|
|
9235
|
+
ForwardOperatorType2["SELECT_CROP"] = "select_crop";
|
|
9236
|
+
ForwardOperatorType2["SELECT_FULL"] = "select_full";
|
|
9237
|
+
return ForwardOperatorType2;
|
|
9238
|
+
})(ForwardOperatorType || {});
|
|
9239
|
+
var SelectMode = /* @__PURE__ */ ((SelectMode2) => {
|
|
9240
|
+
SelectMode2["MOST_RELEVANT"] = "most_relevant";
|
|
9241
|
+
return SelectMode2;
|
|
9242
|
+
})(SelectMode || {});
|
|
9243
|
+
function isSelectOperator(operator) {
|
|
9244
|
+
return operator?.type === "select_crop" /* SELECT_CROP */ || operator?.type === "select_full" /* SELECT_FULL */;
|
|
9245
|
+
}
|
|
9246
|
+
var InferenceType = /* @__PURE__ */ ((InferenceType2) => {
|
|
9247
|
+
InferenceType2["IMAGE_CLASSIFICATION"] = "image_classification";
|
|
9248
|
+
InferenceType2["OBJECT_DETECTION"] = "object_detection";
|
|
9249
|
+
InferenceType2["KEY_POINTS"] = "key_points";
|
|
9250
|
+
InferenceType2["OCR"] = "ocr";
|
|
9251
|
+
InferenceType2["MESH"] = "mesh";
|
|
9252
|
+
InferenceType2["FEATURE_VECTOR"] = "feature_vector";
|
|
9253
|
+
InferenceType2["SEMANTIC_SEGMENTATION"] = "semantic_segmentation";
|
|
9254
|
+
InferenceType2["SEGMENTATION"] = "segmentation";
|
|
9255
|
+
return InferenceType2;
|
|
9256
|
+
})(InferenceType || {});
|
|
9257
|
+
var MotionModel = /* @__PURE__ */ ((MotionModel2) => {
|
|
9258
|
+
MotionModel2["RANDOM_WALK"] = "random_walk";
|
|
9259
|
+
MotionModel2["CONSTANT_VELOCITY"] = "constant_velocity";
|
|
9260
|
+
MotionModel2["CONSTANT_ACCELERATION"] = "constant_acceleration";
|
|
9261
|
+
return MotionModel2;
|
|
9262
|
+
})(MotionModel || {});
|
|
9263
|
+
var ContourType = /* @__PURE__ */ ((ContourType2) => {
|
|
9264
|
+
ContourType2["ALL_PIXELS"] = "all_pixels";
|
|
9265
|
+
ContourType2["POLYGON"] = "polygon";
|
|
9266
|
+
ContourType2["CONVEX_HULL"] = "convex_hull";
|
|
9267
|
+
ContourType2["HOUGH_CIRCLES"] = "hough_circles";
|
|
9268
|
+
ContourType2["CIRCLE"] = "circle";
|
|
9269
|
+
ContourType2["TRIANGLE"] = "triangle";
|
|
9270
|
+
ContourType2["RECTANGLE"] = "rectangle";
|
|
9271
|
+
return ContourType2;
|
|
9272
|
+
})(ContourType || {});
|
|
9273
|
+
function validatePop(pop) {
|
|
9274
|
+
if (pop.depthMap !== void 0) {
|
|
9275
|
+
if (pop.depthMap.ability === void 0 === (pop.depthMap.abilityUuid === void 0)) {
|
|
9276
|
+
throw new Error("depthMap requires exactly one of ability or abilityUuid");
|
|
9277
|
+
}
|
|
9278
|
+
}
|
|
9279
|
+
if (pop.defaults?.camera !== void 0) {
|
|
9280
|
+
validateCamera(pop.defaults.camera);
|
|
9281
|
+
}
|
|
9282
|
+
validateForwards(pop.components);
|
|
9283
|
+
}
|
|
9284
|
+
function popSelects(pop) {
|
|
9285
|
+
const selects = (components) => (components ?? []).some((component) => isSelectOperator(component.forward?.operator) || selects(component.forward?.targets));
|
|
9286
|
+
return selects(pop?.components);
|
|
9287
|
+
}
|
|
9288
|
+
function validateForwards(components) {
|
|
9289
|
+
for (const component of components ?? []) {
|
|
9290
|
+
const operator = component.forward?.operator;
|
|
9291
|
+
if (operator !== void 0) {
|
|
9292
|
+
validateSelectOperator(operator);
|
|
9293
|
+
}
|
|
9294
|
+
validateForwards(component.forward?.targets);
|
|
9295
|
+
}
|
|
9296
|
+
}
|
|
9297
|
+
function validateSelectOperator(operator) {
|
|
9298
|
+
if (!isSelectOperator(operator)) {
|
|
9299
|
+
if (operator.select !== void 0) {
|
|
9300
|
+
throw new Error("select is only valid with the select_crop or select_full operator");
|
|
9301
|
+
}
|
|
9302
|
+
return;
|
|
9303
|
+
}
|
|
9304
|
+
const select = operator.select;
|
|
9305
|
+
if (select === void 0) {
|
|
9306
|
+
throw new Error(`${operator.type} requires a select block`);
|
|
9307
|
+
}
|
|
9308
|
+
if (select.mode !== void 0 && select.mode !== "most_relevant" /* MOST_RELEVANT */) {
|
|
9309
|
+
throw new Error(`select mode ${select.mode} is not supported, the only mode is ${"most_relevant" /* MOST_RELEVANT */}`);
|
|
9310
|
+
}
|
|
9311
|
+
if (select.relevancyModel !== void 0 && select.relevancyModelUuid !== void 0) {
|
|
9312
|
+
throw new Error("select can only have one of relevancyModelUuid or relevancyModel");
|
|
9313
|
+
}
|
|
9314
|
+
if (select.minTrackLengthSeconds !== void 0 && select.minTrackLengthSeconds < 0) {
|
|
9315
|
+
throw new Error("select minTrackLengthSeconds cannot be negative");
|
|
9316
|
+
}
|
|
9317
|
+
if (select.intervalSeconds !== void 0 && select.intervalSeconds <= 0) {
|
|
9318
|
+
throw new Error("select intervalSeconds must be positive");
|
|
9319
|
+
}
|
|
9320
|
+
if (operator.crop !== void 0) {
|
|
9321
|
+
if (operator.type !== "select_crop" /* SELECT_CROP */) {
|
|
9322
|
+
throw new Error(`crop options are only valid with select_crop, not ${operator.type}`);
|
|
9323
|
+
}
|
|
9324
|
+
if (operator.crop.maxItems !== void 0) {
|
|
9325
|
+
throw new Error("select_crop forwards one detection per selection, maxItems does not apply");
|
|
9326
|
+
}
|
|
9327
|
+
}
|
|
9328
|
+
}
|
|
9329
|
+
|
|
8669
9330
|
// compute/compute_session.ts
|
|
8670
9331
|
var SESSION_DEAD = /* @__PURE__ */ new Set(["error" /* ERROR */, "failed" /* FAILED */, "stopped" /* STOPPED */, "pipeline_error" /* PIPELINE_ERROR */, "unknown" /* UNKNOWN */]);
|
|
8671
9332
|
var CHECK_FOR_IS_READY_INTERVAL = 250;
|
|
@@ -8979,19 +9640,8 @@ var ComputeSessionClient = class {
|
|
|
8979
9640
|
await sleep(CHECK_FOR_IS_READY_INTERVAL);
|
|
8980
9641
|
}
|
|
8981
9642
|
}
|
|
8982
|
-
}
|
|
8983
|
-
};
|
|
8984
|
-
|
|
8985
|
-
// types.ts
|
|
8986
|
-
var EndpointState = /* @__PURE__ */ ((EndpointState2) => {
|
|
8987
|
-
EndpointState2["Idle"] = "Idle";
|
|
8988
|
-
EndpointState2["Busy"] = "Busy";
|
|
8989
|
-
EndpointState2["Authenticating"] = "Authenticating";
|
|
8990
|
-
EndpointState2["FetchConfig"] = "FetchConfig";
|
|
8991
|
-
EndpointState2["Error"] = "Error";
|
|
8992
|
-
EndpointState2["NotAvailable"] = "NotAvailable";
|
|
8993
|
-
return EndpointState2;
|
|
8994
|
-
})(EndpointState || {});
|
|
9643
|
+
}
|
|
9644
|
+
};
|
|
8995
9645
|
|
|
8996
9646
|
// streaming.ts
|
|
8997
9647
|
import { v4 as uuidv4 } from "uuid";
|
|
@@ -9178,6 +9828,9 @@ function readableStreamFromString(s) {
|
|
|
9178
9828
|
function randomMultipartBoundary() {
|
|
9179
9829
|
return `----formdata-boundary-${uuidv4()}`;
|
|
9180
9830
|
}
|
|
9831
|
+
function escapeDispositionValue(value) {
|
|
9832
|
+
return value.replace(/"/g, "%22").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
|
|
9833
|
+
}
|
|
9181
9834
|
function toPartStream(content) {
|
|
9182
9835
|
if (content instanceof ReadableStream) {
|
|
9183
9836
|
return content;
|
|
@@ -9222,8 +9875,11 @@ function encodeMultipartFormData(parts, boundary) {
|
|
|
9222
9875
|
}
|
|
9223
9876
|
const part = parts[partIndex];
|
|
9224
9877
|
let header = `--${boundary}\r
|
|
9225
|
-
Content-Disposition: form-data; name="${part.name}"
|
|
9226
|
-
|
|
9878
|
+
Content-Disposition: form-data; name="${escapeDispositionValue(part.name)}"`;
|
|
9879
|
+
if (part.filename !== void 0) {
|
|
9880
|
+
header += `; filename="${escapeDispositionValue(part.filename)}"`;
|
|
9881
|
+
}
|
|
9882
|
+
header += "\r\n";
|
|
9227
9883
|
if (part.contentType) {
|
|
9228
9884
|
header += `Content-Type: ${part.contentType}\r
|
|
9229
9885
|
`;
|
|
@@ -9246,187 +9902,6 @@ Content-Disposition: form-data; name="${part.name}"\r
|
|
|
9246
9902
|
});
|
|
9247
9903
|
}
|
|
9248
9904
|
|
|
9249
|
-
// camera.ts
|
|
9250
|
-
var QUATERNION_TOLERANCE = 1e-3;
|
|
9251
|
-
function isFinite_(value) {
|
|
9252
|
-
return value === void 0 || Number.isFinite(value);
|
|
9253
|
-
}
|
|
9254
|
-
function validateCamera(camera) {
|
|
9255
|
-
if (camera.intrinsics !== void 0 && camera.hfovDegrees !== void 0) {
|
|
9256
|
-
throw new Error("camera.intrinsics and camera.hfovDegrees are alternatives, supply one");
|
|
9257
|
-
}
|
|
9258
|
-
if (camera.intrinsics === void 0 && camera.hfovDegrees === void 0) {
|
|
9259
|
-
throw new Error("camera requires either camera.intrinsics or camera.hfovDegrees");
|
|
9260
|
-
}
|
|
9261
|
-
if (camera.hfovDegrees !== void 0) {
|
|
9262
|
-
if (!(camera.hfovDegrees > 0 && camera.hfovDegrees < 180)) {
|
|
9263
|
-
throw new Error("camera.hfovDegrees must be a horizontal field of view in (0, 180) degrees");
|
|
9264
|
-
}
|
|
9265
|
-
} else {
|
|
9266
|
-
const intrinsics = camera.intrinsics;
|
|
9267
|
-
for (const [name, focal] of [
|
|
9268
|
-
["fx", intrinsics.fx],
|
|
9269
|
-
["fy", intrinsics.fy]
|
|
9270
|
-
]) {
|
|
9271
|
-
if (!(focal > 0) || !Number.isFinite(focal)) {
|
|
9272
|
-
throw new Error(`camera.intrinsics.${name} must be a positive, finite focal length`);
|
|
9273
|
-
}
|
|
9274
|
-
}
|
|
9275
|
-
for (const [name, principal, extent] of [
|
|
9276
|
-
["cx", intrinsics.cx, "width"],
|
|
9277
|
-
["cy", intrinsics.cy, "height"]
|
|
9278
|
-
]) {
|
|
9279
|
-
if (!(principal >= 0 && principal <= 1)) {
|
|
9280
|
-
throw new Error(`camera.intrinsics.${name} must be within [0, 1] of the frame ${extent}`);
|
|
9281
|
-
}
|
|
9282
|
-
}
|
|
9283
|
-
}
|
|
9284
|
-
if (camera.distortion !== void 0) {
|
|
9285
|
-
for (const name of ["k1", "k2", "p1", "p2", "k3"]) {
|
|
9286
|
-
if (!isFinite_(camera.distortion[name])) {
|
|
9287
|
-
throw new Error(`camera.distortion.${name} must be a finite number`);
|
|
9288
|
-
}
|
|
9289
|
-
}
|
|
9290
|
-
}
|
|
9291
|
-
if (camera.extrinsics !== void 0) {
|
|
9292
|
-
const translation = camera.extrinsics.translation;
|
|
9293
|
-
if (translation !== void 0) {
|
|
9294
|
-
for (const axis of ["x", "y", "z"]) {
|
|
9295
|
-
if (!Number.isFinite(translation[axis])) {
|
|
9296
|
-
throw new Error(`camera.extrinsics.translation.${axis} must be a finite number`);
|
|
9297
|
-
}
|
|
9298
|
-
}
|
|
9299
|
-
}
|
|
9300
|
-
const rotation = camera.extrinsics.rotation;
|
|
9301
|
-
if (rotation !== void 0) {
|
|
9302
|
-
const norm = Math.sqrt(rotation.w ** 2 + rotation.x ** 2 + rotation.y ** 2 + rotation.z ** 2);
|
|
9303
|
-
if (!(Math.abs(norm - 1) <= QUATERNION_TOLERANCE)) {
|
|
9304
|
-
throw new Error("camera.extrinsics.rotation must be a unit quaternion");
|
|
9305
|
-
}
|
|
9306
|
-
}
|
|
9307
|
-
}
|
|
9308
|
-
}
|
|
9309
|
-
|
|
9310
|
-
// worker/worker_types.ts
|
|
9311
|
-
var PredictionVersion = /* @__PURE__ */ ((PredictionVersion3) => {
|
|
9312
|
-
PredictionVersion3[PredictionVersion3["V1"] = 1] = "V1";
|
|
9313
|
-
PredictionVersion3[PredictionVersion3["V2"] = 2] = "V2";
|
|
9314
|
-
PredictionVersion3[PredictionVersion3["V3"] = 3] = "V3";
|
|
9315
|
-
return PredictionVersion3;
|
|
9316
|
-
})(PredictionVersion || {});
|
|
9317
|
-
var DEFAULT_PREDICTION_VERSION = 2 /* V2 */;
|
|
9318
|
-
var VideoMode = /* @__PURE__ */ ((VideoMode2) => {
|
|
9319
|
-
VideoMode2["STREAM"] = "stream";
|
|
9320
|
-
VideoMode2["BUFFER"] = "buffer";
|
|
9321
|
-
return VideoMode2;
|
|
9322
|
-
})(VideoMode || {});
|
|
9323
|
-
var PopComponentType = /* @__PURE__ */ ((PopComponentType2) => {
|
|
9324
|
-
PopComponentType2["FORWARD"] = "forward";
|
|
9325
|
-
PopComponentType2["INFERENCE"] = "inference";
|
|
9326
|
-
PopComponentType2["TRACKING"] = "tracking";
|
|
9327
|
-
PopComponentType2["CONTOUR_FINDER"] = "contour_finder";
|
|
9328
|
-
PopComponentType2["COMPONENT_FINDER"] = "component_finder";
|
|
9329
|
-
return PopComponentType2;
|
|
9330
|
-
})(PopComponentType || {});
|
|
9331
|
-
var ForwardOperatorType = /* @__PURE__ */ ((ForwardOperatorType2) => {
|
|
9332
|
-
ForwardOperatorType2["FULL"] = "full";
|
|
9333
|
-
ForwardOperatorType2["CROP"] = "crop";
|
|
9334
|
-
ForwardOperatorType2["CROP_WITH_FULL_FALLBACK"] = "crop_with_full_fallback";
|
|
9335
|
-
ForwardOperatorType2["SELECT_CROP"] = "select_crop";
|
|
9336
|
-
ForwardOperatorType2["SELECT_FULL"] = "select_full";
|
|
9337
|
-
return ForwardOperatorType2;
|
|
9338
|
-
})(ForwardOperatorType || {});
|
|
9339
|
-
var SelectMode = /* @__PURE__ */ ((SelectMode2) => {
|
|
9340
|
-
SelectMode2["MOST_RELEVANT"] = "most_relevant";
|
|
9341
|
-
return SelectMode2;
|
|
9342
|
-
})(SelectMode || {});
|
|
9343
|
-
function isSelectOperator(operator) {
|
|
9344
|
-
return operator?.type === "select_crop" /* SELECT_CROP */ || operator?.type === "select_full" /* SELECT_FULL */;
|
|
9345
|
-
}
|
|
9346
|
-
var InferenceType = /* @__PURE__ */ ((InferenceType2) => {
|
|
9347
|
-
InferenceType2["IMAGE_CLASSIFICATION"] = "image_classification";
|
|
9348
|
-
InferenceType2["OBJECT_DETECTION"] = "object_detection";
|
|
9349
|
-
InferenceType2["KEY_POINTS"] = "key_points";
|
|
9350
|
-
InferenceType2["OCR"] = "ocr";
|
|
9351
|
-
InferenceType2["MESH"] = "mesh";
|
|
9352
|
-
InferenceType2["FEATURE_VECTOR"] = "feature_vector";
|
|
9353
|
-
InferenceType2["SEMANTIC_SEGMENTATION"] = "semantic_segmentation";
|
|
9354
|
-
InferenceType2["SEGMENTATION"] = "segmentation";
|
|
9355
|
-
return InferenceType2;
|
|
9356
|
-
})(InferenceType || {});
|
|
9357
|
-
var MotionModel = /* @__PURE__ */ ((MotionModel2) => {
|
|
9358
|
-
MotionModel2["RANDOM_WALK"] = "random_walk";
|
|
9359
|
-
MotionModel2["CONSTANT_VELOCITY"] = "constant_velocity";
|
|
9360
|
-
MotionModel2["CONSTANT_ACCELERATION"] = "constant_acceleration";
|
|
9361
|
-
return MotionModel2;
|
|
9362
|
-
})(MotionModel || {});
|
|
9363
|
-
var ContourType = /* @__PURE__ */ ((ContourType2) => {
|
|
9364
|
-
ContourType2["ALL_PIXELS"] = "all_pixels";
|
|
9365
|
-
ContourType2["POLYGON"] = "polygon";
|
|
9366
|
-
ContourType2["CONVEX_HULL"] = "convex_hull";
|
|
9367
|
-
ContourType2["HOUGH_CIRCLES"] = "hough_circles";
|
|
9368
|
-
ContourType2["CIRCLE"] = "circle";
|
|
9369
|
-
ContourType2["TRIANGLE"] = "triangle";
|
|
9370
|
-
ContourType2["RECTANGLE"] = "rectangle";
|
|
9371
|
-
return ContourType2;
|
|
9372
|
-
})(ContourType || {});
|
|
9373
|
-
function validatePop(pop) {
|
|
9374
|
-
if (pop.depthMap !== void 0) {
|
|
9375
|
-
if (pop.depthMap.ability === void 0 === (pop.depthMap.abilityUuid === void 0)) {
|
|
9376
|
-
throw new Error("depthMap requires exactly one of ability or abilityUuid");
|
|
9377
|
-
}
|
|
9378
|
-
}
|
|
9379
|
-
if (pop.defaults?.camera !== void 0) {
|
|
9380
|
-
validateCamera(pop.defaults.camera);
|
|
9381
|
-
}
|
|
9382
|
-
validateForwards(pop.components);
|
|
9383
|
-
}
|
|
9384
|
-
function popSelects(pop) {
|
|
9385
|
-
const selects = (components) => (components ?? []).some((component) => isSelectOperator(component.forward?.operator) || selects(component.forward?.targets));
|
|
9386
|
-
return selects(pop?.components);
|
|
9387
|
-
}
|
|
9388
|
-
function validateForwards(components) {
|
|
9389
|
-
for (const component of components ?? []) {
|
|
9390
|
-
const operator = component.forward?.operator;
|
|
9391
|
-
if (operator !== void 0) {
|
|
9392
|
-
validateSelectOperator(operator);
|
|
9393
|
-
}
|
|
9394
|
-
validateForwards(component.forward?.targets);
|
|
9395
|
-
}
|
|
9396
|
-
}
|
|
9397
|
-
function validateSelectOperator(operator) {
|
|
9398
|
-
if (!isSelectOperator(operator)) {
|
|
9399
|
-
if (operator.select !== void 0) {
|
|
9400
|
-
throw new Error("select is only valid with the select_crop or select_full operator");
|
|
9401
|
-
}
|
|
9402
|
-
return;
|
|
9403
|
-
}
|
|
9404
|
-
const select = operator.select;
|
|
9405
|
-
if (select === void 0) {
|
|
9406
|
-
throw new Error(`${operator.type} requires a select block`);
|
|
9407
|
-
}
|
|
9408
|
-
if (select.mode !== void 0 && select.mode !== "most_relevant" /* MOST_RELEVANT */) {
|
|
9409
|
-
throw new Error(`select mode ${select.mode} is not supported, the only mode is ${"most_relevant" /* MOST_RELEVANT */}`);
|
|
9410
|
-
}
|
|
9411
|
-
if (select.relevancyModel !== void 0 && select.relevancyModelUuid !== void 0) {
|
|
9412
|
-
throw new Error("select can only have one of relevancyModelUuid or relevancyModel");
|
|
9413
|
-
}
|
|
9414
|
-
if (select.minTrackLengthSeconds !== void 0 && select.minTrackLengthSeconds < 0) {
|
|
9415
|
-
throw new Error("select minTrackLengthSeconds cannot be negative");
|
|
9416
|
-
}
|
|
9417
|
-
if (select.intervalSeconds !== void 0 && select.intervalSeconds <= 0) {
|
|
9418
|
-
throw new Error("select intervalSeconds must be positive");
|
|
9419
|
-
}
|
|
9420
|
-
if (operator.crop !== void 0) {
|
|
9421
|
-
if (operator.type !== "select_crop" /* SELECT_CROP */) {
|
|
9422
|
-
throw new Error(`crop options are only valid with select_crop, not ${operator.type}`);
|
|
9423
|
-
}
|
|
9424
|
-
if (operator.crop.maxItems !== void 0) {
|
|
9425
|
-
throw new Error("select_crop forwards one detection per selection, maxItems does not apply");
|
|
9426
|
-
}
|
|
9427
|
-
}
|
|
9428
|
-
}
|
|
9429
|
-
|
|
9430
9905
|
// worker/webrtc_whip.ts
|
|
9431
9906
|
import { v4 as uuidv42 } from "uuid";
|
|
9432
9907
|
|
|
@@ -10157,7 +10632,7 @@ var UploadGroupJob = class extends AbstractJob {
|
|
|
10157
10632
|
parts.push({ name: "camera", contentType: "application/json", content: JSON.stringify(this._params.camera) });
|
|
10158
10633
|
}
|
|
10159
10634
|
for (const source of this._sources) {
|
|
10160
|
-
parts.push({ name: "file", contentType: source.mimeType, content: source.stream });
|
|
10635
|
+
parts.push({ name: "file", filename: "blob", contentType: source.mimeType, content: source.stream });
|
|
10161
10636
|
}
|
|
10162
10637
|
const boundary = randomMultipartBoundary();
|
|
10163
10638
|
const headers = {
|
|
@@ -10351,1310 +10826,1671 @@ if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
|
10351
10826
|
const mime = require_mime_types();
|
|
10352
10827
|
const filehandle = __require("fs/promises");
|
|
10353
10828
|
const fd = await filehandle.open(source.path, "r");
|
|
10829
|
+
const size = (await fd.stat()).size;
|
|
10354
10830
|
const stream = fd.createReadStream();
|
|
10355
10831
|
const iterator = nodeStreamToIterator(stream);
|
|
10356
10832
|
const webStream = iteratorToStream(iterator);
|
|
10357
|
-
const mimeType = source.mimeType ? source.mimeType : mime.lookup(source.path) || "image/*";
|
|
10358
|
-
return {
|
|
10359
|
-
stream: webStream,
|
|
10360
|
-
mimeType
|
|
10361
|
-
|
|
10362
|
-
|
|
10363
|
-
}
|
|
10364
|
-
var iteratorToStream2;
|
|
10365
|
-
|
|
10366
|
-
// shims/http_client.ts
|
|
10367
|
-
var createHttpClient;
|
|
10368
|
-
function logLineFromRequest(input, init) {
|
|
10369
|
-
const url = input instanceof Request ? input.url : input;
|
|
10370
|
-
const method = input instanceof Request ? input.method : init?.method || (init?.body !== void 0 ? "POST" : "GET");
|
|
10371
|
-
return `${method} ${url}`;
|
|
10372
|
-
}
|
|
10373
|
-
if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
10374
|
-
class BrowserHttpClient {
|
|
10375
|
-
constructor(logger) {
|
|
10376
|
-
this._logger = logger;
|
|
10377
|
-
}
|
|
10378
|
-
async fetch(input, init) {
|
|
10379
|
-
const logLine = logLineFromRequest(input, init);
|
|
10380
|
-
this._logger.debug(`Browser fetch() BEFORE ${logLine}`);
|
|
10381
|
-
const response = await fetch(input, init);
|
|
10382
|
-
this._logger.debug(`AFTER ${logLine} -> ${response.status}`);
|
|
10383
|
-
return response;
|
|
10384
|
-
}
|
|
10385
|
-
async close() {
|
|
10386
|
-
}
|
|
10387
|
-
isFullDuplex() {
|
|
10388
|
-
return false;
|
|
10389
|
-
}
|
|
10390
|
-
}
|
|
10391
|
-
createHttpClient = async (logger) => {
|
|
10392
|
-
return new BrowserHttpClient(logger);
|
|
10393
|
-
};
|
|
10394
|
-
} else {
|
|
10395
|
-
class NodeHttpClient {
|
|
10396
|
-
constructor(agent, fetchFn, logger) {
|
|
10397
|
-
this._agent = agent;
|
|
10398
|
-
this._fetch = fetchFn;
|
|
10399
|
-
this._logger = logger;
|
|
10400
|
-
}
|
|
10401
|
-
async fetch(input, init) {
|
|
10402
|
-
init || (init = {});
|
|
10403
|
-
init.dispatcher = this._agent;
|
|
10404
|
-
const logLine = logLineFromRequest(input, init);
|
|
10405
|
-
this._logger.debug(`Node fetch() BEFORE ${logLine}`);
|
|
10406
|
-
const response = await this._fetch(input, init);
|
|
10407
|
-
this._logger.debug(`AFTER ${logLine} -> ${response.status}`);
|
|
10408
|
-
return response;
|
|
10409
|
-
}
|
|
10410
|
-
async close() {
|
|
10411
|
-
return this._agent.close();
|
|
10412
|
-
}
|
|
10413
|
-
isFullDuplex() {
|
|
10414
|
-
return false;
|
|
10415
|
-
}
|
|
10416
|
-
}
|
|
10417
|
-
createHttpClient = async (logger) => {
|
|
10418
|
-
const undici = __require("undici");
|
|
10419
|
-
const agent = new undici.Agent({
|
|
10420
|
-
keepAliveTimeout: 1e4,
|
|
10421
|
-
connections: 5,
|
|
10422
|
-
// two parallel streaming requests to the same host seem to deadlock with pipelining > 0
|
|
10423
|
-
pipelining: 0
|
|
10424
|
-
});
|
|
10425
|
-
logger.debug("Using node fetch with undici agent as http client");
|
|
10426
|
-
return new NodeHttpClient(agent, undici.fetch, logger);
|
|
10833
|
+
const mimeType = source.mimeType ? source.mimeType : mime.lookup(source.path) || "image/*";
|
|
10834
|
+
return {
|
|
10835
|
+
stream: webStream,
|
|
10836
|
+
mimeType,
|
|
10837
|
+
size
|
|
10838
|
+
};
|
|
10427
10839
|
};
|
|
10428
10840
|
}
|
|
10841
|
+
var iteratorToStream2;
|
|
10429
10842
|
|
|
10430
|
-
//
|
|
10431
|
-
var
|
|
10432
|
-
|
|
10433
|
-
|
|
10434
|
-
|
|
10435
|
-
|
|
10436
|
-
|
|
10437
|
-
|
|
10438
|
-
constructor(
|
|
10439
|
-
this.
|
|
10440
|
-
this.
|
|
10441
|
-
|
|
10442
|
-
|
|
10443
|
-
|
|
10444
|
-
|
|
10445
|
-
|
|
10446
|
-
|
|
10447
|
-
|
|
10448
|
-
|
|
10449
|
-
/**
|
|
10450
|
-
* Returns a promise used to wait for a permit to become available. This method should be awaited on.
|
|
10451
|
-
* @returns A promise that gets resolved when execution is allowed to proceed.
|
|
10452
|
-
*/
|
|
10453
|
-
async wait() {
|
|
10454
|
-
if (this.permits > 0) {
|
|
10455
|
-
this.permits -= 1;
|
|
10456
|
-
return Promise.resolve(true);
|
|
10457
|
-
}
|
|
10458
|
-
return new Promise((resolver) => this.promiseResolverQueue.push(resolver));
|
|
10843
|
+
// worker/worker_options.ts
|
|
10844
|
+
var TransientPopId = /* @__PURE__ */ ((TransientPopId2) => {
|
|
10845
|
+
TransientPopId2["Transient"] = "transient";
|
|
10846
|
+
return TransientPopId2;
|
|
10847
|
+
})(TransientPopId || {});
|
|
10848
|
+
|
|
10849
|
+
// worker/session_backend.ts
|
|
10850
|
+
var _SessionBackend = class _SessionBackend {
|
|
10851
|
+
constructor(ctx) {
|
|
10852
|
+
this.ctx = ctx;
|
|
10853
|
+
this._baseUrl = null;
|
|
10854
|
+
this._pipelineId = null;
|
|
10855
|
+
this._popName = null;
|
|
10856
|
+
this._sessionAccessToken = null;
|
|
10857
|
+
this._sessionAccessTokenValidUntil = null;
|
|
10858
|
+
// The account the connected compute session runs under, as compute-api reports it.
|
|
10859
|
+
this._accountId = void 0;
|
|
10860
|
+
this._pipeline = null;
|
|
10861
|
+
this._pipelineCreatePromise = null;
|
|
10459
10862
|
}
|
|
10460
|
-
|
|
10461
|
-
|
|
10462
|
-
|
|
10463
|
-
*/
|
|
10464
|
-
async acquire() {
|
|
10465
|
-
return this.wait();
|
|
10863
|
+
async disconnect(closeEndpoint) {
|
|
10864
|
+
await this.deleteOwnPipeline();
|
|
10865
|
+
await closeEndpoint();
|
|
10466
10866
|
}
|
|
10467
|
-
|
|
10468
|
-
|
|
10469
|
-
|
|
10470
|
-
|
|
10471
|
-
|
|
10472
|
-
|
|
10473
|
-
|
|
10474
|
-
|
|
10475
|
-
|
|
10476
|
-
|
|
10477
|
-
|
|
10478
|
-
|
|
10479
|
-
|
|
10480
|
-
|
|
10481
|
-
const promise = new Promise((r) => {
|
|
10482
|
-
resolver = r;
|
|
10483
|
-
});
|
|
10484
|
-
this.promiseResolverQueue.push(resolver);
|
|
10485
|
-
setTimeout(() => {
|
|
10486
|
-
const index = this.promiseResolverQueue.indexOf(resolver);
|
|
10487
|
-
if (index !== -1) {
|
|
10488
|
-
this.promiseResolverQueue.splice(index, 1);
|
|
10489
|
-
} else {
|
|
10490
|
-
console.warn(`Semaphore.waitFor couldn't find its promise resolver in the queue`);
|
|
10867
|
+
async deleteOwnPipeline() {
|
|
10868
|
+
const client = this.ctx.client();
|
|
10869
|
+
if (this.ctx.options.popId == "transient" /* Transient */ && this._pipelineId && client) {
|
|
10870
|
+
const deleteUrl = `${this._baseUrl}/pipelines/${this._pipelineId}`;
|
|
10871
|
+
const headers = {
|
|
10872
|
+
Authorization: await this.authorizationHeader()
|
|
10873
|
+
};
|
|
10874
|
+
let response = await client.fetch(deleteUrl, {
|
|
10875
|
+
method: "DELETE",
|
|
10876
|
+
headers
|
|
10877
|
+
});
|
|
10878
|
+
if (response?.status != 204) {
|
|
10879
|
+
const message = await response?.text();
|
|
10880
|
+
this.ctx.logger.info(`stopping pipeline failed, status ${response?.status}: ${message}`);
|
|
10491
10881
|
}
|
|
10492
|
-
resolver(false);
|
|
10493
|
-
}, milliseconds);
|
|
10494
|
-
return promise;
|
|
10495
|
-
}
|
|
10496
|
-
/**
|
|
10497
|
-
* Synchronous function that tries to acquire a permit and returns true if successful, false otherwise.
|
|
10498
|
-
* @returns Whether a permit could be acquired.
|
|
10499
|
-
*/
|
|
10500
|
-
tryAcquire() {
|
|
10501
|
-
if (this.permits > 0) {
|
|
10502
|
-
this.permits -= 1;
|
|
10503
|
-
return true;
|
|
10504
10882
|
}
|
|
10505
|
-
return false;
|
|
10506
10883
|
}
|
|
10507
|
-
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
drainPermits() {
|
|
10512
|
-
if (this.permits > 0) {
|
|
10513
|
-
const permitCount = this.permits;
|
|
10514
|
-
this.permits = 0;
|
|
10515
|
-
return permitCount;
|
|
10884
|
+
onStatus(statusCode) {
|
|
10885
|
+
if (statusCode == 404) {
|
|
10886
|
+
this._pipelineId = null;
|
|
10887
|
+
this._baseUrl = null;
|
|
10516
10888
|
}
|
|
10517
|
-
return 0;
|
|
10518
10889
|
}
|
|
10519
|
-
|
|
10520
|
-
|
|
10521
|
-
|
|
10522
|
-
|
|
10523
|
-
|
|
10524
|
-
|
|
10525
|
-
if (this.permits > 1 && this.promiseResolverQueue.length > 0) {
|
|
10526
|
-
console.warn("Semaphore.permits should never be > 0 when there is someone waiting.");
|
|
10527
|
-
} else if (this.permits === 1 && this.promiseResolverQueue.length > 0) {
|
|
10528
|
-
this.permits -= 1;
|
|
10529
|
-
const nextResolver = this.promiseResolverQueue.shift();
|
|
10530
|
-
if (nextResolver) {
|
|
10531
|
-
nextResolver(true);
|
|
10890
|
+
async session() {
|
|
10891
|
+
let session = null;
|
|
10892
|
+
if (this._baseUrl == null) {
|
|
10893
|
+
await this.reconnect();
|
|
10894
|
+
if (this._baseUrl == null) {
|
|
10895
|
+
return Promise.reject("endpoint not connected");
|
|
10532
10896
|
}
|
|
10533
10897
|
}
|
|
10898
|
+
if (this._sessionAccessToken) {
|
|
10899
|
+
session = {
|
|
10900
|
+
eyepopUrl: this.ctx.options.eyepopUrl,
|
|
10901
|
+
accessToken: this._sessionAccessToken,
|
|
10902
|
+
validUntil: this._sessionAccessTokenValidUntil || Number.MAX_VALUE
|
|
10903
|
+
};
|
|
10904
|
+
} else {
|
|
10905
|
+
session = await this.ctx.credentialSession();
|
|
10906
|
+
}
|
|
10907
|
+
return {
|
|
10908
|
+
eyepopUrl: session.eyepopUrl,
|
|
10909
|
+
accessToken: session.accessToken,
|
|
10910
|
+
validUntil: session.validUntil,
|
|
10911
|
+
popId: this.ctx.options.popId,
|
|
10912
|
+
accountId: this._accountId ?? this.ctx.options.accountId,
|
|
10913
|
+
baseUrl: this._baseUrl,
|
|
10914
|
+
pipelineId: this._pipelineId || void 0,
|
|
10915
|
+
isPipelineMode: false,
|
|
10916
|
+
authenticationHeaders: () => this._authenticationHeaders(session)
|
|
10917
|
+
};
|
|
10534
10918
|
}
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
|
|
10539
|
-
this.
|
|
10919
|
+
popName() {
|
|
10920
|
+
return this._popName;
|
|
10921
|
+
}
|
|
10922
|
+
pop() {
|
|
10923
|
+
if (this._pipeline) {
|
|
10924
|
+
return this._pipeline.pop || null;
|
|
10925
|
+
}
|
|
10926
|
+
return this.ctx.options.pop || null;
|
|
10540
10927
|
}
|
|
10541
10928
|
/**
|
|
10542
|
-
*
|
|
10543
|
-
*
|
|
10544
|
-
*
|
|
10545
|
-
* @param func The function to be executed.
|
|
10546
|
-
* @return A promise that gets resolved with the return value of the function.
|
|
10929
|
+
* A select forward's results come only at V3. Only a Pop that selects asks
|
|
10930
|
+
* for it, so a worker too old to know V3 - which also rejects that Pop - is
|
|
10931
|
+
* never sent a version it would not accept.
|
|
10547
10932
|
*/
|
|
10548
|
-
|
|
10549
|
-
|
|
10550
|
-
try {
|
|
10551
|
-
return await func();
|
|
10552
|
-
} finally {
|
|
10553
|
-
this.signal();
|
|
10554
|
-
}
|
|
10933
|
+
predictionVersion() {
|
|
10934
|
+
return popSelects(this.pop()) ? 3 /* V3 */ : DEFAULT_PREDICTION_VERSION;
|
|
10555
10935
|
}
|
|
10556
|
-
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
|
|
10560
|
-
|
|
10561
|
-
// shims/browser_session.ts
|
|
10562
|
-
import { createAuth0Client } from "@auth0/auth0-spa-js";
|
|
10563
|
-
var authenticateBrowserSession;
|
|
10564
|
-
if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
10565
|
-
authenticateBrowserSession = async (auth0, options) => {
|
|
10566
|
-
if (options.eyepopUrl == null) {
|
|
10567
|
-
return Promise.reject("options.eyepopUrl cannot be null");
|
|
10568
|
-
}
|
|
10569
|
-
const auth0ClientOptions = {
|
|
10570
|
-
clientId: auth0.clientId,
|
|
10571
|
-
domain: auth0.domain,
|
|
10572
|
-
authorizationParams: {
|
|
10573
|
-
scope: auth0.scope,
|
|
10574
|
-
audience: auth0.audience
|
|
10575
|
-
}
|
|
10576
|
-
};
|
|
10577
|
-
const auth0Client = await createAuth0Client(auth0ClientOptions);
|
|
10578
|
-
if (!await auth0Client.isAuthenticated()) {
|
|
10579
|
-
await auth0Client.loginWithPopup();
|
|
10580
|
-
}
|
|
10581
|
-
const accessToken = await auth0Client.getTokenSilently();
|
|
10582
|
-
if (!accessToken) {
|
|
10583
|
-
return Promise.reject("auth0 login failed");
|
|
10936
|
+
async changePop(pop) {
|
|
10937
|
+
if (this.ctx.options.popId == "transient" /* Transient */) {
|
|
10938
|
+
await this.changeTransientPop(pop);
|
|
10939
|
+
return;
|
|
10584
10940
|
}
|
|
10585
|
-
|
|
10586
|
-
const
|
|
10587
|
-
if (
|
|
10588
|
-
|
|
10589
|
-
eyepopUrl: options.eyepopUrl,
|
|
10590
|
-
accessToken,
|
|
10591
|
-
validUntil: Date.now() + 60 * 60 * 1e3,
|
|
10592
|
-
popId: workerOptions.popId,
|
|
10593
|
-
baseUrl: void 0,
|
|
10594
|
-
pipelineId: void 0,
|
|
10595
|
-
authenticationHeaders: () => {
|
|
10596
|
-
return { Authorization: `Bearer ${accessToken}` };
|
|
10597
|
-
}
|
|
10598
|
-
};
|
|
10599
|
-
session = workerSession;
|
|
10600
|
-
} else {
|
|
10601
|
-
session = {
|
|
10602
|
-
eyepopUrl: options.eyepopUrl,
|
|
10603
|
-
accessToken,
|
|
10604
|
-
validUntil: Date.now() + 60 * 60 * 1e3
|
|
10605
|
-
};
|
|
10941
|
+
const client = this.ctx.client();
|
|
10942
|
+
const baseUrl = this._baseUrl;
|
|
10943
|
+
if (!baseUrl || !client) {
|
|
10944
|
+
return Promise.reject("endpoint not connected, use connect()");
|
|
10606
10945
|
}
|
|
10607
|
-
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
}
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
10619
|
-
|
|
10620
|
-
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
this.
|
|
10625
|
-
this.
|
|
10626
|
-
|
|
10627
|
-
this._stateChangeHandler = null;
|
|
10628
|
-
let rootLogger;
|
|
10629
|
-
if (options.logger) {
|
|
10630
|
-
rootLogger = options.logger;
|
|
10946
|
+
let response = await this.ctx.fetchWithRetry(async () => {
|
|
10947
|
+
const session = await this.session();
|
|
10948
|
+
let headers = {
|
|
10949
|
+
"Content-Type": "application/json",
|
|
10950
|
+
...this._authenticationHeaders(session)
|
|
10951
|
+
};
|
|
10952
|
+
const patch_url = `${session.baseUrl}/pipelines/${session.pipelineId}/pop`;
|
|
10953
|
+
return await client.fetch(patch_url, {
|
|
10954
|
+
method: "PATCH",
|
|
10955
|
+
body: JSON.stringify(pop),
|
|
10956
|
+
headers
|
|
10957
|
+
});
|
|
10958
|
+
});
|
|
10959
|
+
if (response.status != 204) {
|
|
10960
|
+
const message = await response.text();
|
|
10961
|
+
throw new Error(`Unexpected status ${response.status}: ${message}`);
|
|
10962
|
+
}
|
|
10963
|
+
this.ctx.options.pop = pop;
|
|
10964
|
+
if (this._pipeline) {
|
|
10965
|
+
this._pipeline.pop = pop;
|
|
10631
10966
|
} else {
|
|
10632
|
-
|
|
10967
|
+
this._pipeline = {
|
|
10968
|
+
id: this._pipelineId || "unknown",
|
|
10969
|
+
state: "idle",
|
|
10970
|
+
startTime: (/* @__PURE__ */ new Date()).toString(),
|
|
10971
|
+
pop
|
|
10972
|
+
};
|
|
10633
10973
|
}
|
|
10634
|
-
this._logger = rootLogger.child({ module: "eyepop" });
|
|
10635
|
-
this._requestLogger = this._logger.child({ module: "requests" });
|
|
10636
10974
|
}
|
|
10637
|
-
|
|
10638
|
-
this.
|
|
10639
|
-
this._statusRetryHandlers.set(401, this.statusHandler401);
|
|
10975
|
+
_authenticationHeaders(session) {
|
|
10976
|
+
return resolveAuth(this.ctx.options)?.isLocal !== void 0 ? {} : { Authorization: `Bearer ${session.accessToken}` };
|
|
10640
10977
|
}
|
|
10641
|
-
|
|
10642
|
-
|
|
10643
|
-
|
|
10644
|
-
|
|
10645
|
-
|
|
10978
|
+
async submit(work) {
|
|
10979
|
+
switch (work.kind) {
|
|
10980
|
+
case "source":
|
|
10981
|
+
return await this.process(work.source, work.params);
|
|
10982
|
+
case "uploadGroup":
|
|
10983
|
+
return await this.uploadGroup(work.paths, work.params);
|
|
10984
|
+
case "uploadStreamGroup":
|
|
10985
|
+
return await this.uploadStreamGroup(work.streams, work.mimeTypes, work.params);
|
|
10986
|
+
case "loadFromGroup":
|
|
10987
|
+
return await this.loadFromGroup(work.urls, work.params);
|
|
10646
10988
|
}
|
|
10647
10989
|
}
|
|
10648
|
-
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
|
|
10990
|
+
async process(source, params) {
|
|
10991
|
+
if (source.file !== void 0) {
|
|
10992
|
+
return this.uploadFile(source, params);
|
|
10993
|
+
} else if (source.stream !== void 0) {
|
|
10994
|
+
return this.uploadStream(source, params);
|
|
10995
|
+
} else if (source.path !== void 0) {
|
|
10996
|
+
return this.uploadPath(source, params);
|
|
10997
|
+
} else if (source.url !== void 0) {
|
|
10998
|
+
return this.loadFrom(source, params);
|
|
10999
|
+
} else if (source.assetUuid !== void 0) {
|
|
11000
|
+
return this.loadFromAssetUuid(source, params);
|
|
11001
|
+
} else if (source.mediaStream !== void 0) {
|
|
11002
|
+
return this.loadMediaStream(source, params);
|
|
10652
11003
|
} else {
|
|
10653
|
-
return
|
|
11004
|
+
return Promise.reject("unknown source type");
|
|
10654
11005
|
}
|
|
10655
11006
|
}
|
|
10656
|
-
|
|
10657
|
-
return
|
|
10658
|
-
|
|
10659
|
-
|
|
10660
|
-
|
|
10661
|
-
|
|
10662
|
-
|
|
10663
|
-
|
|
10664
|
-
|
|
10665
|
-
|
|
10666
|
-
|
|
10667
|
-
return this;
|
|
10668
|
-
}
|
|
10669
|
-
updateState(newState = void 0, message = void 0) {
|
|
10670
|
-
const fromState = this._state;
|
|
10671
|
-
if (newState == void 0) {
|
|
10672
|
-
if (this._limit.getPermits() == this._options.jobQueueLength) {
|
|
10673
|
-
newState = "Idle" /* Idle */;
|
|
10674
|
-
} else {
|
|
10675
|
-
newState = "Busy" /* Busy */;
|
|
11007
|
+
start(job) {
|
|
11008
|
+
return job.start(
|
|
11009
|
+
() => {
|
|
11010
|
+
this.ctx.jobDone();
|
|
11011
|
+
},
|
|
11012
|
+
(statusCode) => {
|
|
11013
|
+
if (statusCode == 404) {
|
|
11014
|
+
this.onStatus(statusCode);
|
|
11015
|
+
} else if (statusCode == 401) {
|
|
11016
|
+
this.ctx.forgetCredential();
|
|
11017
|
+
}
|
|
10676
11018
|
}
|
|
10677
|
-
|
|
10678
|
-
this._state = newState;
|
|
10679
|
-
this._message = message ? message : null;
|
|
10680
|
-
if (this._stateChangeHandler) {
|
|
10681
|
-
this._stateChangeHandler(fromState, this._state);
|
|
10682
|
-
}
|
|
11019
|
+
);
|
|
10683
11020
|
}
|
|
10684
|
-
async
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
if (!this._options.eyepopUrl) {
|
|
10690
|
-
return Promise.reject("option eyepopUrl or environment variable EYEPOP_URL is required");
|
|
11021
|
+
async uploadGroup(paths, params) {
|
|
11022
|
+
const client = this.ctx.client();
|
|
11023
|
+
const limit = this.ctx.limit();
|
|
11024
|
+
if (!this._baseUrl || !this._pipelineId || !client) {
|
|
11025
|
+
throw new Error("endpoint not connected, use connect()");
|
|
10691
11026
|
}
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
|
-
|
|
11027
|
+
await limit.acquire();
|
|
11028
|
+
try {
|
|
11029
|
+
this.ctx.updateState();
|
|
11030
|
+
const sources = await Promise.all(
|
|
11031
|
+
paths.map(async (path2) => {
|
|
11032
|
+
const streamSource = await this.resolvePath({ path: path2 });
|
|
11033
|
+
return { stream: streamSource.stream, mimeType: streamSource.mimeType };
|
|
11034
|
+
})
|
|
11035
|
+
);
|
|
11036
|
+
return this.start(new UploadGroupJob(sources, params, async () => this.session(), client, this.ctx.requestLogger, this.predictionVersion()));
|
|
11037
|
+
} catch (e) {
|
|
11038
|
+
limit.release();
|
|
11039
|
+
throw e;
|
|
10695
11040
|
}
|
|
10696
|
-
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
|
|
10702
|
-
} else if (auth.isLocal !== void 0) {
|
|
10703
|
-
} else {
|
|
10704
|
-
return Promise.reject("option apiKey/accessToken or environment variable EYEPOP_API_KEY is required");
|
|
11041
|
+
}
|
|
11042
|
+
async uploadStreamGroup(streams, mimeTypes, params) {
|
|
11043
|
+
const client = this.ctx.client();
|
|
11044
|
+
const limit = this.ctx.limit();
|
|
11045
|
+
if (!this._baseUrl || !this._pipelineId || !client) {
|
|
11046
|
+
throw new Error("endpoint not connected, use connect()");
|
|
10705
11047
|
}
|
|
10706
|
-
|
|
10707
|
-
|
|
10708
|
-
|
|
10709
|
-
|
|
11048
|
+
await limit.acquire();
|
|
11049
|
+
try {
|
|
11050
|
+
this.ctx.updateState();
|
|
11051
|
+
const sources = streams.map((stream, i) => ({
|
|
11052
|
+
stream,
|
|
11053
|
+
mimeType: mimeTypes?.[i] ?? null
|
|
11054
|
+
}));
|
|
11055
|
+
return this.start(new UploadGroupJob(sources, params, async () => this.session(), client, this.ctx.requestLogger, this.predictionVersion()));
|
|
11056
|
+
} catch (e) {
|
|
11057
|
+
limit.release();
|
|
11058
|
+
throw e;
|
|
10710
11059
|
}
|
|
10711
|
-
return await this.reconnect();
|
|
10712
11060
|
}
|
|
10713
|
-
async
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
11061
|
+
async loadFromGroup(urls, params) {
|
|
11062
|
+
const client = this.ctx.client();
|
|
11063
|
+
const limit = this.ctx.limit();
|
|
11064
|
+
if (!this._baseUrl || !this._pipelineId || !client) {
|
|
11065
|
+
throw new Error("endpoint not connected, use connect()");
|
|
10718
11066
|
}
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
this.
|
|
11067
|
+
await limit.acquire();
|
|
11068
|
+
try {
|
|
11069
|
+
this.ctx.updateState();
|
|
11070
|
+
return this.start(new LoadFromGroupJob(urls, params, async () => this.session(), client, this.ctx.requestLogger, this.predictionVersion()));
|
|
11071
|
+
} catch (e) {
|
|
11072
|
+
limit.release();
|
|
11073
|
+
throw e;
|
|
10723
11074
|
}
|
|
10724
11075
|
}
|
|
10725
|
-
async
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
return Promise.reject("endpoint not connected");
|
|
11076
|
+
async resolvePath(source) {
|
|
11077
|
+
if (this.ctx.options.platformSupport?.resolvePath) {
|
|
11078
|
+
return await this.ctx.options.platformSupport.resolvePath(source, this.ctx.logger);
|
|
10729
11079
|
}
|
|
10730
|
-
return
|
|
10731
|
-
eyepopUrl: this._options.eyepopUrl,
|
|
10732
|
-
accessToken: this._token,
|
|
10733
|
-
validUntil: this._expire_token_time * 1e3
|
|
10734
|
-
};
|
|
10735
|
-
}
|
|
10736
|
-
statusHandler401(_statusCode) {
|
|
10737
|
-
this._token = null;
|
|
10738
|
-
this._expire_token_time = null;
|
|
11080
|
+
return await resolvePath(source, this.ctx.logger);
|
|
10739
11081
|
}
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
if (handler != null) {
|
|
10749
|
-
handler(response.status);
|
|
10750
|
-
if (retries--) {
|
|
10751
|
-
this._requestLogger.info("received %d response, retry", response.status);
|
|
10752
|
-
} else {
|
|
10753
|
-
return response;
|
|
10754
|
-
}
|
|
10755
|
-
} else {
|
|
10756
|
-
return response;
|
|
10757
|
-
}
|
|
10758
|
-
}
|
|
10759
|
-
} catch (error) {
|
|
10760
|
-
const handler = this._statusRetryHandlers.get(404);
|
|
10761
|
-
if (handler != null) {
|
|
10762
|
-
handler(error);
|
|
10763
|
-
if (retries--) {
|
|
10764
|
-
this._requestLogger.info("error %s, retry", error);
|
|
10765
|
-
} else {
|
|
10766
|
-
return Promise.reject(`error ${error}`);
|
|
10767
|
-
}
|
|
10768
|
-
} else {
|
|
10769
|
-
return Promise.reject(`error ${error}`);
|
|
10770
|
-
}
|
|
11082
|
+
/** Start a job once the transient pipeline runs and a queue permit is held; the permit is released if it cannot start. */
|
|
11083
|
+
async startConnected(makeJob, rejectsWithText = false) {
|
|
11084
|
+
await this.ensureTransientPipelineStarted();
|
|
11085
|
+
const client = this.ctx.client();
|
|
11086
|
+
const limit = this.ctx.limit();
|
|
11087
|
+
if (!this._baseUrl || !this._pipelineId || !client) {
|
|
11088
|
+
if (rejectsWithText) {
|
|
11089
|
+
return Promise.reject("endpoint not connected, use connect()");
|
|
10771
11090
|
}
|
|
11091
|
+
throw new Error("endpoint not connected, use connect()");
|
|
11092
|
+
}
|
|
11093
|
+
await limit.acquire();
|
|
11094
|
+
try {
|
|
11095
|
+
this.ctx.updateState();
|
|
11096
|
+
return this.start(await makeJob(client));
|
|
11097
|
+
} catch (e) {
|
|
11098
|
+
limit.release();
|
|
11099
|
+
throw e;
|
|
10772
11100
|
}
|
|
10773
11101
|
}
|
|
10774
|
-
async
|
|
10775
|
-
|
|
11102
|
+
async uploadFile(source, params) {
|
|
11103
|
+
return await this.startConnected(
|
|
11104
|
+
async (client) => new UploadJob(
|
|
11105
|
+
source.file,
|
|
11106
|
+
source.file.type,
|
|
11107
|
+
source.file.size,
|
|
11108
|
+
source.videoMode,
|
|
11109
|
+
params,
|
|
11110
|
+
async () => this.session(),
|
|
11111
|
+
client,
|
|
11112
|
+
this.ctx.requestLogger,
|
|
11113
|
+
void 0,
|
|
11114
|
+
this.predictionVersion()
|
|
11115
|
+
),
|
|
11116
|
+
true
|
|
11117
|
+
);
|
|
10776
11118
|
}
|
|
10777
|
-
async
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
11119
|
+
async uploadStream(source, params) {
|
|
11120
|
+
return await this.startConnected(
|
|
11121
|
+
async (client) => new UploadJob(source.stream, source.mimeType, source.size, source.videoMode, params, async () => this.session(), client, this.ctx.requestLogger, void 0, this.predictionVersion()),
|
|
11122
|
+
true
|
|
11123
|
+
);
|
|
10782
11124
|
}
|
|
10783
|
-
async
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
|
|
10788
|
-
|
|
10789
|
-
|
|
10790
|
-
return
|
|
10791
|
-
} else if (auth?.isLocal !== void 0) {
|
|
10792
|
-
this._token = "implicit";
|
|
10793
|
-
this._expire_token_time = Number.MAX_VALUE;
|
|
10794
|
-
} else if (auth?.session !== void 0) {
|
|
10795
|
-
return Promise.reject("temporary access token expired");
|
|
10796
|
-
} else if (auth?.oAuth2 !== void 0 && this._options.eyepopUrl) {
|
|
10797
|
-
const session = await authenticateBrowserSession(auth.oAuth2, this._options);
|
|
10798
|
-
this._token = session.accessToken;
|
|
10799
|
-
this._expire_token_time = session.validUntil / 1e3;
|
|
10800
|
-
} else if (accessTokenCredential(auth) !== void 0) {
|
|
10801
|
-
this._token = accessTokenCredential(auth);
|
|
10802
|
-
this._expire_token_time = Number.MAX_VALUE;
|
|
10803
|
-
} else if (this._options.eyepopUrl) {
|
|
10804
|
-
const credential = apiKeyCredential(auth);
|
|
10805
|
-
if (credential === void 0) {
|
|
10806
|
-
return Promise.reject("no valid auth option");
|
|
10807
|
-
}
|
|
10808
|
-
const headers = { Authorization: `Bearer ${credential}` };
|
|
10809
|
-
const post_url = `${this.eyepopUrl()}/v1/auth/authenticate`;
|
|
10810
|
-
const response = await this._client.fetch(post_url, {
|
|
10811
|
-
method: "POST",
|
|
10812
|
-
headers
|
|
10813
|
-
});
|
|
10814
|
-
if (response.status != 200) {
|
|
10815
|
-
const message = await response.text();
|
|
10816
|
-
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
10817
|
-
}
|
|
10818
|
-
const data = await response.json();
|
|
10819
|
-
const token = data;
|
|
10820
|
-
this._token = token.access_token;
|
|
10821
|
-
this._expire_token_time = now + token.expires_in - 60;
|
|
10822
|
-
} else {
|
|
10823
|
-
return Promise.reject("no valid auth option");
|
|
11125
|
+
async uploadPath(source, params) {
|
|
11126
|
+
return await this.startConnected(async (client) => {
|
|
11127
|
+
const streamSource = await this.resolvePath(source);
|
|
11128
|
+
let firstStreamPending = true;
|
|
11129
|
+
const uploadBodyFactory = async () => {
|
|
11130
|
+
if (firstStreamPending) {
|
|
11131
|
+
firstStreamPending = false;
|
|
11132
|
+
return streamSource.stream;
|
|
10824
11133
|
}
|
|
10825
|
-
|
|
10826
|
-
|
|
10827
|
-
|
|
11134
|
+
return (await this.resolvePath(source)).stream;
|
|
11135
|
+
};
|
|
11136
|
+
return new UploadJob(
|
|
11137
|
+
streamSource.stream,
|
|
11138
|
+
streamSource.mimeType,
|
|
11139
|
+
streamSource.size,
|
|
11140
|
+
source.videoMode,
|
|
11141
|
+
params,
|
|
11142
|
+
async () => this.session(),
|
|
11143
|
+
client,
|
|
11144
|
+
this.ctx.requestLogger,
|
|
11145
|
+
uploadBodyFactory,
|
|
11146
|
+
this.predictionVersion()
|
|
11147
|
+
);
|
|
11148
|
+
});
|
|
11149
|
+
}
|
|
11150
|
+
async loadFrom(source, params) {
|
|
11151
|
+
if (source.url.startsWith("file://")) {
|
|
11152
|
+
return await this.uploadPath({ path: source.url.substring("file://".length) }, params);
|
|
10828
11153
|
}
|
|
10829
|
-
this.
|
|
10830
|
-
return this._token;
|
|
11154
|
+
return await this.startConnected(async (client) => new LoadFromJob(source.url, params, async () => this.session(), client, this.ctx.requestLogger, this.predictionVersion()));
|
|
10831
11155
|
}
|
|
10832
|
-
|
|
10833
|
-
|
|
10834
|
-
// worker/worker_options.ts
|
|
10835
|
-
var TransientPopId = /* @__PURE__ */ ((TransientPopId2) => {
|
|
10836
|
-
TransientPopId2["Transient"] = "transient";
|
|
10837
|
-
return TransientPopId2;
|
|
10838
|
-
})(TransientPopId || {});
|
|
10839
|
-
|
|
10840
|
-
// worker/worker_endpoint.ts
|
|
10841
|
-
var _WorkerEndpoint = class _WorkerEndpoint extends Endpoint {
|
|
10842
|
-
constructor(options) {
|
|
10843
|
-
super(options);
|
|
10844
|
-
this.setStatusRetryHandlers(/* @__PURE__ */ new Map([[404, (statusCode) => this.statusHandler404(statusCode)]]));
|
|
10845
|
-
this._baseUrl = null;
|
|
10846
|
-
this._pipelineId = null;
|
|
10847
|
-
this._popName = null;
|
|
10848
|
-
this._sessionAccessToken = null;
|
|
10849
|
-
this._sessionAccessTokenValidUntil = null;
|
|
10850
|
-
this._accountId = void 0;
|
|
10851
|
-
this._pipeline = null;
|
|
10852
|
-
this._pipelineCreatePromise = null;
|
|
11156
|
+
async loadFromAssetUuid(source, params) {
|
|
11157
|
+
return await this.startConnected(async (client) => new LoadFromAssetUuidJob(source.assetUuid, params, async () => this.session(), client, this.ctx.requestLogger, this.predictionVersion()));
|
|
10853
11158
|
}
|
|
10854
|
-
|
|
10855
|
-
return this.
|
|
11159
|
+
async loadMediaStream(source, params) {
|
|
11160
|
+
return await this.startConnected(async (client) => new LoadMediaStreamJob(source.mediaStream, params, async () => this.session(), client, this.ctx.requestLogger, this.predictionVersion()));
|
|
10856
11161
|
}
|
|
10857
|
-
async
|
|
10858
|
-
if (this.options
|
|
10859
|
-
|
|
10860
|
-
|
|
11162
|
+
async reconnect() {
|
|
11163
|
+
if (this.ctx.options.popId == "transient" /* Transient */) {
|
|
11164
|
+
await this.getComputeSession();
|
|
11165
|
+
if (this.ctx.options.pop) {
|
|
11166
|
+
this.setTransientPipelinePop();
|
|
11167
|
+
}
|
|
11168
|
+
} else if (this.ctx.options.sessionUuid) {
|
|
11169
|
+
await this.getComputeSession();
|
|
11170
|
+
} else {
|
|
11171
|
+
await this.startWebApiSessionWithPopId();
|
|
11172
|
+
}
|
|
11173
|
+
this.ctx.updateState();
|
|
11174
|
+
}
|
|
11175
|
+
async startWebApiSessionWithPopId() {
|
|
11176
|
+
const client = this.ctx.client();
|
|
11177
|
+
if (!client) {
|
|
11178
|
+
throw new Error("endpoint not initialized");
|
|
11179
|
+
}
|
|
11180
|
+
const config_url = `${this.ctx.eyepopWebApiUrl()}/pops/${this.ctx.options.popId}/config?auto_start=false`;
|
|
11181
|
+
const headers = {
|
|
11182
|
+
Authorization: await this.authorizationHeader()
|
|
11183
|
+
};
|
|
11184
|
+
this.ctx.updateState("FetchConfig" /* FetchConfig */);
|
|
11185
|
+
let response = await client.fetch(config_url, { headers });
|
|
11186
|
+
if (response.status == 401) {
|
|
11187
|
+
this.ctx.requestLogger.debug("GET %s: 401, about to retry with fresh access token", config_url);
|
|
11188
|
+
this.ctx.forgetCredential();
|
|
11189
|
+
const headers2 = {
|
|
10861
11190
|
Authorization: await this.authorizationHeader()
|
|
10862
11191
|
};
|
|
10863
|
-
|
|
10864
|
-
|
|
10865
|
-
headers
|
|
11192
|
+
this.ctx.updateState("FetchConfig" /* FetchConfig */);
|
|
11193
|
+
response = await client.fetch(config_url, {
|
|
11194
|
+
headers: headers2
|
|
10866
11195
|
});
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
11196
|
+
}
|
|
11197
|
+
if (response.status != 200) {
|
|
11198
|
+
const message = await response.text();
|
|
11199
|
+
if (response.status == 429) {
|
|
11200
|
+
this.ctx.updateState("NotAvailable" /* NotAvailable */, message);
|
|
11201
|
+
} else {
|
|
11202
|
+
this.ctx.updateState("Error" /* Error */, message);
|
|
10870
11203
|
}
|
|
11204
|
+
throw new Error(`Unexpected status ${response.status}: ${message}`);
|
|
10871
11205
|
}
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
if (
|
|
10883
|
-
|
|
11206
|
+
let config = await response.json();
|
|
11207
|
+
if (!config.base_url && this.ctx.options.autoStart) {
|
|
11208
|
+
const auto_start_config_url = `${this.ctx.eyepopWebApiUrl()}/pops/${this.ctx.options.popId}/config?auto_start=true`;
|
|
11209
|
+
this.ctx.requestLogger.debug("pop was not running, trying to autostart with: %s", auto_start_config_url);
|
|
11210
|
+
const headers2 = {
|
|
11211
|
+
Authorization: await this.authorizationHeader()
|
|
11212
|
+
};
|
|
11213
|
+
response = await client.fetch(auto_start_config_url, {
|
|
11214
|
+
headers: headers2
|
|
11215
|
+
});
|
|
11216
|
+
if (response.status != 200) {
|
|
11217
|
+
this.ctx.updateState("Error" /* Error */);
|
|
11218
|
+
const message = await response.text();
|
|
11219
|
+
throw new Error(`Unexpected status ${response.status}: ${message}`);
|
|
10884
11220
|
}
|
|
11221
|
+
config = await response.json();
|
|
10885
11222
|
}
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
|
|
11223
|
+
const baseUrl = new URL(config.base_url, this.ctx.eyepopUrl());
|
|
11224
|
+
this._baseUrl = baseUrl.toString();
|
|
11225
|
+
if (this._baseUrl) {
|
|
11226
|
+
this._baseUrl = this._baseUrl.replace(/\/+$/, "");
|
|
11227
|
+
this._pipelineId = config.pipeline_id;
|
|
11228
|
+
this._popName = config.name;
|
|
11229
|
+
if (!this._pipelineId || !this._baseUrl) {
|
|
11230
|
+
throw new Error("Pop not started");
|
|
11231
|
+
}
|
|
11232
|
+
const get_url = `${this._baseUrl}/pipelines/${this._pipelineId}`;
|
|
11233
|
+
const headers2 = {
|
|
11234
|
+
Authorization: await this.authorizationHeader()
|
|
10891
11235
|
};
|
|
10892
|
-
|
|
10893
|
-
|
|
11236
|
+
let response2 = await client.fetch(get_url, {
|
|
11237
|
+
method: "GET",
|
|
11238
|
+
headers: headers2
|
|
11239
|
+
});
|
|
11240
|
+
if (response2.status > 200) {
|
|
11241
|
+
const message = await response2.text();
|
|
11242
|
+
throw new Error(`Unexpected status ${response2.status}: ${message}`);
|
|
11243
|
+
}
|
|
11244
|
+
this._pipeline = await response2.json();
|
|
11245
|
+
if (this.ctx.options.stopJobs) {
|
|
11246
|
+
const body = { sourceType: "NONE" };
|
|
11247
|
+
const headers3 = {
|
|
11248
|
+
Authorization: await this.authorizationHeader(),
|
|
11249
|
+
"Content-Type": "application/json"
|
|
11250
|
+
};
|
|
11251
|
+
const stop_url = `${this._baseUrl}/pipelines/${this._pipeline.id}/source?mode=preempt&processing=sync`;
|
|
11252
|
+
let response3 = await client.fetch(stop_url, {
|
|
11253
|
+
method: "PATCH",
|
|
11254
|
+
headers: headers3,
|
|
11255
|
+
body: JSON.stringify(body)
|
|
11256
|
+
});
|
|
11257
|
+
if (response3.status >= 300) {
|
|
11258
|
+
const message = await response3.text();
|
|
11259
|
+
throw new Error(`Unexpected status ${response3.status}: ${message}`);
|
|
11260
|
+
}
|
|
11261
|
+
}
|
|
10894
11262
|
}
|
|
10895
|
-
return {
|
|
10896
|
-
eyepopUrl: session.eyepopUrl,
|
|
10897
|
-
accessToken: session.accessToken,
|
|
10898
|
-
validUntil: session.validUntil,
|
|
10899
|
-
popId: this.options().popId,
|
|
10900
|
-
accountId: this._accountId ?? this.options().accountId,
|
|
10901
|
-
baseUrl: this._baseUrl,
|
|
10902
|
-
pipelineId: this._pipelineId || void 0,
|
|
10903
|
-
authenticationHeaders: () => this._authenticationHeaders(session)
|
|
10904
|
-
};
|
|
10905
11263
|
}
|
|
10906
|
-
|
|
10907
|
-
|
|
11264
|
+
sessionReadyTimeoutMs() {
|
|
11265
|
+
const seconds = this.ctx.options.sessionReadyTimeoutSeconds;
|
|
11266
|
+
return typeof seconds == "number" && Number.isFinite(seconds) && seconds > 0 ? seconds * 1e3 : _SessionBackend.WAIT_FOR_IS_READY;
|
|
10908
11267
|
}
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
11268
|
+
async getComputeSession() {
|
|
11269
|
+
const client = this.ctx.client();
|
|
11270
|
+
if (!client) {
|
|
11271
|
+
throw new Error("endpoint not initialized");
|
|
10912
11272
|
}
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10926
|
-
|
|
10927
|
-
|
|
11273
|
+
let resolved;
|
|
11274
|
+
try {
|
|
11275
|
+
resolved = await new ComputeSessionClient({
|
|
11276
|
+
computeUrl: this.ctx.eyepopUrl(),
|
|
11277
|
+
httpClient: client,
|
|
11278
|
+
authorizationHeader: () => this.computeAuthorizationHeader(),
|
|
11279
|
+
sessionUuid: this.ctx.options.sessionUuid,
|
|
11280
|
+
sessionName: this.ctx.options.sessionName,
|
|
11281
|
+
accountId: this.ctx.options.accountId,
|
|
11282
|
+
pipelineImage: this.ctx.options.pipelineImage,
|
|
11283
|
+
pipelineVersion: this.ctx.options.pipelineVersion,
|
|
11284
|
+
pop: this.ctx.options.pop,
|
|
11285
|
+
readyTimeoutMs: this.sessionReadyTimeoutMs(),
|
|
11286
|
+
logger: this.ctx.logger,
|
|
11287
|
+
requestLogger: this.ctx.requestLogger
|
|
11288
|
+
}).resolve();
|
|
11289
|
+
} catch (error) {
|
|
11290
|
+
this.ctx.updateState("Error" /* Error */);
|
|
11291
|
+
throw error;
|
|
10928
11292
|
}
|
|
10929
|
-
|
|
11293
|
+
this._sessionAccessToken = resolved.accessToken;
|
|
11294
|
+
this._sessionAccessTokenValidUntil = resolved.accessTokenValidUntil;
|
|
11295
|
+
this._baseUrl = resolved.session.session_endpoint;
|
|
11296
|
+
this._accountId = resolved.session.account_uuid || void 0;
|
|
11297
|
+
this._pipeline = null;
|
|
11298
|
+
this._pipelineId = resolved.pipelineId;
|
|
11299
|
+
if (this.ctx.options.pop) {
|
|
11300
|
+
this.setTransientPipelinePop();
|
|
11301
|
+
}
|
|
11302
|
+
}
|
|
11303
|
+
async startTransientPipeline() {
|
|
11304
|
+
const client = this.ctx.client();
|
|
10930
11305
|
const baseUrl = this._baseUrl;
|
|
10931
|
-
if (
|
|
10932
|
-
|
|
11306
|
+
if (client == null || baseUrl == null) {
|
|
11307
|
+
throw new Error("endpoint not initialized");
|
|
10933
11308
|
}
|
|
10934
|
-
let
|
|
10935
|
-
|
|
11309
|
+
let pop;
|
|
11310
|
+
if (this.ctx.options.pop) {
|
|
11311
|
+
pop = this.ctx.options.pop;
|
|
11312
|
+
} else if (this._pipeline && this._pipeline.pop) {
|
|
11313
|
+
pop = this._pipeline.pop;
|
|
11314
|
+
} else {
|
|
11315
|
+
throw new Error("Cannot start a transient pipeline without a pop");
|
|
11316
|
+
}
|
|
11317
|
+
const body = {
|
|
11318
|
+
pop,
|
|
11319
|
+
source: {
|
|
11320
|
+
sourceType: "NONE"
|
|
11321
|
+
},
|
|
11322
|
+
idleTimeoutSeconds: 30,
|
|
11323
|
+
logging: ["out_meta"],
|
|
11324
|
+
videoOutput: "no_output"
|
|
11325
|
+
};
|
|
11326
|
+
const post_url = `${baseUrl.replace(/\/+$/, "")}/pipelines`;
|
|
11327
|
+
const response = await this.ctx.fetchWithRetry(async () => {
|
|
10936
11328
|
let headers = {
|
|
11329
|
+
Accept: "application/json",
|
|
10937
11330
|
"Content-Type": "application/json",
|
|
10938
|
-
|
|
11331
|
+
Authorization: await this.authorizationHeader()
|
|
10939
11332
|
};
|
|
10940
|
-
|
|
10941
|
-
|
|
10942
|
-
|
|
10943
|
-
body: JSON.stringify(pop),
|
|
11333
|
+
return client.fetch(post_url, {
|
|
11334
|
+
method: "POST",
|
|
11335
|
+
body: JSON.stringify(body),
|
|
10944
11336
|
headers
|
|
10945
11337
|
});
|
|
10946
11338
|
});
|
|
10947
|
-
if (response.status !=
|
|
11339
|
+
if (response.status != 200) {
|
|
11340
|
+
const message = await response.text();
|
|
11341
|
+
throw new Error(`Unexpected status ${response.status} starting transient pipeline: ${message.slice(0, 300)}`);
|
|
11342
|
+
}
|
|
11343
|
+
const result = await response.json();
|
|
11344
|
+
return result["id"];
|
|
11345
|
+
}
|
|
11346
|
+
async ensureTransientPipelineStarted() {
|
|
11347
|
+
if (this.ctx.options.popId != "transient" /* Transient */ || this._pipelineId) {
|
|
11348
|
+
return;
|
|
11349
|
+
}
|
|
11350
|
+
if (!this.ctx.options.pop) {
|
|
11351
|
+
return;
|
|
11352
|
+
}
|
|
11353
|
+
if (!this._baseUrl) {
|
|
11354
|
+
await this.reconnect();
|
|
11355
|
+
}
|
|
11356
|
+
if (this._pipelineId) {
|
|
11357
|
+
return;
|
|
11358
|
+
}
|
|
11359
|
+
if (this.ctx.options.pop) {
|
|
11360
|
+
await this.reconnect();
|
|
11361
|
+
if (!this._pipelineId) {
|
|
11362
|
+
throw new Error("Compute session did not provide a pipeline for the requested pop");
|
|
11363
|
+
}
|
|
11364
|
+
return;
|
|
11365
|
+
}
|
|
11366
|
+
if (!this._pipelineCreatePromise) {
|
|
11367
|
+
this._pipelineCreatePromise = this.startTransientPipeline();
|
|
11368
|
+
}
|
|
11369
|
+
try {
|
|
11370
|
+
this._pipelineId = await this._pipelineCreatePromise;
|
|
11371
|
+
this.setTransientPipelinePop();
|
|
11372
|
+
} finally {
|
|
11373
|
+
this._pipelineCreatePromise = null;
|
|
11374
|
+
}
|
|
11375
|
+
}
|
|
11376
|
+
async changeTransientPop(pop) {
|
|
11377
|
+
if (!this.ctx.client()) {
|
|
11378
|
+
throw new Error("endpoint not initialized");
|
|
11379
|
+
}
|
|
11380
|
+
const previousPop = this.ctx.options.pop;
|
|
11381
|
+
const previousBaseUrl = this._baseUrl;
|
|
11382
|
+
const previousSessionAccessToken = this._sessionAccessToken;
|
|
11383
|
+
const previousSessionAccessTokenValidUntil = this._sessionAccessTokenValidUntil;
|
|
11384
|
+
if (this._pipelineId) {
|
|
11385
|
+
await this.deleteTransientPipeline(this._pipelineId);
|
|
11386
|
+
this._pipelineId = null;
|
|
11387
|
+
}
|
|
11388
|
+
this._pipeline = null;
|
|
11389
|
+
try {
|
|
11390
|
+
this.ctx.options.pop = pop;
|
|
11391
|
+
await this.getComputeSession();
|
|
11392
|
+
} catch (error) {
|
|
11393
|
+
this.ctx.options.pop = previousPop;
|
|
11394
|
+
this._pipeline = null;
|
|
11395
|
+
this._pipelineId = null;
|
|
11396
|
+
this._baseUrl = previousPop ? null : previousBaseUrl;
|
|
11397
|
+
this._sessionAccessToken = previousSessionAccessToken;
|
|
11398
|
+
this._sessionAccessTokenValidUntil = previousSessionAccessTokenValidUntil;
|
|
11399
|
+
throw error;
|
|
11400
|
+
}
|
|
11401
|
+
if (!this._pipelineId) {
|
|
11402
|
+
throw new Error("Compute session did not provide a pipeline for the requested pop");
|
|
11403
|
+
}
|
|
11404
|
+
this.setTransientPipelinePop();
|
|
11405
|
+
}
|
|
11406
|
+
async deleteTransientPipeline(pipelineId) {
|
|
11407
|
+
const client = this.ctx.client();
|
|
11408
|
+
if (!client || !this._baseUrl) {
|
|
11409
|
+
return;
|
|
11410
|
+
}
|
|
11411
|
+
const deleteUrl = `${this._baseUrl}/pipelines/${pipelineId}`;
|
|
11412
|
+
const headers = {
|
|
11413
|
+
Authorization: await this.authorizationHeader()
|
|
11414
|
+
};
|
|
11415
|
+
let response = await client.fetch(deleteUrl, {
|
|
11416
|
+
method: "DELETE",
|
|
11417
|
+
headers
|
|
11418
|
+
});
|
|
11419
|
+
if (response.status >= 300) {
|
|
10948
11420
|
const message = await response.text();
|
|
10949
|
-
|
|
11421
|
+
this.ctx.logger.info(`stopping pipeline failed, status ${response.status}: ${message}`);
|
|
10950
11422
|
}
|
|
10951
|
-
|
|
10952
|
-
|
|
10953
|
-
|
|
10954
|
-
|
|
11423
|
+
}
|
|
11424
|
+
async authorizationHeader() {
|
|
11425
|
+
if (this._sessionAccessToken) {
|
|
11426
|
+
return `Bearer ${this._sessionAccessToken}`;
|
|
11427
|
+
}
|
|
11428
|
+
return this.ctx.credentialHeader();
|
|
11429
|
+
}
|
|
11430
|
+
async computeAuthorizationHeader() {
|
|
11431
|
+
const auth = resolveAuth(this.ctx.options);
|
|
11432
|
+
if (auth?.isLocal !== void 0) {
|
|
11433
|
+
return "Implicit";
|
|
11434
|
+
}
|
|
11435
|
+
const credential = apiKeyCredential(auth) ?? accessTokenCredential(auth);
|
|
11436
|
+
if (credential !== void 0) {
|
|
11437
|
+
return `Bearer ${credential}`;
|
|
11438
|
+
}
|
|
11439
|
+
return this.ctx.credentialHeader();
|
|
11440
|
+
}
|
|
11441
|
+
setTransientPipelinePop() {
|
|
11442
|
+
const pop = this.ctx.options.pop;
|
|
11443
|
+
if (pop && this._pipelineId) {
|
|
10955
11444
|
this._pipeline = {
|
|
10956
|
-
id: this._pipelineId
|
|
11445
|
+
id: this._pipelineId,
|
|
10957
11446
|
state: "idle",
|
|
10958
11447
|
startTime: (/* @__PURE__ */ new Date()).toString(),
|
|
10959
11448
|
pop
|
|
10960
11449
|
};
|
|
10961
11450
|
}
|
|
10962
11451
|
}
|
|
10963
|
-
|
|
10964
|
-
|
|
11452
|
+
};
|
|
11453
|
+
_SessionBackend.WAIT_FOR_IS_READY = 60 * 1e3;
|
|
11454
|
+
var SessionBackend = _SessionBackend;
|
|
11455
|
+
|
|
11456
|
+
// shims/websockets.ts
|
|
11457
|
+
var createWebSocket;
|
|
11458
|
+
var UpgradeError = class extends Error {
|
|
11459
|
+
constructor(message, status, retryAfter) {
|
|
11460
|
+
super(message);
|
|
11461
|
+
this.name = "UpgradeError";
|
|
11462
|
+
this.status = status;
|
|
11463
|
+
this.retryAfter = retryAfter;
|
|
10965
11464
|
}
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
return
|
|
11465
|
+
};
|
|
11466
|
+
var openAuthorizedWebSocket;
|
|
11467
|
+
var isBrowser = "document" in globalThis && "implementation" in globalThis.document;
|
|
11468
|
+
if (isBrowser) {
|
|
11469
|
+
createWebSocket = (url, protocols) => {
|
|
11470
|
+
return new WebSocket(url, protocols);
|
|
11471
|
+
};
|
|
11472
|
+
openAuthorizedWebSocket = (url, protocol, token) => {
|
|
11473
|
+
const protocols = token === void 0 ? [protocol] : [protocol, `eyepop.bearer.${token}`];
|
|
11474
|
+
const ws = new WebSocket(url, protocols);
|
|
11475
|
+
ws.binaryType = "arraybuffer";
|
|
11476
|
+
return new Promise((resolve, reject) => {
|
|
11477
|
+
ws.onopen = () => resolve(ws);
|
|
11478
|
+
ws.onerror = () => reject(new UpgradeError(`could not open ${url}`));
|
|
11479
|
+
});
|
|
11480
|
+
};
|
|
11481
|
+
} else {
|
|
11482
|
+
createWebSocket = (url, protocols) => {
|
|
11483
|
+
const ws = __require("ws");
|
|
11484
|
+
return new ws.WebSocket(url, protocols);
|
|
11485
|
+
};
|
|
11486
|
+
openAuthorizedWebSocket = (url, protocol, token) => {
|
|
11487
|
+
const ws = __require("ws");
|
|
11488
|
+
const headers = token === void 0 ? {} : { Authorization: `Bearer ${token}` };
|
|
11489
|
+
const socket = new ws.WebSocket(url, [protocol], { headers, maxPayload: 0 });
|
|
11490
|
+
socket.binaryType = "arraybuffer";
|
|
11491
|
+
return new Promise((resolve, reject) => {
|
|
11492
|
+
socket.once("open", () => resolve(socket));
|
|
11493
|
+
socket.once("unexpected-response", (_request, response) => {
|
|
11494
|
+
const retryAfter = Number.parseFloat(response.headers?.["retry-after"]);
|
|
11495
|
+
reject(new UpgradeError(`the pipeline API answered the upgrade ${response.statusCode}`, response.statusCode, Number.isFinite(retryAfter) ? retryAfter : void 0));
|
|
11496
|
+
response.resume();
|
|
11497
|
+
socket.terminate();
|
|
11498
|
+
});
|
|
11499
|
+
socket.once("error", (error) => reject(new UpgradeError(`could not open ${url}: ${error.message}`)));
|
|
11500
|
+
});
|
|
11501
|
+
};
|
|
11502
|
+
}
|
|
11503
|
+
|
|
11504
|
+
// worker/pipeline_backend.ts
|
|
11505
|
+
var PIPELINE_PATH = "/api/v1/pipeline";
|
|
11506
|
+
var SUBPROTOCOL = "eyepop.v1";
|
|
11507
|
+
var MAX_OPEN_SOURCES = 256;
|
|
11508
|
+
var COMBINED_UPLOAD_MAX_BYTES = 8 * 1024 * 1024;
|
|
11509
|
+
var CHUNK = 1;
|
|
11510
|
+
var COMBINED = 2;
|
|
11511
|
+
var CHUNK_BYTES = 64 * 1024;
|
|
11512
|
+
var HEARTBEAT_MS = 20 * 1e3;
|
|
11513
|
+
var MAX_RETRY_MS = 30 * 1e3;
|
|
11514
|
+
var RECONNECT_AT_ONCE = /* @__PURE__ */ new Set(["1008 credential_expired", "1011 overloaded", "1001 shutting_down"]);
|
|
11515
|
+
var MAX_RECONNECT_DELAY_MS = 30 * 1e3;
|
|
11516
|
+
var PipelineConfigurationError = class extends Error {
|
|
11517
|
+
constructor(problem, message, options = []) {
|
|
11518
|
+
super(message);
|
|
11519
|
+
this.name = "PipelineConfigurationError";
|
|
11520
|
+
this.problem = problem;
|
|
11521
|
+
this.options = options;
|
|
10972
11522
|
}
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
|
|
10976
|
-
|
|
10977
|
-
|
|
10978
|
-
|
|
11523
|
+
};
|
|
11524
|
+
var PipelineSocketClosedError = class extends Error {
|
|
11525
|
+
constructor(code, reason) {
|
|
11526
|
+
super(`the pipeline API closed the socket: ${code ?? ""} ${reason}`.trim());
|
|
11527
|
+
this.name = "PipelineSocketClosedError";
|
|
11528
|
+
this.code = code;
|
|
11529
|
+
this.reason = reason;
|
|
10979
11530
|
}
|
|
10980
|
-
|
|
10981
|
-
|
|
10982
|
-
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
} else if (source.url !== void 0) {
|
|
10988
|
-
return this.loadFrom(source, { componentParams: params });
|
|
10989
|
-
} else if (source.assetUuid !== void 0) {
|
|
10990
|
-
return this.loadFromAssetUuid(source, { componentParams: params });
|
|
10991
|
-
} else if (source.mediaStream !== void 0) {
|
|
10992
|
-
return this.loadMediaStream(source, { componentParams: params });
|
|
10993
|
-
} else {
|
|
10994
|
-
return Promise.reject("unknown source type");
|
|
10995
|
-
}
|
|
11531
|
+
};
|
|
11532
|
+
var PipelineCommandError = class extends Error {
|
|
11533
|
+
constructor(error, detail = "") {
|
|
11534
|
+
super(`the pipeline API refused the command: ${error} ${detail}`.trim());
|
|
11535
|
+
this.name = "PipelineCommandError";
|
|
11536
|
+
this.error = error;
|
|
11537
|
+
this.detail = detail;
|
|
10996
11538
|
}
|
|
10997
|
-
|
|
10998
|
-
|
|
10999
|
-
|
|
11000
|
-
|
|
11001
|
-
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
|
|
11005
|
-
*/
|
|
11006
|
-
validateProcessParams(params) {
|
|
11007
|
-
if (params.camera !== void 0) {
|
|
11008
|
-
validateCamera(params.camera);
|
|
11009
|
-
}
|
|
11539
|
+
};
|
|
11540
|
+
var PipelineSourceError = class extends Error {
|
|
11541
|
+
constructor(sourceId, reason, detail = "") {
|
|
11542
|
+
super(`Error in source ${sourceId}: ${reason} ${detail}`.trim());
|
|
11543
|
+
this.name = "PipelineSourceError";
|
|
11544
|
+
this.sourceId = sourceId;
|
|
11545
|
+
this.reason = reason;
|
|
11546
|
+
this.detail = detail;
|
|
11010
11547
|
}
|
|
11011
|
-
|
|
11012
|
-
|
|
11013
|
-
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
|
|
11017
|
-
|
|
11018
|
-
|
|
11019
|
-
|
|
11020
|
-
|
|
11021
|
-
|
|
11022
|
-
|
|
11023
|
-
} else if (request.source.mediaStream !== void 0) {
|
|
11024
|
-
return this.loadMediaStream(request.source, request);
|
|
11548
|
+
};
|
|
11549
|
+
var CANCELLED = /* @__PURE__ */ Symbol("cancelled");
|
|
11550
|
+
var Inbox = class {
|
|
11551
|
+
constructor() {
|
|
11552
|
+
this._items = [];
|
|
11553
|
+
this._waiter = null;
|
|
11554
|
+
}
|
|
11555
|
+
push(item) {
|
|
11556
|
+
const waiter = this._waiter;
|
|
11557
|
+
if (waiter) {
|
|
11558
|
+
this._waiter = null;
|
|
11559
|
+
waiter(item);
|
|
11025
11560
|
} else {
|
|
11026
|
-
|
|
11561
|
+
this._items.push(item);
|
|
11027
11562
|
}
|
|
11028
11563
|
}
|
|
11029
|
-
|
|
11030
|
-
|
|
11031
|
-
|
|
11564
|
+
next() {
|
|
11565
|
+
const item = this._items.shift();
|
|
11566
|
+
if (item !== void 0) {
|
|
11567
|
+
return Promise.resolve(item);
|
|
11032
11568
|
}
|
|
11033
|
-
this.
|
|
11034
|
-
|
|
11035
|
-
|
|
11569
|
+
return new Promise((resolve) => this._waiter = resolve);
|
|
11570
|
+
}
|
|
11571
|
+
};
|
|
11572
|
+
var UploadEnded = class extends Error {
|
|
11573
|
+
};
|
|
11574
|
+
var Credit = class {
|
|
11575
|
+
constructor() {
|
|
11576
|
+
this._credit = 0;
|
|
11577
|
+
this._ended = false;
|
|
11578
|
+
this._waiter = null;
|
|
11579
|
+
}
|
|
11580
|
+
grant(n) {
|
|
11581
|
+
this._credit += n;
|
|
11582
|
+
this.wake();
|
|
11583
|
+
}
|
|
11584
|
+
end() {
|
|
11585
|
+
this._ended = true;
|
|
11586
|
+
this.wake();
|
|
11587
|
+
}
|
|
11588
|
+
async take(most) {
|
|
11589
|
+
while (this._credit <= 0 && !this._ended) {
|
|
11590
|
+
await new Promise((resolve) => this._waiter = resolve);
|
|
11036
11591
|
}
|
|
11037
|
-
|
|
11038
|
-
|
|
11039
|
-
this.updateState();
|
|
11040
|
-
const sources = await Promise.all(
|
|
11041
|
-
paths.map(async (path2) => {
|
|
11042
|
-
let streamSource;
|
|
11043
|
-
if (this._options.platformSupport?.resolvePath) {
|
|
11044
|
-
streamSource = await this._options.platformSupport.resolvePath({ path: path2 }, this._logger);
|
|
11045
|
-
} else {
|
|
11046
|
-
streamSource = await resolvePath({ path: path2 }, this._logger);
|
|
11047
|
-
}
|
|
11048
|
-
return { stream: streamSource.stream, mimeType: streamSource.mimeType };
|
|
11049
|
-
})
|
|
11050
|
-
);
|
|
11051
|
-
const job = new UploadGroupJob(sources, params, async () => this.session(), this._client, this._requestLogger, this.predictionVersion());
|
|
11052
|
-
return job.start(
|
|
11053
|
-
() => {
|
|
11054
|
-
this.jobDone(job);
|
|
11055
|
-
},
|
|
11056
|
-
(statusCode) => {
|
|
11057
|
-
this.jobStatus(job, statusCode);
|
|
11058
|
-
}
|
|
11059
|
-
);
|
|
11060
|
-
} catch (e) {
|
|
11061
|
-
this._limit.release();
|
|
11062
|
-
throw e;
|
|
11592
|
+
if (this._ended) {
|
|
11593
|
+
throw new UploadEnded();
|
|
11063
11594
|
}
|
|
11595
|
+
const n = Math.min(most, this._credit);
|
|
11596
|
+
this._credit -= n;
|
|
11597
|
+
return n;
|
|
11064
11598
|
}
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
|
|
11599
|
+
wake() {
|
|
11600
|
+
const waiter = this._waiter;
|
|
11601
|
+
this._waiter = null;
|
|
11602
|
+
waiter?.();
|
|
11603
|
+
}
|
|
11604
|
+
};
|
|
11605
|
+
var OpenSource = class {
|
|
11606
|
+
constructor(id) {
|
|
11607
|
+
this.id = id;
|
|
11608
|
+
this.inbox = new Inbox();
|
|
11609
|
+
this.uploads = /* @__PURE__ */ new Map();
|
|
11610
|
+
}
|
|
11611
|
+
close(error) {
|
|
11612
|
+
this.uploads.forEach((upload) => upload.end());
|
|
11613
|
+
this.inbox.push(error);
|
|
11614
|
+
}
|
|
11615
|
+
};
|
|
11616
|
+
var PipelineSocket = class {
|
|
11617
|
+
constructor(ws) {
|
|
11618
|
+
this.ws = ws;
|
|
11619
|
+
this.sources = /* @__PURE__ */ new Map();
|
|
11620
|
+
this.commands = /* @__PURE__ */ new Map();
|
|
11621
|
+
this._closed = false;
|
|
11622
|
+
this.closed = new Promise((resolve) => this._markClosed = resolve);
|
|
11623
|
+
}
|
|
11624
|
+
get open() {
|
|
11625
|
+
return !this._closed && this.ws.readyState === 1;
|
|
11626
|
+
}
|
|
11627
|
+
markClosed() {
|
|
11628
|
+
this._closed = true;
|
|
11629
|
+
this._markClosed();
|
|
11630
|
+
}
|
|
11631
|
+
sendJson(message) {
|
|
11632
|
+
this.ws.send(JSON.stringify(message));
|
|
11633
|
+
}
|
|
11634
|
+
sendBytes(data) {
|
|
11635
|
+
this.ws.send(data);
|
|
11636
|
+
}
|
|
11637
|
+
};
|
|
11638
|
+
var PipelineJob = class {
|
|
11639
|
+
constructor(source, media, live, params, mediaStream = void 0) {
|
|
11640
|
+
this.source = source;
|
|
11641
|
+
this.media = media;
|
|
11642
|
+
this.live = live;
|
|
11643
|
+
this.params = params;
|
|
11644
|
+
this.mediaStream = mediaStream;
|
|
11645
|
+
this._results = new Inbox();
|
|
11646
|
+
this._consumed = false;
|
|
11647
|
+
this._cancelled = false;
|
|
11648
|
+
this.openSource = null;
|
|
11649
|
+
// Stops the job's source on the pipeline, once it was sent.
|
|
11650
|
+
this.stopOnPipeline = null;
|
|
11651
|
+
}
|
|
11652
|
+
get cancelled() {
|
|
11653
|
+
return this._cancelled;
|
|
11654
|
+
}
|
|
11655
|
+
command(id) {
|
|
11656
|
+
const command = { type: "setSource", id, ...this.source };
|
|
11657
|
+
if (this.params.componentParams !== void 0) {
|
|
11658
|
+
command["params"] = this.params.componentParams;
|
|
11068
11659
|
}
|
|
11069
|
-
if (
|
|
11070
|
-
|
|
11660
|
+
if (this.params.roi !== void 0) {
|
|
11661
|
+
command["roi"] = this.params.roi;
|
|
11071
11662
|
}
|
|
11072
|
-
this.
|
|
11073
|
-
|
|
11074
|
-
throw new Error("endpoint not connected, use connect()");
|
|
11663
|
+
if (this.params.camera !== void 0) {
|
|
11664
|
+
command["camera"] = this.params.camera;
|
|
11075
11665
|
}
|
|
11076
|
-
|
|
11077
|
-
|
|
11078
|
-
this.updateState();
|
|
11079
|
-
const sources = streams.map((stream, i) => ({
|
|
11080
|
-
stream,
|
|
11081
|
-
mimeType: mimeTypes?.[i] ?? null
|
|
11082
|
-
}));
|
|
11083
|
-
const job = new UploadGroupJob(sources, params, async () => this.session(), this._client, this._requestLogger, this.predictionVersion());
|
|
11084
|
-
return job.start(
|
|
11085
|
-
() => {
|
|
11086
|
-
this.jobDone(job);
|
|
11087
|
-
},
|
|
11088
|
-
(statusCode) => {
|
|
11089
|
-
this.jobStatus(job, statusCode);
|
|
11090
|
-
}
|
|
11091
|
-
);
|
|
11092
|
-
} catch (e) {
|
|
11093
|
-
this._limit.release();
|
|
11094
|
-
throw e;
|
|
11666
|
+
if (this.params.fps !== void 0) {
|
|
11667
|
+
command["fps"] = this.params.fps;
|
|
11095
11668
|
}
|
|
11669
|
+
return command;
|
|
11096
11670
|
}
|
|
11097
|
-
|
|
11098
|
-
if (
|
|
11099
|
-
|
|
11100
|
-
}
|
|
11101
|
-
this.validateProcessParams(params);
|
|
11102
|
-
if (!this._baseUrl || !this._pipelineId || !this._client || !this._limit) {
|
|
11103
|
-
throw new Error("endpoint not connected, use connect()");
|
|
11104
|
-
}
|
|
11105
|
-
await this._limit.acquire();
|
|
11106
|
-
try {
|
|
11107
|
-
this.updateState();
|
|
11108
|
-
const job = new LoadFromGroupJob(urls, params, async () => this.session(), this._client, this._requestLogger, this.predictionVersion());
|
|
11109
|
-
return job.start(
|
|
11110
|
-
() => {
|
|
11111
|
-
this.jobDone(job);
|
|
11112
|
-
},
|
|
11113
|
-
(statusCode) => {
|
|
11114
|
-
this.jobStatus(job, statusCode);
|
|
11115
|
-
}
|
|
11116
|
-
);
|
|
11117
|
-
} catch (e) {
|
|
11118
|
-
this._limit.release();
|
|
11119
|
-
throw e;
|
|
11671
|
+
predicted(prediction) {
|
|
11672
|
+
if (!this._cancelled) {
|
|
11673
|
+
this._results.push(prediction);
|
|
11120
11674
|
}
|
|
11121
11675
|
}
|
|
11122
|
-
|
|
11123
|
-
|
|
11124
|
-
|
|
11125
|
-
return Promise.reject("endpoint not connected, use connect()");
|
|
11126
|
-
}
|
|
11127
|
-
await this._limit.acquire();
|
|
11128
|
-
try {
|
|
11129
|
-
this.updateState();
|
|
11130
|
-
const job = new UploadJob(
|
|
11131
|
-
source.file,
|
|
11132
|
-
source.file.type,
|
|
11133
|
-
source.file.size,
|
|
11134
|
-
source.videoMode,
|
|
11135
|
-
params,
|
|
11136
|
-
async () => {
|
|
11137
|
-
return this.session();
|
|
11138
|
-
},
|
|
11139
|
-
this._client,
|
|
11140
|
-
this._requestLogger,
|
|
11141
|
-
void 0,
|
|
11142
|
-
this.predictionVersion()
|
|
11143
|
-
);
|
|
11144
|
-
return job.start(
|
|
11145
|
-
() => {
|
|
11146
|
-
this.jobDone(job);
|
|
11147
|
-
},
|
|
11148
|
-
(statusCode) => {
|
|
11149
|
-
this.jobStatus(job, statusCode);
|
|
11150
|
-
}
|
|
11151
|
-
);
|
|
11152
|
-
} catch (e) {
|
|
11153
|
-
this._limit.release();
|
|
11154
|
-
throw e;
|
|
11676
|
+
finish(error = null) {
|
|
11677
|
+
if (error !== null) {
|
|
11678
|
+
this._results.push(error);
|
|
11155
11679
|
}
|
|
11680
|
+
this._results.push(null);
|
|
11156
11681
|
}
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
return Promise.reject("endpoint not connected, use connect()");
|
|
11161
|
-
}
|
|
11162
|
-
await this._limit.acquire();
|
|
11163
|
-
try {
|
|
11164
|
-
this.updateState();
|
|
11165
|
-
const job = new UploadJob(
|
|
11166
|
-
source.stream,
|
|
11167
|
-
source.mimeType,
|
|
11168
|
-
source.size,
|
|
11169
|
-
source.videoMode,
|
|
11170
|
-
params,
|
|
11171
|
-
async () => {
|
|
11172
|
-
return this.session();
|
|
11173
|
-
},
|
|
11174
|
-
this._client,
|
|
11175
|
-
this._requestLogger,
|
|
11176
|
-
void 0,
|
|
11177
|
-
this.predictionVersion()
|
|
11178
|
-
);
|
|
11179
|
-
return job.start(
|
|
11180
|
-
() => {
|
|
11181
|
-
this.jobDone(job);
|
|
11182
|
-
},
|
|
11183
|
-
(statusCode) => {
|
|
11184
|
-
this.jobStatus(job, statusCode);
|
|
11185
|
-
}
|
|
11186
|
-
);
|
|
11187
|
-
} catch (e) {
|
|
11188
|
-
this._limit.release();
|
|
11189
|
-
throw e;
|
|
11682
|
+
cancel() {
|
|
11683
|
+
if (this._cancelled) {
|
|
11684
|
+
return;
|
|
11190
11685
|
}
|
|
11686
|
+
this._cancelled = true;
|
|
11687
|
+
this._results.push(null);
|
|
11688
|
+
this.openSource?.inbox.push(CANCELLED);
|
|
11689
|
+
this.stopOnPipeline?.();
|
|
11191
11690
|
}
|
|
11192
|
-
async
|
|
11193
|
-
|
|
11194
|
-
|
|
11195
|
-
throw new Error("endpoint not connected, use connect()");
|
|
11691
|
+
async *[Symbol.asyncIterator]() {
|
|
11692
|
+
if (this._consumed) {
|
|
11693
|
+
throw new Error("Cannot iterate over a consumed stream");
|
|
11196
11694
|
}
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
this.
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
}
|
|
11206
|
-
|
|
11207
|
-
let firstStreamPending = true;
|
|
11208
|
-
const uploadBodyFactory = async () => {
|
|
11209
|
-
if (firstStreamPending) {
|
|
11210
|
-
firstStreamPending = false;
|
|
11211
|
-
return streamSource.stream;
|
|
11212
|
-
}
|
|
11213
|
-
return (await resolveStreamSource()).stream;
|
|
11214
|
-
};
|
|
11215
|
-
const job = new UploadJob(
|
|
11216
|
-
streamSource.stream,
|
|
11217
|
-
streamSource.mimeType,
|
|
11218
|
-
streamSource.size,
|
|
11219
|
-
source.videoMode,
|
|
11220
|
-
params,
|
|
11221
|
-
async () => {
|
|
11222
|
-
return this.session();
|
|
11223
|
-
},
|
|
11224
|
-
this._client,
|
|
11225
|
-
this._requestLogger,
|
|
11226
|
-
uploadBodyFactory,
|
|
11227
|
-
this.predictionVersion()
|
|
11228
|
-
);
|
|
11229
|
-
return job.start(
|
|
11230
|
-
() => {
|
|
11231
|
-
this.jobDone(job);
|
|
11232
|
-
},
|
|
11233
|
-
(statusCode) => {
|
|
11234
|
-
this.jobStatus(job, statusCode);
|
|
11235
|
-
}
|
|
11236
|
-
);
|
|
11237
|
-
} catch (e) {
|
|
11238
|
-
this._limit.release();
|
|
11239
|
-
throw e;
|
|
11695
|
+
this._consumed = true;
|
|
11696
|
+
while (true) {
|
|
11697
|
+
const item = await this._results.next();
|
|
11698
|
+
if (item === null) {
|
|
11699
|
+
return;
|
|
11700
|
+
}
|
|
11701
|
+
if (item instanceof Error) {
|
|
11702
|
+
throw item;
|
|
11703
|
+
}
|
|
11704
|
+
yield item;
|
|
11240
11705
|
}
|
|
11241
11706
|
}
|
|
11242
|
-
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11707
|
+
};
|
|
11708
|
+
var PipelineBackend = class {
|
|
11709
|
+
constructor(ctx) {
|
|
11710
|
+
this.ctx = ctx;
|
|
11711
|
+
this._pipelineApiUrl = null;
|
|
11712
|
+
this._socket = null;
|
|
11713
|
+
this._connecting = null;
|
|
11714
|
+
// Every job's setSource and every changePop goes out through this chain, in the order submitted.
|
|
11715
|
+
this._sendChain = Promise.resolve();
|
|
11716
|
+
this._disconnecting = false;
|
|
11717
|
+
this._nextId = 0;
|
|
11718
|
+
this._warned = /* @__PURE__ */ new Set();
|
|
11719
|
+
this._heartbeat = null;
|
|
11720
|
+
// Reconnects at once since a source last played.
|
|
11721
|
+
this._reconnects = 0;
|
|
11722
|
+
this._currentPop = ctx.options.pop ?? null;
|
|
11723
|
+
}
|
|
11724
|
+
// Connection
|
|
11725
|
+
async reconnect() {
|
|
11726
|
+
this._disconnecting = false;
|
|
11727
|
+
await this.inOrder(() => this.ensureSocket());
|
|
11728
|
+
this.ctx.updateState();
|
|
11729
|
+
}
|
|
11730
|
+
async disconnect(closeEndpoint) {
|
|
11731
|
+
await closeEndpoint();
|
|
11732
|
+
this._disconnecting = true;
|
|
11733
|
+
if (this._heartbeat !== null) {
|
|
11734
|
+
clearInterval(this._heartbeat);
|
|
11735
|
+
this._heartbeat = null;
|
|
11250
11736
|
}
|
|
11251
|
-
|
|
11252
|
-
|
|
11253
|
-
|
|
11737
|
+
const socket = this._socket;
|
|
11738
|
+
this._socket = null;
|
|
11739
|
+
if (socket !== null) {
|
|
11740
|
+
socket.ws.close(1e3);
|
|
11741
|
+
await socket.closed;
|
|
11254
11742
|
}
|
|
11255
|
-
|
|
11256
|
-
|
|
11257
|
-
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11263
|
-
|
|
11264
|
-
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
|
|
11268
|
-
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
|
|
11272
|
-
|
|
11273
|
-
this.jobStatus(job, statusCode);
|
|
11274
|
-
}
|
|
11275
|
-
);
|
|
11276
|
-
} catch (e) {
|
|
11277
|
-
this._limit.release();
|
|
11278
|
-
throw e;
|
|
11743
|
+
}
|
|
11744
|
+
onStatus(_statusCode) {
|
|
11745
|
+
}
|
|
11746
|
+
popName() {
|
|
11747
|
+
return null;
|
|
11748
|
+
}
|
|
11749
|
+
async authorizationHeader() {
|
|
11750
|
+
return this.ctx.credentialHeader();
|
|
11751
|
+
}
|
|
11752
|
+
inOrder(work) {
|
|
11753
|
+
const result = this._sendChain.then(work);
|
|
11754
|
+
this._sendChain = result.catch(() => void 0);
|
|
11755
|
+
return result;
|
|
11756
|
+
}
|
|
11757
|
+
/** The open socket, or a new one with the last pop set on it. */
|
|
11758
|
+
async ensureSocket() {
|
|
11759
|
+
if (this._socket !== null && this._socket.open) {
|
|
11760
|
+
return this._socket;
|
|
11279
11761
|
}
|
|
11762
|
+
if (this._connecting === null) {
|
|
11763
|
+
this._connecting = this.openSocket().finally(() => this._connecting = null);
|
|
11764
|
+
}
|
|
11765
|
+
return await this._connecting;
|
|
11280
11766
|
}
|
|
11281
|
-
async
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
throw new Error("endpoint not connected, use connect()");
|
|
11767
|
+
async openSocket() {
|
|
11768
|
+
if (this.ctx.client() === null) {
|
|
11769
|
+
throw new PipelineSocketClosedError(void 0, "the endpoint is not connected");
|
|
11285
11770
|
}
|
|
11286
|
-
await this.
|
|
11287
|
-
|
|
11288
|
-
|
|
11289
|
-
|
|
11290
|
-
|
|
11291
|
-
|
|
11292
|
-
|
|
11293
|
-
|
|
11294
|
-
},
|
|
11295
|
-
this._client,
|
|
11296
|
-
this._requestLogger,
|
|
11297
|
-
this.predictionVersion()
|
|
11298
|
-
);
|
|
11299
|
-
return job.start(
|
|
11300
|
-
() => {
|
|
11301
|
-
this.jobDone(job);
|
|
11302
|
-
},
|
|
11303
|
-
(statusCode) => {
|
|
11304
|
-
this.jobStatus(job, statusCode);
|
|
11771
|
+
const ws = await this.upgrade(await this.socketUrl());
|
|
11772
|
+
const socket = new PipelineSocket(ws);
|
|
11773
|
+
ws.onmessage = (event) => {
|
|
11774
|
+
if (typeof event.data === "string") {
|
|
11775
|
+
try {
|
|
11776
|
+
this.dispatch(socket, JSON.parse(event.data));
|
|
11777
|
+
} catch (error) {
|
|
11778
|
+
this.ctx.logger.warn("unreadable message from the pipeline API: %s", error);
|
|
11305
11779
|
}
|
|
11306
|
-
|
|
11307
|
-
}
|
|
11308
|
-
|
|
11309
|
-
|
|
11780
|
+
}
|
|
11781
|
+
};
|
|
11782
|
+
ws.onerror = () => {
|
|
11783
|
+
};
|
|
11784
|
+
ws.onclose = (event) => this.closed(socket, event.code, event.reason);
|
|
11785
|
+
this._socket = socket;
|
|
11786
|
+
this.startHeartbeat(ws);
|
|
11787
|
+
if (this._currentPop !== null) {
|
|
11788
|
+
try {
|
|
11789
|
+
await this.setPopOn(socket, this._currentPop);
|
|
11790
|
+
} catch (error) {
|
|
11791
|
+
this._socket = null;
|
|
11792
|
+
ws.close(1e3);
|
|
11793
|
+
throw error;
|
|
11794
|
+
}
|
|
11310
11795
|
}
|
|
11796
|
+
return socket;
|
|
11311
11797
|
}
|
|
11312
|
-
|
|
11313
|
-
|
|
11314
|
-
|
|
11315
|
-
throw new Error("endpoint not connected, use connect()");
|
|
11798
|
+
startHeartbeat(ws) {
|
|
11799
|
+
if (this._heartbeat !== null) {
|
|
11800
|
+
clearInterval(this._heartbeat);
|
|
11316
11801
|
}
|
|
11317
|
-
|
|
11318
|
-
|
|
11319
|
-
this.
|
|
11320
|
-
|
|
11321
|
-
|
|
11322
|
-
params,
|
|
11323
|
-
async () => {
|
|
11324
|
-
return this.session();
|
|
11325
|
-
},
|
|
11326
|
-
this._client,
|
|
11327
|
-
this._requestLogger,
|
|
11328
|
-
this.predictionVersion()
|
|
11329
|
-
);
|
|
11330
|
-
return job.start(
|
|
11331
|
-
() => {
|
|
11332
|
-
this.jobDone(job);
|
|
11333
|
-
},
|
|
11334
|
-
(statusCode) => {
|
|
11335
|
-
this.jobStatus(job, statusCode);
|
|
11802
|
+
const ping = ws.ping;
|
|
11803
|
+
if (typeof ping === "function") {
|
|
11804
|
+
this._heartbeat = setInterval(() => {
|
|
11805
|
+
if (ws.readyState === 1) {
|
|
11806
|
+
ping.call(ws);
|
|
11336
11807
|
}
|
|
11337
|
-
);
|
|
11338
|
-
|
|
11339
|
-
this._limit.release();
|
|
11340
|
-
throw e;
|
|
11808
|
+
}, HEARTBEAT_MS);
|
|
11809
|
+
this._heartbeat.unref?.();
|
|
11341
11810
|
}
|
|
11342
11811
|
}
|
|
11343
|
-
|
|
11344
|
-
this.
|
|
11345
|
-
|
|
11812
|
+
async socketUrl() {
|
|
11813
|
+
if (this._pipelineApiUrl === null) {
|
|
11814
|
+
const base = this.ctx.options.isLocalMode ? this.ctx.eyepopUrl() : new URL(await this.configuredPipelineApiUrl(), this.ctx.eyepopUrl() + "/").toString();
|
|
11815
|
+
this._pipelineApiUrl = checkedUrl(base);
|
|
11816
|
+
}
|
|
11817
|
+
return "ws" + this._pipelineApiUrl.slice("http".length) + PIPELINE_PATH;
|
|
11346
11818
|
}
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
|
|
11351
|
-
|
|
11819
|
+
async configuredPipelineApiUrl() {
|
|
11820
|
+
const client = this.ctx.client();
|
|
11821
|
+
if (client === null) {
|
|
11822
|
+
throw new Error("endpoint not connected");
|
|
11823
|
+
}
|
|
11824
|
+
let configUrl = `${this.ctx.eyepopUrl()}/v1/configs`;
|
|
11825
|
+
const accountId = this.ctx.options.accountId;
|
|
11826
|
+
if (accountId) {
|
|
11827
|
+
configUrl += `?account_uuid=${encodeURIComponent(accountId)}`;
|
|
11828
|
+
}
|
|
11829
|
+
const response = await this.ctx.fetchWithRetry(async () => client.fetch(configUrl, { headers: { Authorization: await this.ctx.credentialHeader() } }));
|
|
11830
|
+
if (!response.ok) {
|
|
11831
|
+
throw new Error(`Unexpected status ${response.status} for GET ${configUrl}: ${await response.text()}`);
|
|
11832
|
+
}
|
|
11833
|
+
const config = await response.json();
|
|
11834
|
+
const url = config?.["pipeline_api_url"];
|
|
11835
|
+
if (!url) {
|
|
11836
|
+
throw new PipelineConfigurationError("no_pipeline_api_url", `${configUrl} has no pipeline_api_url: this compute API serves no pipeline API`);
|
|
11837
|
+
}
|
|
11838
|
+
return url;
|
|
11839
|
+
}
|
|
11840
|
+
async token() {
|
|
11841
|
+
if (resolveAuth(this.ctx.options)?.isLocal !== void 0) {
|
|
11842
|
+
return void 0;
|
|
11352
11843
|
}
|
|
11844
|
+
return (await this.ctx.credentialHeader()).replace(/^Bearer /, "");
|
|
11353
11845
|
}
|
|
11354
|
-
|
|
11355
|
-
|
|
11356
|
-
|
|
11357
|
-
|
|
11358
|
-
|
|
11846
|
+
/** Open the socket, waiting through 503 with Retry-After and exchanging the API key again after a 401. */
|
|
11847
|
+
async upgrade(url) {
|
|
11848
|
+
const deadline = Date.now() + MAX_RETRY_MS;
|
|
11849
|
+
let rejected = false;
|
|
11850
|
+
while (true) {
|
|
11851
|
+
try {
|
|
11852
|
+
this.ctx.requestLogger.debug("before upgrade %s", url);
|
|
11853
|
+
return await openAuthorizedWebSocket(url, SUBPROTOCOL, await this.token());
|
|
11854
|
+
} catch (error) {
|
|
11855
|
+
if (!(error instanceof UpgradeError)) {
|
|
11856
|
+
throw error;
|
|
11857
|
+
}
|
|
11858
|
+
if (error.status === 401 && !rejected) {
|
|
11859
|
+
this.ctx.requestLogger.debug("the pipeline API answered 401, authenticating again");
|
|
11860
|
+
rejected = true;
|
|
11861
|
+
this.ctx.forgetCredential();
|
|
11862
|
+
continue;
|
|
11863
|
+
}
|
|
11864
|
+
const wait = error.status === 503 && error.retryAfter !== void 0 ? Math.max(error.retryAfter, 1) * 1e3 : void 0;
|
|
11865
|
+
if (wait === void 0 || Date.now() + wait > deadline) {
|
|
11866
|
+
throw error;
|
|
11867
|
+
}
|
|
11868
|
+
this.ctx.requestLogger.info("the pipeline API answered 503, retrying in %d ms", wait);
|
|
11869
|
+
await new Promise((resolve) => setTimeout(resolve, wait));
|
|
11359
11870
|
}
|
|
11360
|
-
} else if (this.options().sessionUuid) {
|
|
11361
|
-
await this.getComputeSession();
|
|
11362
|
-
} else {
|
|
11363
|
-
await this.startWebApiSessionWithPopId();
|
|
11364
11871
|
}
|
|
11365
|
-
this.updateState();
|
|
11366
|
-
return Promise.resolve(this);
|
|
11367
11872
|
}
|
|
11368
|
-
|
|
11369
|
-
|
|
11370
|
-
|
|
11873
|
+
closed(socket, code, reason) {
|
|
11874
|
+
socket.markClosed();
|
|
11875
|
+
if (this._socket === socket) {
|
|
11876
|
+
this._socket = null;
|
|
11371
11877
|
}
|
|
11372
|
-
const
|
|
11373
|
-
|
|
11374
|
-
|
|
11375
|
-
|
|
11376
|
-
this.
|
|
11377
|
-
|
|
11378
|
-
if (response.status == 401) {
|
|
11379
|
-
this._requestLogger.debug("GET %s: 401, about to retry with fresh access token", config_url);
|
|
11380
|
-
this.statusHandler401(response.status);
|
|
11381
|
-
const headers2 = {
|
|
11382
|
-
Authorization: await this.authorizationHeader()
|
|
11383
|
-
};
|
|
11384
|
-
this.updateState("FetchConfig" /* FetchConfig */);
|
|
11385
|
-
response = await this._client.fetch(config_url, {
|
|
11386
|
-
headers: headers2
|
|
11387
|
-
});
|
|
11878
|
+
const error = new PipelineSocketClosedError(code, reason);
|
|
11879
|
+
socket.sources.forEach((source) => source.close(error));
|
|
11880
|
+
socket.commands.forEach((command) => command.reject(error));
|
|
11881
|
+
socket.commands.clear();
|
|
11882
|
+
if (this._disconnecting) {
|
|
11883
|
+
return;
|
|
11388
11884
|
}
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
if (
|
|
11392
|
-
this.
|
|
11393
|
-
} else {
|
|
11394
|
-
this.updateState("Error" /* Error */, message);
|
|
11885
|
+
this.ctx.requestLogger.debug("the pipeline API closed the socket: %s %s", code, reason);
|
|
11886
|
+
if (RECONNECT_AT_ONCE.has(`${code} ${reason}`)) {
|
|
11887
|
+
if (reason === "credential_expired") {
|
|
11888
|
+
this.ctx.forgetCredential();
|
|
11395
11889
|
}
|
|
11396
|
-
|
|
11397
|
-
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
const auto_start_config_url = `${this.eyepopWebApiUrl()}/pops/${this.options().popId}/config?auto_start=true`;
|
|
11401
|
-
this._requestLogger.debug("pop was not running, trying to autostart with: %s", auto_start_config_url);
|
|
11402
|
-
const headers2 = {
|
|
11403
|
-
Authorization: await this.authorizationHeader()
|
|
11404
|
-
};
|
|
11405
|
-
response = await this._client.fetch(auto_start_config_url, {
|
|
11406
|
-
headers: headers2
|
|
11890
|
+
const delay = this._reconnects === 0 ? 0 : Math.min(1e3 * 2 ** (this._reconnects - 1), MAX_RECONNECT_DELAY_MS);
|
|
11891
|
+
this._reconnects += 1;
|
|
11892
|
+
new Promise((resolve) => setTimeout(resolve, delay)).then(() => this._disconnecting ? void 0 : this.inOrder(() => this.ensureSocket())).catch((error2) => {
|
|
11893
|
+
this.ctx.requestLogger.info("could not reopen the pipeline API socket: %s", error2);
|
|
11407
11894
|
});
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
|
|
11895
|
+
}
|
|
11896
|
+
}
|
|
11897
|
+
dispatch(socket, message) {
|
|
11898
|
+
const type = message["type"];
|
|
11899
|
+
const id = message["id"];
|
|
11900
|
+
const source = typeof id === "string" ? socket.sources.get(id) : void 0;
|
|
11901
|
+
if (type === "send" || type === "credit") {
|
|
11902
|
+
const upload = source?.uploads.get(message["member"] ?? null);
|
|
11903
|
+
upload?.grant(Number(type === "send" ? message["credit"] : message["bytes"]));
|
|
11904
|
+
return;
|
|
11905
|
+
}
|
|
11906
|
+
const command = typeof id === "string" ? socket.commands.get(id) : void 0;
|
|
11907
|
+
if (command !== void 0) {
|
|
11908
|
+
socket.commands.delete(id);
|
|
11909
|
+
if (type === "error") {
|
|
11910
|
+
command.reject(new PipelineCommandError(message["error"] ?? "", message["message"] ?? ""));
|
|
11911
|
+
} else {
|
|
11912
|
+
command.resolve(message);
|
|
11412
11913
|
}
|
|
11413
|
-
|
|
11914
|
+
return;
|
|
11414
11915
|
}
|
|
11415
|
-
|
|
11416
|
-
|
|
11417
|
-
|
|
11418
|
-
this._baseUrl = this._baseUrl.replace(/\/+$/, "");
|
|
11419
|
-
this._pipelineId = config.pipeline_id;
|
|
11420
|
-
this._popName = config.name;
|
|
11421
|
-
if (!this._pipelineId || !this._baseUrl) {
|
|
11422
|
-
throw new Error("Pop not started");
|
|
11916
|
+
if (source !== void 0) {
|
|
11917
|
+
if (type === "start") {
|
|
11918
|
+
this._reconnects = 0;
|
|
11423
11919
|
}
|
|
11424
|
-
|
|
11425
|
-
|
|
11426
|
-
Authorization: await this.authorizationHeader()
|
|
11427
|
-
};
|
|
11428
|
-
let response2 = await this._client.fetch(get_url, {
|
|
11429
|
-
method: "GET",
|
|
11430
|
-
headers: headers2
|
|
11431
|
-
});
|
|
11432
|
-
if (response2.status > 200) {
|
|
11433
|
-
const message = await response2.text();
|
|
11434
|
-
throw new Error(`Unexpected status ${response2.status}: ${message}`);
|
|
11920
|
+
if (type === "end") {
|
|
11921
|
+
source.uploads.forEach((upload) => upload.end());
|
|
11435
11922
|
}
|
|
11436
|
-
|
|
11437
|
-
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11441
|
-
|
|
11442
|
-
};
|
|
11443
|
-
const stop_url = `${this._baseUrl}/pipelines/${this._pipeline.id}/source?mode=preempt&processing=sync`;
|
|
11444
|
-
let response3 = await this._client.fetch(stop_url, {
|
|
11445
|
-
method: "PATCH",
|
|
11446
|
-
headers: headers3,
|
|
11447
|
-
body: JSON.stringify(body)
|
|
11448
|
-
});
|
|
11449
|
-
if (response3.status >= 300) {
|
|
11450
|
-
const message = await response3.text();
|
|
11451
|
-
throw new Error(`Unexpected status ${response3.status}: ${message}`);
|
|
11452
|
-
}
|
|
11923
|
+
source.inbox.push(message);
|
|
11924
|
+
} else if (type === "error") {
|
|
11925
|
+
if (id === void 0) {
|
|
11926
|
+
this.ctx.logger.warn("the pipeline API refused a message: %s %s", message["error"], message["message"]);
|
|
11927
|
+
} else {
|
|
11928
|
+
this.ctx.requestLogger.debug("the pipeline API refused a command for %s: %s %s", id, message["error"], message["message"]);
|
|
11453
11929
|
}
|
|
11454
11930
|
}
|
|
11455
11931
|
}
|
|
11456
|
-
|
|
11457
|
-
|
|
11458
|
-
return
|
|
11932
|
+
newId(prefix) {
|
|
11933
|
+
this._nextId += 1;
|
|
11934
|
+
return `${prefix}-${this._nextId}`;
|
|
11459
11935
|
}
|
|
11460
|
-
|
|
11461
|
-
|
|
11462
|
-
|
|
11936
|
+
/** Send a command that is answered by `result` or `error` under its id. */
|
|
11937
|
+
command(socket, message) {
|
|
11938
|
+
const id = this.newId(message["type"]);
|
|
11939
|
+
return new Promise((resolve, reject) => {
|
|
11940
|
+
socket.commands.set(id, { resolve, reject });
|
|
11941
|
+
socket.sendJson({ ...message, id });
|
|
11942
|
+
});
|
|
11943
|
+
}
|
|
11944
|
+
// Pop
|
|
11945
|
+
pop() {
|
|
11946
|
+
return this._currentPop;
|
|
11947
|
+
}
|
|
11948
|
+
/** Set the pop on the socket's pipeline; a pop it refuses rejects, and the last pop it took stays. */
|
|
11949
|
+
async changePop(pop) {
|
|
11950
|
+
if (this.ctx.client() === null) {
|
|
11951
|
+
this._currentPop = pop;
|
|
11952
|
+
return;
|
|
11463
11953
|
}
|
|
11464
|
-
|
|
11465
|
-
|
|
11466
|
-
|
|
11467
|
-
|
|
11468
|
-
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11954
|
+
await this.inOrder(async () => {
|
|
11955
|
+
if (this._socket !== null && this._socket.open) {
|
|
11956
|
+
await this.setPopOn(this._socket, pop);
|
|
11957
|
+
this._currentPop = pop;
|
|
11958
|
+
return;
|
|
11959
|
+
}
|
|
11960
|
+
const previous = this._currentPop;
|
|
11961
|
+
this._currentPop = pop;
|
|
11962
|
+
try {
|
|
11963
|
+
await this.ensureSocket();
|
|
11964
|
+
} catch (error) {
|
|
11965
|
+
this._currentPop = previous;
|
|
11966
|
+
throw error;
|
|
11967
|
+
}
|
|
11968
|
+
});
|
|
11969
|
+
}
|
|
11970
|
+
async setPopOn(socket, pop) {
|
|
11971
|
+
await this.command(socket, { type: "setPop", pop });
|
|
11972
|
+
}
|
|
11973
|
+
// Jobs
|
|
11974
|
+
async submit(work) {
|
|
11975
|
+
if (this.ctx.client() === null) {
|
|
11976
|
+
throw new Error("endpoint not connected, use connect()");
|
|
11483
11977
|
}
|
|
11484
|
-
|
|
11485
|
-
this.
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
this.
|
|
11490
|
-
|
|
11491
|
-
|
|
11978
|
+
const sourceOptions = work.kind === "source" ? work.source : void 0;
|
|
11979
|
+
this.notSent({ motionDetect: work.params.motionDetect, videoMode: sourceOptions?.videoMode, rtspForceNonCompliantUrl: work.params.rtspForceNonCompliantUrl });
|
|
11980
|
+
const job = await this.jobOf(work);
|
|
11981
|
+
const limit = this.ctx.limit();
|
|
11982
|
+
await limit.acquire();
|
|
11983
|
+
this.ctx.updateState();
|
|
11984
|
+
this.run(job).then(
|
|
11985
|
+
() => job.finish(),
|
|
11986
|
+
(error) => job.finish(error instanceof Error ? error : new Error(String(error)))
|
|
11987
|
+
).finally(() => this.ctx.jobDone());
|
|
11988
|
+
return job;
|
|
11989
|
+
}
|
|
11990
|
+
notSent(options) {
|
|
11991
|
+
for (const [name, value] of Object.entries(options)) {
|
|
11992
|
+
if (value === void 0 || this._warned.has(name)) {
|
|
11993
|
+
continue;
|
|
11994
|
+
}
|
|
11995
|
+
this._warned.add(name);
|
|
11996
|
+
const ticket = name === "rtspForceNonCompliantUrl" ? "" : " (AWSU-317)";
|
|
11997
|
+
this.ctx.logger.warn(`${name} is not sent to the pipeline API and has no effect in pipeline mode${ticket}`);
|
|
11998
|
+
}
|
|
11999
|
+
}
|
|
12000
|
+
async jobOf(work) {
|
|
12001
|
+
switch (work.kind) {
|
|
12002
|
+
case "source":
|
|
12003
|
+
return await this.sourceJob(work.source, work.params);
|
|
12004
|
+
case "uploadGroup": {
|
|
12005
|
+
const media = await Promise.all(work.paths.map((path2) => this.pathMedia({ path: path2 })));
|
|
12006
|
+
return new PipelineJob(uploadGroup(media), media, false, work.params);
|
|
12007
|
+
}
|
|
12008
|
+
case "uploadStreamGroup": {
|
|
12009
|
+
const media = work.streams.map((stream, i) => bodyMedia(stream, work.mimeTypes?.[i] ?? "application/octet-stream", void 0));
|
|
12010
|
+
return new PipelineJob(uploadGroup(media), media, false, work.params);
|
|
12011
|
+
}
|
|
12012
|
+
case "loadFromGroup":
|
|
12013
|
+
return new PipelineJob({ group: work.urls.map((url) => ({ url })) }, [], false, work.params);
|
|
11492
12014
|
}
|
|
11493
12015
|
}
|
|
11494
|
-
async
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
|
|
11499
|
-
}
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
} else if (
|
|
11504
|
-
|
|
11505
|
-
|
|
11506
|
-
|
|
12016
|
+
async sourceJob(source, params) {
|
|
12017
|
+
if (source.file !== void 0) {
|
|
12018
|
+
const file = source.file;
|
|
12019
|
+
const media = bodyMedia(file, file.type || "application/octet-stream", file.size);
|
|
12020
|
+
return new PipelineJob({ upload: { contentType: media.contentType } }, [media], false, params);
|
|
12021
|
+
} else if (source.stream !== void 0) {
|
|
12022
|
+
const stream = source;
|
|
12023
|
+
const media = bodyMedia(stream.stream, stream.mimeType, stream.size ?? knownSize(stream.stream));
|
|
12024
|
+
return new PipelineJob({ upload: { contentType: media.contentType } }, [media], false, params);
|
|
12025
|
+
} else if (source.path !== void 0) {
|
|
12026
|
+
const media = await this.pathMedia(source);
|
|
12027
|
+
return new PipelineJob({ upload: { contentType: media.contentType } }, [media], false, params);
|
|
12028
|
+
} else if (source.url !== void 0) {
|
|
12029
|
+
const url = source.url;
|
|
12030
|
+
if (url.startsWith("file://")) {
|
|
12031
|
+
return await this.sourceJob({ path: url.substring("file://".length) }, params);
|
|
12032
|
+
}
|
|
12033
|
+
return new PipelineJob({ url }, [], /^(rtsp|rtmp):\/\//.test(url), params);
|
|
12034
|
+
} else if (source.assetUuid !== void 0) {
|
|
12035
|
+
return new PipelineJob({ assetUuid: source.assetUuid }, [], false, params);
|
|
12036
|
+
} else if (source.mediaStream !== void 0) {
|
|
12037
|
+
const ingressId = this.newId("whip");
|
|
12038
|
+
return new PipelineJob({ whip: { ingressId } }, [], true, params, source.mediaStream);
|
|
11507
12039
|
}
|
|
11508
|
-
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
|
|
11512
|
-
|
|
11513
|
-
|
|
11514
|
-
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
|
|
11523
|
-
|
|
11524
|
-
|
|
11525
|
-
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
|
|
11530
|
-
|
|
11531
|
-
const
|
|
11532
|
-
|
|
12040
|
+
throw new Error("unknown source type");
|
|
12041
|
+
}
|
|
12042
|
+
async pathMedia(source) {
|
|
12043
|
+
const options = this.ctx.options;
|
|
12044
|
+
const resolve = async () => options.platformSupport?.resolvePath ? await options.platformSupport.resolvePath(source, this.ctx.logger) : await resolvePath(source, this.ctx.logger);
|
|
12045
|
+
const first = await resolve();
|
|
12046
|
+
let firstPending = true;
|
|
12047
|
+
return {
|
|
12048
|
+
contentType: first.mimeType,
|
|
12049
|
+
size: first.size,
|
|
12050
|
+
open: async () => {
|
|
12051
|
+
if (firstPending) {
|
|
12052
|
+
firstPending = false;
|
|
12053
|
+
return first.stream;
|
|
12054
|
+
}
|
|
12055
|
+
return (await resolve()).stream;
|
|
12056
|
+
}
|
|
12057
|
+
};
|
|
12058
|
+
}
|
|
12059
|
+
/** Run the job's source to its end; a live source refused overloaded goes once more on a new socket. */
|
|
12060
|
+
async run(job) {
|
|
12061
|
+
let retried = false;
|
|
12062
|
+
while (true) {
|
|
12063
|
+
const sent = await this.inOrder(() => this.setSource(job));
|
|
12064
|
+
if (sent === null) {
|
|
12065
|
+
return;
|
|
12066
|
+
}
|
|
12067
|
+
const { socket, source } = sent;
|
|
12068
|
+
const uploading = source.uploads.size > 0 ? this.upload(socket, source, job) : Promise.resolve();
|
|
12069
|
+
let whip = null;
|
|
12070
|
+
let overloaded;
|
|
12071
|
+
try {
|
|
12072
|
+
overloaded = await this.follow(job, source, () => {
|
|
12073
|
+
if (job.mediaStream !== void 0) {
|
|
12074
|
+
const fail = (error) => {
|
|
12075
|
+
job.stopOnPipeline?.();
|
|
12076
|
+
source.inbox.push(error instanceof Error ? error : new Error(String(error)));
|
|
12077
|
+
};
|
|
12078
|
+
whip = new SocketWhip(job.mediaStream, job.source["whip"]["ingressId"], (message) => this.command(socket, message), fail, this.ctx.requestLogger);
|
|
12079
|
+
whip.start().catch(fail);
|
|
12080
|
+
}
|
|
12081
|
+
});
|
|
12082
|
+
} finally {
|
|
12083
|
+
job.openSource = null;
|
|
12084
|
+
job.stopOnPipeline = null;
|
|
12085
|
+
socket.sources.delete(source.id);
|
|
12086
|
+
source.uploads.forEach((upload) => upload.end());
|
|
12087
|
+
await uploading;
|
|
12088
|
+
await whip?.close();
|
|
12089
|
+
}
|
|
12090
|
+
if (!overloaded) {
|
|
12091
|
+
return;
|
|
12092
|
+
}
|
|
12093
|
+
if (retried || !job.live) {
|
|
12094
|
+
throw new PipelineCommandError("overloaded", "the pipeline API has no capacity for another live source");
|
|
12095
|
+
}
|
|
12096
|
+
retried = true;
|
|
12097
|
+
await socket.closed;
|
|
11533
12098
|
}
|
|
11534
|
-
const result = await response.json();
|
|
11535
|
-
return result["id"];
|
|
11536
12099
|
}
|
|
11537
|
-
|
|
11538
|
-
|
|
11539
|
-
|
|
12100
|
+
/** Send the job's setSource; the caller runs it in submission order. */
|
|
12101
|
+
async setSource(job) {
|
|
12102
|
+
if (job.cancelled) {
|
|
12103
|
+
return null;
|
|
11540
12104
|
}
|
|
11541
|
-
|
|
11542
|
-
|
|
12105
|
+
const combined = await combinedMedia(job);
|
|
12106
|
+
const socket = await this.ensureSocket();
|
|
12107
|
+
const source = new OpenSource(this.newId("source"));
|
|
12108
|
+
if (combined === null) {
|
|
12109
|
+
uploadKeys(job).forEach((key) => source.uploads.set(key, new Credit()));
|
|
12110
|
+
}
|
|
12111
|
+
socket.sources.set(source.id, source);
|
|
12112
|
+
job.openSource = source;
|
|
12113
|
+
job.stopOnPipeline = () => {
|
|
12114
|
+
if (socket.open) {
|
|
12115
|
+
socket.sendJson({ type: "stopSource", id: source.id });
|
|
12116
|
+
}
|
|
12117
|
+
};
|
|
12118
|
+
const command = job.command(source.id);
|
|
12119
|
+
if (combined === null) {
|
|
12120
|
+
socket.sendJson(command);
|
|
12121
|
+
} else {
|
|
12122
|
+
socket.sendBytes(combinedMessage(command, combined));
|
|
11543
12123
|
}
|
|
11544
|
-
|
|
11545
|
-
|
|
12124
|
+
return { socket, source };
|
|
12125
|
+
}
|
|
12126
|
+
/** Hand the source's predictions to the job until it ends; true when the pipeline API was overloaded. */
|
|
12127
|
+
async follow(job, source, onResult) {
|
|
12128
|
+
while (true) {
|
|
12129
|
+
if (job.cancelled) {
|
|
12130
|
+
return false;
|
|
12131
|
+
}
|
|
12132
|
+
const message = await source.inbox.next();
|
|
12133
|
+
if (message === CANCELLED) {
|
|
12134
|
+
return false;
|
|
12135
|
+
}
|
|
12136
|
+
if (message instanceof Error) {
|
|
12137
|
+
throw message;
|
|
12138
|
+
}
|
|
12139
|
+
switch (message["type"]) {
|
|
12140
|
+
case "result":
|
|
12141
|
+
onResult();
|
|
12142
|
+
break;
|
|
12143
|
+
case "prediction":
|
|
12144
|
+
job.predicted(message["prediction"]);
|
|
12145
|
+
break;
|
|
12146
|
+
case "end":
|
|
12147
|
+
if (message["reason"] === "eos") {
|
|
12148
|
+
return false;
|
|
12149
|
+
}
|
|
12150
|
+
throw new PipelineSourceError(source.id, message["reason"] ?? "", message["message"] ?? "");
|
|
12151
|
+
case "error":
|
|
12152
|
+
if (message["error"] === "overloaded") {
|
|
12153
|
+
return true;
|
|
12154
|
+
}
|
|
12155
|
+
throw new PipelineCommandError(message["error"] ?? "", message["message"] ?? "");
|
|
12156
|
+
case "dropped":
|
|
12157
|
+
this.ctx.requestLogger.debug("the pipeline API dropped %s predictions of a live source", message["count"]);
|
|
12158
|
+
break;
|
|
12159
|
+
}
|
|
11546
12160
|
}
|
|
11547
|
-
|
|
11548
|
-
|
|
12161
|
+
}
|
|
12162
|
+
/** Send each upload member's bytes in chunks within its credit, then its uploaded. */
|
|
12163
|
+
async upload(socket, source, job) {
|
|
12164
|
+
const keys = uploadKeys(job);
|
|
12165
|
+
try {
|
|
12166
|
+
for (let i = 0; i < keys.length; i++) {
|
|
12167
|
+
const key = keys[i];
|
|
12168
|
+
const credit = source.uploads.get(key);
|
|
12169
|
+
for await (let piece of pieces(await job.media[i].open())) {
|
|
12170
|
+
while (piece.length > 0) {
|
|
12171
|
+
const n = await credit.take(Math.min(piece.length, CHUNK_BYTES));
|
|
12172
|
+
const chunk = new Uint8Array(n + 1);
|
|
12173
|
+
chunk[0] = CHUNK;
|
|
12174
|
+
chunk.set(piece.subarray(0, n), 1);
|
|
12175
|
+
socket.sendBytes(chunk);
|
|
12176
|
+
piece = piece.subarray(n);
|
|
12177
|
+
}
|
|
12178
|
+
}
|
|
12179
|
+
socket.sendJson(key === null ? { type: "uploaded", id: source.id } : { type: "uploaded", id: source.id, member: key });
|
|
12180
|
+
}
|
|
12181
|
+
} catch (error) {
|
|
12182
|
+
if (!(error instanceof UploadEnded)) {
|
|
12183
|
+
if (socket.open) {
|
|
12184
|
+
source.inbox.push(error instanceof Error ? error : new Error(String(error)));
|
|
12185
|
+
}
|
|
12186
|
+
}
|
|
11549
12187
|
}
|
|
11550
|
-
|
|
11551
|
-
|
|
11552
|
-
|
|
11553
|
-
|
|
12188
|
+
}
|
|
12189
|
+
async session() {
|
|
12190
|
+
const token = await this.token();
|
|
12191
|
+
const validUntil = token === void 0 ? Number.MAX_VALUE : Math.min((await this.ctx.credentialSession()).validUntil, Number.MAX_VALUE);
|
|
12192
|
+
return {
|
|
12193
|
+
eyepopUrl: this.ctx.eyepopUrl(),
|
|
12194
|
+
accessToken: token ?? "",
|
|
12195
|
+
validUntil,
|
|
12196
|
+
popId: "transient",
|
|
12197
|
+
accountId: this.ctx.options.accountId,
|
|
12198
|
+
baseUrl: this._pipelineApiUrl ?? void 0,
|
|
12199
|
+
pipelineId: void 0,
|
|
12200
|
+
isPipelineMode: true,
|
|
12201
|
+
authenticationHeaders: () => token === void 0 ? {} : { Authorization: `Bearer ${token}` }
|
|
12202
|
+
};
|
|
12203
|
+
}
|
|
12204
|
+
};
|
|
12205
|
+
var SocketWhip = class {
|
|
12206
|
+
constructor(_stream, _ingressId, _command, _fail, _logger) {
|
|
12207
|
+
this._stream = _stream;
|
|
12208
|
+
this._ingressId = _ingressId;
|
|
12209
|
+
this._command = _command;
|
|
12210
|
+
this._fail = _fail;
|
|
12211
|
+
this._logger = _logger;
|
|
12212
|
+
this._pc = null;
|
|
12213
|
+
this._answered = false;
|
|
12214
|
+
this._queued = [];
|
|
12215
|
+
this._offerData = null;
|
|
12216
|
+
}
|
|
12217
|
+
async start() {
|
|
12218
|
+
const servers = await this._command({ type: "whipIceServers", ingressId: this._ingressId });
|
|
12219
|
+
const iceServers = servers["iceServers"] ?? [];
|
|
12220
|
+
this._logger.debug("whip %s: ice servers %j", this._ingressId, iceServers.map((server) => server.split(";")[0]));
|
|
12221
|
+
const pc = new RTCPeerConnection({ iceServers: WebrtcBase.linkToIceServers(iceServers.join(", ") || null) });
|
|
12222
|
+
this._pc = pc;
|
|
12223
|
+
pc.oniceconnectionstatechange = () => {
|
|
12224
|
+
this._logger.debug("whip %s: ice connection %s", this._ingressId, pc.iceConnectionState);
|
|
12225
|
+
if (pc.iceConnectionState === "failed" && this._pc === pc) {
|
|
12226
|
+
this._fail(
|
|
12227
|
+
new Error(
|
|
12228
|
+
`the WebRTC connection of whip ingress ${this._ingressId} failed: no candidate pair connected, so the pipeline API is likely reachable through no STUN or TURN server (ice servers: ${iceServers.length})`
|
|
12229
|
+
)
|
|
12230
|
+
);
|
|
12231
|
+
}
|
|
12232
|
+
};
|
|
12233
|
+
pc.onicecandidate = (evt) => {
|
|
12234
|
+
if (evt.candidate !== null) {
|
|
12235
|
+
this.candidate(evt.candidate).catch((error) => this._logger.debug("whipIce failed: %s", error));
|
|
11554
12236
|
}
|
|
12237
|
+
};
|
|
12238
|
+
this._stream.getTracks().forEach((track) => pc.addTrack(track, this._stream));
|
|
12239
|
+
const offer = await pc.createOffer();
|
|
12240
|
+
if (!offer.sdp) {
|
|
12241
|
+
throw new Error("the local offer has no sdp");
|
|
12242
|
+
}
|
|
12243
|
+
this._offerData = WebrtcBase.parseOffer(offer.sdp);
|
|
12244
|
+
await pc.setLocalDescription(offer);
|
|
12245
|
+
const answer = await this._command({ type: "whipOffer", ingressId: this._ingressId, sdp: offer.sdp });
|
|
12246
|
+
await pc.setRemoteDescription({ type: "answer", sdp: answer["sdp"] });
|
|
12247
|
+
this._answered = true;
|
|
12248
|
+
const queued = this._queued;
|
|
12249
|
+
this._queued = [];
|
|
12250
|
+
if (queued.length > 0) {
|
|
12251
|
+
await this.sendCandidates(queued);
|
|
12252
|
+
}
|
|
12253
|
+
}
|
|
12254
|
+
async candidate(candidate) {
|
|
12255
|
+
if (!this._answered) {
|
|
12256
|
+
this._queued.push(candidate);
|
|
11555
12257
|
return;
|
|
11556
12258
|
}
|
|
11557
|
-
|
|
11558
|
-
|
|
12259
|
+
await this.sendCandidates([candidate]);
|
|
12260
|
+
}
|
|
12261
|
+
async sendCandidates(candidates) {
|
|
12262
|
+
if (this._offerData === null) {
|
|
12263
|
+
return;
|
|
11559
12264
|
}
|
|
12265
|
+
await this._command({ type: "whipIce", ingressId: this._ingressId, fragment: WebrtcBase.generateSdpFragment(this._offerData, candidates) });
|
|
12266
|
+
}
|
|
12267
|
+
async close() {
|
|
12268
|
+
this._stream.getTracks().forEach((track) => track.stop());
|
|
12269
|
+
const pc = this._pc;
|
|
12270
|
+
this._pc = null;
|
|
12271
|
+
pc?.close();
|
|
12272
|
+
}
|
|
12273
|
+
};
|
|
12274
|
+
function checkedUrl(url) {
|
|
12275
|
+
const parsed = new URL(url);
|
|
12276
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
12277
|
+
throw new PipelineConfigurationError("insecure_url", `the pipeline API url ${url} must be an http or https url`);
|
|
12278
|
+
}
|
|
12279
|
+
if (parsed.protocol === "http:" && !isLoopback(parsed.hostname)) {
|
|
12280
|
+
throw new PipelineConfigurationError("insecure_url", `the pipeline API url ${url} must use https unless its host is a loopback address`);
|
|
12281
|
+
}
|
|
12282
|
+
return url.replace(/\/+$/, "");
|
|
12283
|
+
}
|
|
12284
|
+
function isLoopback(host) {
|
|
12285
|
+
return host === "localhost" || host === "[::1]" || host === "::1" || /^127\.\d+\.\d+\.\d+$/.test(host);
|
|
12286
|
+
}
|
|
12287
|
+
function knownSize(body) {
|
|
12288
|
+
if (typeof Blob !== "undefined" && body instanceof Blob) {
|
|
12289
|
+
return body.size;
|
|
12290
|
+
}
|
|
12291
|
+
if (ArrayBuffer.isView(body) || body instanceof ArrayBuffer) {
|
|
12292
|
+
return body.byteLength;
|
|
12293
|
+
}
|
|
12294
|
+
return void 0;
|
|
12295
|
+
}
|
|
12296
|
+
function bodyMedia(body, contentType, size) {
|
|
12297
|
+
return { open: async () => body, contentType, size: size ?? knownSize(body) };
|
|
12298
|
+
}
|
|
12299
|
+
function uploadGroup(media) {
|
|
12300
|
+
return { group: media.map((m) => ({ upload: { contentType: m.contentType } })) };
|
|
12301
|
+
}
|
|
12302
|
+
function uploadKeys(job) {
|
|
12303
|
+
if (job.source["upload"] !== void 0) {
|
|
12304
|
+
return [null];
|
|
12305
|
+
}
|
|
12306
|
+
const group = job.source["group"] ?? [];
|
|
12307
|
+
return group.flatMap((member, i) => member["upload"] !== void 0 ? [i] : []);
|
|
12308
|
+
}
|
|
12309
|
+
async function combinedMedia(job) {
|
|
12310
|
+
if (job.media.length === 0 || job.live || job.media.some((m) => m.size === void 0)) {
|
|
12311
|
+
return null;
|
|
12312
|
+
}
|
|
12313
|
+
if (job.media.reduce((total, m) => total + (m.size ?? 0), 0) > COMBINED_UPLOAD_MAX_BYTES) {
|
|
12314
|
+
return null;
|
|
12315
|
+
}
|
|
12316
|
+
const bytes = [];
|
|
12317
|
+
for (const media of job.media) {
|
|
12318
|
+
bytes.push(await readAll(await media.open()));
|
|
12319
|
+
}
|
|
12320
|
+
return bytes;
|
|
12321
|
+
}
|
|
12322
|
+
async function readAll(body) {
|
|
12323
|
+
const parts = [];
|
|
12324
|
+
for await (const piece of pieces(body)) {
|
|
12325
|
+
parts.push(piece);
|
|
12326
|
+
}
|
|
12327
|
+
return concat(parts);
|
|
12328
|
+
}
|
|
12329
|
+
function concat(parts) {
|
|
12330
|
+
const all = new Uint8Array(parts.reduce((total, p) => total + p.length, 0));
|
|
12331
|
+
let offset = 0;
|
|
12332
|
+
for (const part of parts) {
|
|
12333
|
+
all.set(part, offset);
|
|
12334
|
+
offset += part.length;
|
|
12335
|
+
}
|
|
12336
|
+
return all;
|
|
12337
|
+
}
|
|
12338
|
+
function combinedMessage(command, media) {
|
|
12339
|
+
if (command["group"] !== void 0) {
|
|
12340
|
+
let i = 0;
|
|
12341
|
+
command = {
|
|
12342
|
+
...command,
|
|
12343
|
+
group: command["group"].map((member) => member["upload"] !== void 0 ? { upload: { ...member["upload"], bytes: media[i++].length } } : member)
|
|
12344
|
+
};
|
|
12345
|
+
}
|
|
12346
|
+
const header = new TextEncoder().encode(JSON.stringify(command));
|
|
12347
|
+
const prefix = new Uint8Array(5);
|
|
12348
|
+
prefix[0] = COMBINED;
|
|
12349
|
+
new DataView(prefix.buffer).setUint32(1, header.length, false);
|
|
12350
|
+
return concat([prefix, header, ...media]);
|
|
12351
|
+
}
|
|
12352
|
+
async function* pieces(body) {
|
|
12353
|
+
if (typeof Blob !== "undefined" && body instanceof Blob) {
|
|
12354
|
+
yield* pieces(body.stream());
|
|
12355
|
+
} else if (body instanceof ArrayBuffer) {
|
|
12356
|
+
yield new Uint8Array(body);
|
|
12357
|
+
} else if (ArrayBuffer.isView(body)) {
|
|
12358
|
+
yield new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
|
|
12359
|
+
} else {
|
|
12360
|
+
const reader = body.getReader();
|
|
11560
12361
|
try {
|
|
11561
|
-
|
|
11562
|
-
|
|
12362
|
+
while (true) {
|
|
12363
|
+
const { value, done } = await reader.read();
|
|
12364
|
+
if (done) {
|
|
12365
|
+
return;
|
|
12366
|
+
}
|
|
12367
|
+
if (value !== void 0 && value.length > 0) {
|
|
12368
|
+
yield value;
|
|
12369
|
+
}
|
|
12370
|
+
}
|
|
11563
12371
|
} finally {
|
|
11564
|
-
|
|
12372
|
+
reader.releaseLock();
|
|
11565
12373
|
}
|
|
11566
12374
|
}
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
|
|
11577
|
-
this._pipelineId = null;
|
|
11578
|
-
}
|
|
11579
|
-
this._pipeline = null;
|
|
11580
|
-
try {
|
|
11581
|
-
this.options().pop = pop;
|
|
11582
|
-
await this.getComputeSession();
|
|
11583
|
-
} catch (error) {
|
|
11584
|
-
this.options().pop = previousPop;
|
|
11585
|
-
this._pipeline = null;
|
|
11586
|
-
this._pipelineId = null;
|
|
11587
|
-
this._baseUrl = previousPop ? null : previousBaseUrl;
|
|
11588
|
-
this._sessionAccessToken = previousSessionAccessToken;
|
|
11589
|
-
this._sessionAccessTokenValidUntil = previousSessionAccessTokenValidUntil;
|
|
11590
|
-
throw error;
|
|
11591
|
-
}
|
|
11592
|
-
if (!this._pipelineId) {
|
|
11593
|
-
throw new Error("Compute session did not provide a pipeline for the requested pop");
|
|
12375
|
+
}
|
|
12376
|
+
|
|
12377
|
+
// worker/worker_endpoint.ts
|
|
12378
|
+
var WorkerEndpoint = class extends Endpoint {
|
|
12379
|
+
constructor(options) {
|
|
12380
|
+
if (options.isPipelineMode) {
|
|
12381
|
+
options = { ...options, jobQueueLength: options.jobQueueLength || MAX_OPEN_SOURCES };
|
|
12382
|
+
if (options.jobQueueLength > MAX_OPEN_SOURCES) {
|
|
12383
|
+
throw new PipelineConfigurationError("job_queue_length", `jobQueueLength ${options.jobQueueLength} exceeds ${MAX_OPEN_SOURCES}, the open sources a pipeline API socket takes`);
|
|
12384
|
+
}
|
|
11594
12385
|
}
|
|
11595
|
-
|
|
12386
|
+
super(options);
|
|
12387
|
+
const context = {
|
|
12388
|
+
options,
|
|
12389
|
+
logger: this._logger,
|
|
12390
|
+
requestLogger: this._requestLogger,
|
|
12391
|
+
client: () => this._client,
|
|
12392
|
+
limit: () => this._limit,
|
|
12393
|
+
jobDone: () => {
|
|
12394
|
+
this._limit.release();
|
|
12395
|
+
this.updateState();
|
|
12396
|
+
},
|
|
12397
|
+
updateState: (state, message) => this.updateState(state, message),
|
|
12398
|
+
eyepopUrl: () => this.eyepopUrl(),
|
|
12399
|
+
eyepopWebApiUrl: () => this.eyepopWebApiUrl(),
|
|
12400
|
+
credentialHeader: () => super.authorizationHeader(),
|
|
12401
|
+
forgetCredential: () => this.statusHandler401(401),
|
|
12402
|
+
fetchWithRetry: (fetcher, retries) => this.fetchWithRetry(fetcher, retries),
|
|
12403
|
+
credentialSession: () => super.session()
|
|
12404
|
+
};
|
|
12405
|
+
this._backend = options.isPipelineMode ? new PipelineBackend(context) : new SessionBackend(context);
|
|
12406
|
+
this.setStatusRetryHandlers(/* @__PURE__ */ new Map([[404, (statusCode) => this._backend.onStatus(statusCode)]]));
|
|
11596
12407
|
}
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
|
|
12408
|
+
options() {
|
|
12409
|
+
return this._options;
|
|
12410
|
+
}
|
|
12411
|
+
/** What runs this endpoint's jobs. */
|
|
12412
|
+
backend() {
|
|
12413
|
+
return this._backend;
|
|
12414
|
+
}
|
|
12415
|
+
async disconnect(wait = true) {
|
|
12416
|
+
await this._backend.disconnect(() => super.disconnect(wait));
|
|
12417
|
+
}
|
|
12418
|
+
async session() {
|
|
12419
|
+
return await this._backend.session();
|
|
12420
|
+
}
|
|
12421
|
+
popName() {
|
|
12422
|
+
return this._backend.popName();
|
|
12423
|
+
}
|
|
12424
|
+
pop() {
|
|
12425
|
+
return this._backend.pop();
|
|
12426
|
+
}
|
|
12427
|
+
async changePop(pop) {
|
|
12428
|
+
validatePop(pop);
|
|
12429
|
+
await this._backend.changePop(pop);
|
|
12430
|
+
}
|
|
12431
|
+
/**
|
|
12432
|
+
* @deprecated Pop ids are only retained for backwards compatibility.
|
|
12433
|
+
* Configure transient sessions with `WorkerOptions.pop`.
|
|
12434
|
+
*/
|
|
12435
|
+
popId() {
|
|
12436
|
+
return this.options().popId || null;
|
|
12437
|
+
}
|
|
12438
|
+
async process(param1, param2) {
|
|
12439
|
+
if (param1.source !== void 0) {
|
|
12440
|
+
const request = param1;
|
|
12441
|
+
this.validateProcessParams(request);
|
|
12442
|
+
return await this.submit({ kind: "source", source: request.source, params: request });
|
|
12443
|
+
} else {
|
|
12444
|
+
return await this.submit({ kind: "source", source: param1, params: { componentParams: param2 } });
|
|
11600
12445
|
}
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
|
|
11606
|
-
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
|
|
12446
|
+
}
|
|
12447
|
+
/**
|
|
12448
|
+
* Reject a source's calibration before any work is started for it.
|
|
12449
|
+
*
|
|
12450
|
+
* Called by every entry point that takes ProcessParams, before the
|
|
12451
|
+
* concurrency limit is acquired, so a request that can never be sent
|
|
12452
|
+
* does not hold a slot.
|
|
12453
|
+
*/
|
|
12454
|
+
validateProcessParams(params) {
|
|
12455
|
+
if (params.camera !== void 0) {
|
|
12456
|
+
validateCamera(params.camera);
|
|
11612
12457
|
}
|
|
11613
12458
|
}
|
|
11614
|
-
async
|
|
11615
|
-
if (
|
|
11616
|
-
|
|
12459
|
+
async uploadGroup(paths, params = {}) {
|
|
12460
|
+
if (paths.length === 0) {
|
|
12461
|
+
throw new Error("upload group requires at least one path");
|
|
11617
12462
|
}
|
|
11618
|
-
|
|
12463
|
+
this.validateProcessParams(params);
|
|
12464
|
+
return await this.submit({ kind: "uploadGroup", paths, params });
|
|
11619
12465
|
}
|
|
11620
|
-
async
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
return "Implicit";
|
|
12466
|
+
async uploadStreamGroup(streams, mimeTypes, params = {}) {
|
|
12467
|
+
if (streams.length === 0) {
|
|
12468
|
+
throw new Error("upload stream group requires at least one stream");
|
|
11624
12469
|
}
|
|
11625
|
-
|
|
11626
|
-
|
|
11627
|
-
return `Bearer ${credential}`;
|
|
12470
|
+
if (mimeTypes !== void 0 && mimeTypes.length !== streams.length) {
|
|
12471
|
+
throw new Error("mimeTypes must have the same length as streams");
|
|
11628
12472
|
}
|
|
11629
|
-
|
|
12473
|
+
this.validateProcessParams(params);
|
|
12474
|
+
return await this.submit({ kind: "uploadStreamGroup", streams, mimeTypes, params });
|
|
11630
12475
|
}
|
|
11631
|
-
|
|
11632
|
-
|
|
11633
|
-
|
|
11634
|
-
this._pipeline = {
|
|
11635
|
-
id: this._pipelineId,
|
|
11636
|
-
state: "idle",
|
|
11637
|
-
startTime: (/* @__PURE__ */ new Date()).toString(),
|
|
11638
|
-
pop
|
|
11639
|
-
};
|
|
12476
|
+
async loadFromGroup(urls, params = {}) {
|
|
12477
|
+
if (urls.length === 0) {
|
|
12478
|
+
throw new Error("load from group requires at least one url");
|
|
11640
12479
|
}
|
|
12480
|
+
this.validateProcessParams(params);
|
|
12481
|
+
return await this.submit({ kind: "loadFromGroup", urls, params });
|
|
12482
|
+
}
|
|
12483
|
+
async submit(work) {
|
|
12484
|
+
return await this._backend.submit(work);
|
|
12485
|
+
}
|
|
12486
|
+
async reconnect() {
|
|
12487
|
+
await this._backend.reconnect();
|
|
12488
|
+
return this;
|
|
12489
|
+
}
|
|
12490
|
+
async authorizationHeader() {
|
|
12491
|
+
return await this._backend.authorizationHeader();
|
|
11641
12492
|
}
|
|
11642
12493
|
};
|
|
11643
|
-
_WorkerEndpoint.WAIT_FOR_IS_READY = 60 * 1e3;
|
|
11644
|
-
var WorkerEndpoint = _WorkerEndpoint;
|
|
11645
|
-
|
|
11646
|
-
// shims/websockets.ts
|
|
11647
|
-
var createWebSocket;
|
|
11648
|
-
if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
11649
|
-
createWebSocket = (url, protocols) => {
|
|
11650
|
-
return new WebSocket(url, protocols);
|
|
11651
|
-
};
|
|
11652
|
-
} else {
|
|
11653
|
-
createWebSocket = (url, protocols) => {
|
|
11654
|
-
const ws = __require("ws");
|
|
11655
|
-
return new ws.WebSocket(url, protocols);
|
|
11656
|
-
};
|
|
11657
|
-
}
|
|
11658
12494
|
|
|
11659
12495
|
// data/data_endpoint.ts
|
|
11660
12496
|
import urljoin from "url-join";
|
|
@@ -13322,6 +14158,13 @@ var EyePop;
|
|
|
13322
14158
|
if (opts.isLocalMode === void 0) {
|
|
13323
14159
|
opts.isLocalMode = stringToBooleanSafe(readEnv("EYEPOP_LOCAL_MODE"));
|
|
13324
14160
|
}
|
|
14161
|
+
if (opts.isPipelineMode === void 0) {
|
|
14162
|
+
const shared = resolveAuth(opts)?.session;
|
|
14163
|
+
opts.isPipelineMode = shared?.isPipelineMode ?? stringToBooleanSafe(readEnv("EYEPOP_PIPELINE_MODE"));
|
|
14164
|
+
}
|
|
14165
|
+
if (opts.isPipelineMode) {
|
|
14166
|
+
return pipelineEndpoint(opts);
|
|
14167
|
+
}
|
|
13325
14168
|
if (opts.isLocalMode) {
|
|
13326
14169
|
opts.eyepopUrl = "http://127.0.0.1:8080";
|
|
13327
14170
|
}
|
|
@@ -13373,6 +14216,38 @@ var EyePop;
|
|
|
13373
14216
|
return new WorkerEndpoint(opts);
|
|
13374
14217
|
}
|
|
13375
14218
|
EyePop2.workerEndpoint = workerEndpoint;
|
|
14219
|
+
function pipelineEndpoint(opts) {
|
|
14220
|
+
const popId = opts.popId ?? readEnv("EYEPOP_POP_ID");
|
|
14221
|
+
const sessionOnly = {
|
|
14222
|
+
popId: popId === "transient" /* Transient */ ? void 0 : popId,
|
|
14223
|
+
sessionUuid: opts.sessionUuid ?? readEnv("EYEPOP_SESSION_UUID"),
|
|
14224
|
+
sessionName: opts.sessionName,
|
|
14225
|
+
pipelineImage: opts.pipelineImage,
|
|
14226
|
+
pipelineVersion: opts.pipelineVersion
|
|
14227
|
+
};
|
|
14228
|
+
const named = Object.entries(sessionOnly).filter(([, value]) => value).map(([name]) => name);
|
|
14229
|
+
if (named.length > 0) {
|
|
14230
|
+
throw new PipelineConfigurationError("session_options", `pipeline mode runs no worker session; it takes no ${named.join(", ")}`, named);
|
|
14231
|
+
}
|
|
14232
|
+
if (opts.isLocalMode && !opts.eyepopUrl) {
|
|
14233
|
+
opts.eyepopUrl = readEnv("EYEPOP_URL") || "http://127.0.0.1:9002";
|
|
14234
|
+
}
|
|
14235
|
+
if (!opts.jobQueueLength) {
|
|
14236
|
+
opts.jobQueueLength = MAX_OPEN_SOURCES;
|
|
14237
|
+
}
|
|
14238
|
+
_fill_default_options(opts);
|
|
14239
|
+
if (resolveAuth(opts) === void 0) {
|
|
14240
|
+
if (opts.isLocalMode) {
|
|
14241
|
+
opts.auth = { isLocal: true };
|
|
14242
|
+
} else {
|
|
14243
|
+
throw new Error("apiKey/accessToken/session/oAuth2 option or EYEPOP_API_KEY environment variable is required");
|
|
14244
|
+
}
|
|
14245
|
+
}
|
|
14246
|
+
if (opts.accountId === void 0) {
|
|
14247
|
+
opts.accountId = resolveAuth(opts)?.session?.accountId ?? readAccountUuidEnv();
|
|
14248
|
+
}
|
|
14249
|
+
return new WorkerEndpoint(opts);
|
|
14250
|
+
}
|
|
13376
14251
|
function dataEndpoint(opts = {}) {
|
|
13377
14252
|
_fill_default_options(opts);
|
|
13378
14253
|
const auth = resolveAuth(opts);
|
|
@@ -13449,6 +14324,7 @@ export {
|
|
|
13449
14324
|
AssetUrlType,
|
|
13450
14325
|
AutoAnnotateStatus,
|
|
13451
14326
|
AutoAnnotateTask,
|
|
14327
|
+
COMBINED_UPLOAD_MAX_BYTES,
|
|
13452
14328
|
ChangeType,
|
|
13453
14329
|
ComputeAccountMismatchError,
|
|
13454
14330
|
ComputeApiError,
|
|
@@ -13470,6 +14346,7 @@ export {
|
|
|
13470
14346
|
LoadFromGroupJob,
|
|
13471
14347
|
LoadFromJob,
|
|
13472
14348
|
LoadMediaStreamJob,
|
|
14349
|
+
MAX_OPEN_SOURCES,
|
|
13473
14350
|
ModelExportStatus,
|
|
13474
14351
|
ModelFormat,
|
|
13475
14352
|
ModelPrecisionType,
|
|
@@ -13478,12 +14355,21 @@ export {
|
|
|
13478
14355
|
ModelTrainingStage,
|
|
13479
14356
|
ModelType,
|
|
13480
14357
|
MotionModel,
|
|
14358
|
+
PIPELINE_PATH,
|
|
14359
|
+
PipelineBackend,
|
|
14360
|
+
PipelineCommandError,
|
|
14361
|
+
PipelineConfigurationError,
|
|
14362
|
+
PipelineJob,
|
|
14363
|
+
PipelineSocketClosedError,
|
|
14364
|
+
PipelineSourceError,
|
|
13481
14365
|
PointCloud,
|
|
13482
14366
|
PopComponentType,
|
|
13483
14367
|
PredictionVersion,
|
|
13484
14368
|
QUATERNION_TOLERANCE,
|
|
14369
|
+
SUBPROTOCOL,
|
|
13485
14370
|
SelectMode,
|
|
13486
14371
|
Semaphore,
|
|
14372
|
+
SessionBackend,
|
|
13487
14373
|
Stream,
|
|
13488
14374
|
TaskMode,
|
|
13489
14375
|
TaskType,
|