@eyepop.ai/eyepop 3.26.0-rc.2 → 3.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/eyepop.index.d.mts +96 -5
- package/dist/eyepop.index.d.ts +96 -5
- package/dist/eyepop.index.js +183 -52
- package/dist/eyepop.index.js.map +1 -1
- package/dist/eyepop.index.mjs +181 -52
- 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
|
@@ -8928,14 +8928,25 @@ if ("document" in globalThis && "implementation" in globalThis.document) {
|
|
|
8928
8928
|
}
|
|
8929
8929
|
|
|
8930
8930
|
// endpoint.ts
|
|
8931
|
+
var ACCOUNT_CLAIM = "https://ident.eyepop.ai/account-uuid";
|
|
8932
|
+
var NOT_EXCHANGEABLE = ["API key or user login required", "API key authentication required for token refresh"];
|
|
8933
|
+
function carriesAccount(token) {
|
|
8934
|
+
try {
|
|
8935
|
+
const payload = (token.split(".")[1] ?? "").replace(/-/g, "+").replace(/_/g, "/");
|
|
8936
|
+
return Boolean(JSON.parse(atob(payload))?.[ACCOUNT_CLAIM]);
|
|
8937
|
+
} catch {
|
|
8938
|
+
return false;
|
|
8939
|
+
}
|
|
8940
|
+
}
|
|
8931
8941
|
var Endpoint = class {
|
|
8932
8942
|
constructor(options) {
|
|
8943
|
+
this._exchanging = null;
|
|
8933
8944
|
this._options = options;
|
|
8934
8945
|
this._token = null;
|
|
8935
8946
|
this._expire_token_time = null;
|
|
8936
8947
|
this._client = null;
|
|
8937
8948
|
this._statusRetryHandlers = /* @__PURE__ */ new Map();
|
|
8938
|
-
this._statusRetryHandlers.set(401, (statusCode) => this.statusHandler401(statusCode));
|
|
8949
|
+
this._statusRetryHandlers.set(401, (statusCode, failedToken) => this.statusHandler401(statusCode, failedToken));
|
|
8939
8950
|
this._limit = new Semaphore(this._options.jobQueueLength ?? 1024);
|
|
8940
8951
|
this._state = "Idle" /* Idle */;
|
|
8941
8952
|
this._message = null;
|
|
@@ -8951,7 +8962,7 @@ var Endpoint = class {
|
|
|
8951
8962
|
}
|
|
8952
8963
|
setStatusRetryHandlers(statusRetryHandlers = void 0) {
|
|
8953
8964
|
this._statusRetryHandlers = new Map(statusRetryHandlers);
|
|
8954
|
-
this._statusRetryHandlers.set(401, (statusCode) => this.statusHandler401(statusCode));
|
|
8965
|
+
this._statusRetryHandlers.set(401, (statusCode, failedToken) => this.statusHandler401(statusCode, failedToken));
|
|
8955
8966
|
}
|
|
8956
8967
|
eyepopUrl() {
|
|
8957
8968
|
if (this._options.eyepopUrl) {
|
|
@@ -9048,12 +9059,15 @@ var Endpoint = class {
|
|
|
9048
9059
|
validUntil: this._expire_token_time * 1e3
|
|
9049
9060
|
};
|
|
9050
9061
|
}
|
|
9051
|
-
statusHandler401(_statusCode) {
|
|
9052
|
-
this._token
|
|
9053
|
-
|
|
9062
|
+
statusHandler401(_statusCode, failedToken = this._token) {
|
|
9063
|
+
if (this._token === failedToken) {
|
|
9064
|
+
this._token = null;
|
|
9065
|
+
this._expire_token_time = null;
|
|
9066
|
+
}
|
|
9054
9067
|
}
|
|
9055
9068
|
async fetchWithRetry(fetcher, retries = 1) {
|
|
9056
9069
|
while (true) {
|
|
9070
|
+
const sentToken = this._token ?? void 0;
|
|
9057
9071
|
try {
|
|
9058
9072
|
const response = await fetcher();
|
|
9059
9073
|
if (response.ok) {
|
|
@@ -9061,7 +9075,7 @@ var Endpoint = class {
|
|
|
9061
9075
|
} else {
|
|
9062
9076
|
const handler = this._statusRetryHandlers.get(response.status);
|
|
9063
9077
|
if (handler != null) {
|
|
9064
|
-
handler(response.status);
|
|
9078
|
+
handler(response.status, sentToken);
|
|
9065
9079
|
if (retries--) {
|
|
9066
9080
|
this._requestLogger.info("received %d response, retry", response.status);
|
|
9067
9081
|
} else {
|
|
@@ -9095,54 +9109,75 @@ var Endpoint = class {
|
|
|
9095
9109
|
}
|
|
9096
9110
|
return `Bearer ${await this.currentAccessToken()}`;
|
|
9097
9111
|
}
|
|
9112
|
+
async exchange(client, credential, accountUuid) {
|
|
9113
|
+
const query = accountUuid ? `?account_uuid=${encodeURIComponent(accountUuid)}` : "";
|
|
9114
|
+
return await client.fetch(`${this.eyepopUrl()}/v1/auth/authenticate${query}`, {
|
|
9115
|
+
method: "POST",
|
|
9116
|
+
headers: { Authorization: `Bearer ${credential}` }
|
|
9117
|
+
});
|
|
9118
|
+
}
|
|
9119
|
+
async storeExchangedToken(response, now) {
|
|
9120
|
+
if (response.status != 200) {
|
|
9121
|
+
const message = await response.text();
|
|
9122
|
+
return Promise.reject(`Unexpected status ${response.status}: ${message}`);
|
|
9123
|
+
}
|
|
9124
|
+
const token = await response.json();
|
|
9125
|
+
this._token = token.access_token;
|
|
9126
|
+
this._expire_token_time = now + token.expires_in - 60;
|
|
9127
|
+
}
|
|
9128
|
+
/**
|
|
9129
|
+
* A token that already carries an account, or that the compute API refuses to exchange
|
|
9130
|
+
* (see NOT_EXCHANGEABLE), is used as is. Any other refusal is raised.
|
|
9131
|
+
*/
|
|
9132
|
+
async exchangeLoginToken(client, loginToken, validUntil, now) {
|
|
9133
|
+
if (!carriesAccount(loginToken)) {
|
|
9134
|
+
const response = await this.exchange(client, loginToken, this._options.accountId);
|
|
9135
|
+
const refusal = response.status == 401 ? await response.clone().text() : "";
|
|
9136
|
+
if (!NOT_EXCHANGEABLE.some((message) => refusal.includes(message))) {
|
|
9137
|
+
await this.storeExchangedToken(response, now);
|
|
9138
|
+
return;
|
|
9139
|
+
}
|
|
9140
|
+
}
|
|
9141
|
+
this._token = loginToken;
|
|
9142
|
+
this._expire_token_time = validUntil;
|
|
9143
|
+
}
|
|
9098
9144
|
async currentAccessToken() {
|
|
9145
|
+
if (!this._token || this._expire_token_time < Date.now() / 1e3) {
|
|
9146
|
+
this._exchanging ?? (this._exchanging = this.authenticate().finally(() => this._exchanging = null));
|
|
9147
|
+
await this._exchanging;
|
|
9148
|
+
}
|
|
9149
|
+
this._logger.debug("using access token, valid for at least %d seconds", this._expire_token_time - Date.now() / 1e3);
|
|
9150
|
+
return this._token;
|
|
9151
|
+
}
|
|
9152
|
+
async authenticate() {
|
|
9099
9153
|
const now = Date.now() / 1e3;
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
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 {
|
|
9154
|
+
this.updateState("Authenticating" /* Authenticating */);
|
|
9155
|
+
try {
|
|
9156
|
+
const auth = resolveAuth(this._options);
|
|
9157
|
+
if (!this._client) {
|
|
9158
|
+
return Promise.reject("endpoint not connected");
|
|
9159
|
+
} else if (auth?.isLocal !== void 0) {
|
|
9160
|
+
this._token = "implicit";
|
|
9161
|
+
this._expire_token_time = Number.MAX_VALUE;
|
|
9162
|
+
} else if (auth?.session !== void 0) {
|
|
9163
|
+
return Promise.reject("temporary access token expired");
|
|
9164
|
+
} else if (auth?.oAuth2 !== void 0 && this._options.eyepopUrl) {
|
|
9165
|
+
const login = await authenticateBrowserSession(auth.oAuth2, this._options);
|
|
9166
|
+
await this.exchangeLoginToken(this._client, login.accessToken, login.validUntil / 1e3, now);
|
|
9167
|
+
} else if (accessTokenCredential(auth) !== void 0) {
|
|
9168
|
+
await this.exchangeLoginToken(this._client, accessTokenCredential(auth), Number.MAX_VALUE, now);
|
|
9169
|
+
} else if (this._options.eyepopUrl) {
|
|
9170
|
+
const credential = apiKeyCredential(auth);
|
|
9171
|
+
if (credential === void 0) {
|
|
9138
9172
|
return Promise.reject("no valid auth option");
|
|
9139
9173
|
}
|
|
9140
|
-
|
|
9141
|
-
|
|
9174
|
+
await this.storeExchangedToken(await this.exchange(this._client, credential), now);
|
|
9175
|
+
} else {
|
|
9176
|
+
return Promise.reject("no valid auth option");
|
|
9142
9177
|
}
|
|
9178
|
+
} finally {
|
|
9179
|
+
this.updateState();
|
|
9143
9180
|
}
|
|
9144
|
-
this._logger.debug("using access token, valid for at least %d seconds", this._expire_token_time - now);
|
|
9145
|
-
return this._token;
|
|
9146
9181
|
}
|
|
9147
9182
|
};
|
|
9148
9183
|
|
|
@@ -11692,10 +11727,22 @@ var PipelineJob = class {
|
|
|
11692
11727
|
this.openSource = null;
|
|
11693
11728
|
// Stops the job's source on the pipeline, once it was sent.
|
|
11694
11729
|
this.stopOnPipeline = null;
|
|
11730
|
+
this._milliComputeUnits = void 0;
|
|
11695
11731
|
}
|
|
11696
11732
|
get cancelled() {
|
|
11697
11733
|
return this._cancelled;
|
|
11698
11734
|
}
|
|
11735
|
+
/** The source's milli compute units: the latest total of its `usage` messages and its `end`. */
|
|
11736
|
+
get milliComputeUnits() {
|
|
11737
|
+
return this._milliComputeUnits;
|
|
11738
|
+
}
|
|
11739
|
+
/** Keep a usage's or an end's milliComputeUnits: each carries the source's total so far. */
|
|
11740
|
+
noteMilliComputeUnits(message) {
|
|
11741
|
+
const value = message["milliComputeUnits"];
|
|
11742
|
+
if (Number.isInteger(value) && value >= 0) {
|
|
11743
|
+
this._milliComputeUnits = value;
|
|
11744
|
+
}
|
|
11745
|
+
}
|
|
11699
11746
|
command(id) {
|
|
11700
11747
|
const command = { type: "setSource", id, ...this.source };
|
|
11701
11748
|
if (this.params.componentParams !== void 0) {
|
|
@@ -12273,7 +12320,11 @@ var PipelineBackend = class {
|
|
|
12273
12320
|
case "prediction":
|
|
12274
12321
|
job.predicted(message["prediction"]);
|
|
12275
12322
|
break;
|
|
12323
|
+
case "usage":
|
|
12324
|
+
job.noteMilliComputeUnits(message);
|
|
12325
|
+
break;
|
|
12276
12326
|
case "end":
|
|
12327
|
+
job.noteMilliComputeUnits(message);
|
|
12277
12328
|
if (message["reason"] === "eos") {
|
|
12278
12329
|
return null;
|
|
12279
12330
|
}
|
|
@@ -12837,6 +12888,7 @@ var InferAssetJob = class {
|
|
|
12837
12888
|
constructor(assetUrl, inferRequest, vlmFetch, requestLogger) {
|
|
12838
12889
|
this._response = null;
|
|
12839
12890
|
this._runInfo = null;
|
|
12891
|
+
this._milliComputeUnits = void 0;
|
|
12840
12892
|
this._controller = new AbortController();
|
|
12841
12893
|
this._vlmFetch = vlmFetch;
|
|
12842
12894
|
this._assetUrl = assetUrl;
|
|
@@ -12873,6 +12925,13 @@ var InferAssetJob = class {
|
|
|
12873
12925
|
}
|
|
12874
12926
|
return iterator();
|
|
12875
12927
|
}
|
|
12928
|
+
/**
|
|
12929
|
+
* The milli compute units vlm-server billed for the inference, 0 on a cache hit; undefined before it answered
|
|
12930
|
+
* or when it reported none.
|
|
12931
|
+
*/
|
|
12932
|
+
get milliComputeUnits() {
|
|
12933
|
+
return this._milliComputeUnits;
|
|
12934
|
+
}
|
|
12876
12935
|
start(done) {
|
|
12877
12936
|
this._response = new Promise(async (resolve, reject) => {
|
|
12878
12937
|
try {
|
|
@@ -12897,6 +12956,8 @@ var InferAssetJob = class {
|
|
|
12897
12956
|
const runInfo = response["run_info"];
|
|
12898
12957
|
if (predictions) {
|
|
12899
12958
|
this._runInfo = runInfo;
|
|
12959
|
+
const used = response["milli_compute_units"] ?? response["compute_units"];
|
|
12960
|
+
this._milliComputeUnits = typeof used === "number" ? used : void 0;
|
|
12900
12961
|
resolve(predictions);
|
|
12901
12962
|
break;
|
|
12902
12963
|
} else {
|
|
@@ -13013,6 +13074,70 @@ function omit_nulls(_, value) {
|
|
|
13013
13074
|
}
|
|
13014
13075
|
return value;
|
|
13015
13076
|
}
|
|
13077
|
+
var TASK_EXCLUDED_FIELDS = ["text_prompt", "transform_into", "response_schema"];
|
|
13078
|
+
var VlmAbilityModeErrorReason = /* @__PURE__ */ ((VlmAbilityModeErrorReason2) => {
|
|
13079
|
+
VlmAbilityModeErrorReason2["missing_mode"] = "missing_mode";
|
|
13080
|
+
VlmAbilityModeErrorReason2["unknown_task"] = "unknown_task";
|
|
13081
|
+
VlmAbilityModeErrorReason2["task_excludes_free_form"] = "task_excludes_free_form";
|
|
13082
|
+
VlmAbilityModeErrorReason2["task_without_prompts"] = "task_without_prompts";
|
|
13083
|
+
VlmAbilityModeErrorReason2["prompts_without_task"] = "prompts_without_task";
|
|
13084
|
+
VlmAbilityModeErrorReason2["empty_prompts"] = "empty_prompts";
|
|
13085
|
+
VlmAbilityModeErrorReason2["invalid_prompt"] = "invalid_prompt";
|
|
13086
|
+
return VlmAbilityModeErrorReason2;
|
|
13087
|
+
})(VlmAbilityModeErrorReason || {});
|
|
13088
|
+
var VlmAbilityModeError = class extends Error {
|
|
13089
|
+
constructor(reason, message, fields = []) {
|
|
13090
|
+
super(message);
|
|
13091
|
+
this.name = "VlmAbilityModeError";
|
|
13092
|
+
this.reason = reason;
|
|
13093
|
+
this.fields = fields;
|
|
13094
|
+
}
|
|
13095
|
+
};
|
|
13096
|
+
function isSet(value) {
|
|
13097
|
+
return value !== void 0 && value !== null;
|
|
13098
|
+
}
|
|
13099
|
+
function validateVlmAbilityMode(ability, partial) {
|
|
13100
|
+
const kind = partial ? "VLM ability update" : "VLM ability";
|
|
13101
|
+
const taskSet = isSet(ability.task);
|
|
13102
|
+
const promptsSet = isSet(ability.prompts);
|
|
13103
|
+
if (taskSet && !Object.values(AutoAnnotateTask).includes(ability.task)) {
|
|
13104
|
+
throw new VlmAbilityModeError("unknown_task" /* unknown_task */, `${kind}: unknown task '${String(ability.task)}', expected one of ${Object.values(AutoAnnotateTask).join(", ")}`, [
|
|
13105
|
+
"task"
|
|
13106
|
+
]);
|
|
13107
|
+
}
|
|
13108
|
+
if (taskSet || promptsSet) {
|
|
13109
|
+
const conflicting = TASK_EXCLUDED_FIELDS.filter((field) => isSet(ability[field]));
|
|
13110
|
+
if (conflicting.length > 0) {
|
|
13111
|
+
throw new VlmAbilityModeError(
|
|
13112
|
+
"task_excludes_free_form" /* task_excludes_free_form */,
|
|
13113
|
+
`${kind}: a task derives the prompt and output schema, so ${conflicting.join(", ")} must be unset with task and prompts`,
|
|
13114
|
+
[...conflicting]
|
|
13115
|
+
);
|
|
13116
|
+
}
|
|
13117
|
+
}
|
|
13118
|
+
if (promptsSet) {
|
|
13119
|
+
if (!Array.isArray(ability.prompts) || ability.prompts.length === 0) {
|
|
13120
|
+
throw new VlmAbilityModeError("empty_prompts" /* empty_prompts */, `${kind}: prompts must be a non-empty list of {label, prompt}`, ["prompts"]);
|
|
13121
|
+
}
|
|
13122
|
+
ability.prompts.forEach((entry, i) => {
|
|
13123
|
+
if (!entry || typeof entry.label !== "string" || entry.label.length === 0 || typeof entry.prompt !== "string" || entry.prompt.length === 0) {
|
|
13124
|
+
throw new VlmAbilityModeError("invalid_prompt" /* invalid_prompt */, `${kind}: prompts[${i}] needs a non-empty label and prompt`, [`prompts[${i}]`]);
|
|
13125
|
+
}
|
|
13126
|
+
});
|
|
13127
|
+
}
|
|
13128
|
+
if (partial) {
|
|
13129
|
+
return;
|
|
13130
|
+
}
|
|
13131
|
+
if (taskSet && !promptsSet) {
|
|
13132
|
+
throw new VlmAbilityModeError("task_without_prompts" /* task_without_prompts */, `${kind}: task '${ability.task}' requires a non-empty prompts list of {label, prompt}`, ["prompts"]);
|
|
13133
|
+
}
|
|
13134
|
+
if (!taskSet && promptsSet) {
|
|
13135
|
+
throw new VlmAbilityModeError("prompts_without_task" /* prompts_without_task */, `${kind}: prompts are only used with a task; set task, or use text_prompt for a free-form ability`, ["prompts"]);
|
|
13136
|
+
}
|
|
13137
|
+
if (!taskSet && !(typeof ability.text_prompt === "string" && ability.text_prompt.length > 0)) {
|
|
13138
|
+
throw new VlmAbilityModeError("missing_mode" /* missing_mode */, `${kind}: set either text_prompt (free-form) or task with non-empty prompts`, ["text_prompt", "task"]);
|
|
13139
|
+
}
|
|
13140
|
+
}
|
|
13016
13141
|
var DataEndpoint = class extends Endpoint {
|
|
13017
13142
|
constructor(options) {
|
|
13018
13143
|
super(options);
|
|
@@ -13804,6 +13929,7 @@ var DataEndpoint = class extends Endpoint {
|
|
|
13804
13929
|
});
|
|
13805
13930
|
}
|
|
13806
13931
|
async createVlmAbility(create, vlm_ability_group_uuid) {
|
|
13932
|
+
validateVlmAbilityMode(create, false);
|
|
13807
13933
|
const groupQuery = vlm_ability_group_uuid ? `&vlm_ability_group_uuid=${vlm_ability_group_uuid}` : "";
|
|
13808
13934
|
return this.request(`/vlm_abilities?account_uuid=${this._accountId}${groupQuery}`, {
|
|
13809
13935
|
method: "POST",
|
|
@@ -13822,6 +13948,7 @@ var DataEndpoint = class extends Endpoint {
|
|
|
13822
13948
|
});
|
|
13823
13949
|
}
|
|
13824
13950
|
async updateVlmAbility(vlm_ability_uuid, update) {
|
|
13951
|
+
validateVlmAbilityMode(update, true);
|
|
13825
13952
|
return this.request(`/vlm_abilities/${vlm_ability_uuid}`, {
|
|
13826
13953
|
method: "PATCH",
|
|
13827
13954
|
body: JSON.stringify(update),
|
|
@@ -14420,17 +14547,17 @@ var EyePop;
|
|
|
14420
14547
|
if (typeof auth.oAuth2 === "boolean") {
|
|
14421
14548
|
const oAuth2 = opts.eyepopUrl && opts.eyepopUrl.match(/https:(.*).staging.eyepop.xyz/i) ? {
|
|
14422
14549
|
oAuth2: {
|
|
14423
|
-
domain: "
|
|
14550
|
+
domain: "auth0.eyepop.xyz",
|
|
14424
14551
|
clientId: "jktx3YO2UnbkNPvr05PQWf26t1kNTJyg",
|
|
14425
14552
|
audience: "https://dev-app.eyepop.ai",
|
|
14426
|
-
scope: "
|
|
14553
|
+
scope: "access:inference-api access:datasets"
|
|
14427
14554
|
}
|
|
14428
14555
|
} : {
|
|
14429
14556
|
oAuth2: {
|
|
14430
|
-
domain: "eyepop.
|
|
14557
|
+
domain: "auth0.eyepop.ai",
|
|
14431
14558
|
clientId: "Lb9ubA9Hf3jlaqWLUx8XgA0zvotgViCl",
|
|
14432
14559
|
audience: "https://api.eyepop.ai",
|
|
14433
|
-
scope: "
|
|
14560
|
+
scope: "access:inference-api access:datasets"
|
|
14434
14561
|
}
|
|
14435
14562
|
};
|
|
14436
14563
|
if (opts.oAuth2 !== void 0) {
|
|
@@ -14514,6 +14641,8 @@ export {
|
|
|
14514
14641
|
UploadJob,
|
|
14515
14642
|
UserReview,
|
|
14516
14643
|
VideoMode,
|
|
14644
|
+
VlmAbilityModeError,
|
|
14645
|
+
VlmAbilityModeErrorReason,
|
|
14517
14646
|
VlmAbilityStatus,
|
|
14518
14647
|
WebrtcBase,
|
|
14519
14648
|
WebrtcWhep,
|