@inerrata-corporation/errata 2.0.6-dev.2082 → 2.0.6-dev.2138
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/errata.mjs +67 -9
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -77056,7 +77056,7 @@ function createWatchBreaker(deps) {
|
|
|
77056
77056
|
}
|
|
77057
77057
|
|
|
77058
77058
|
// src/engine.ts
|
|
77059
|
-
var DAEMON_VERSION = true ? "2.0.6-dev.
|
|
77059
|
+
var DAEMON_VERSION = true ? "2.0.6-dev.2138" : "2.0.0-alpha.0";
|
|
77060
77060
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
77061
77061
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
77062
77062
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -82572,16 +82572,49 @@ import { execFileSync as execFileSync4 } from "node:child_process";
|
|
|
82572
82572
|
import { existsSync as existsSync29, writeFileSync as writeFileSync22 } from "node:fs";
|
|
82573
82573
|
import { join as join34 } from "node:path";
|
|
82574
82574
|
|
|
82575
|
+
// src/device-poll.ts
|
|
82576
|
+
var THROTTLED_POLL_MIN_WAIT_MS = 11e3;
|
|
82577
|
+
var THROTTLED_INTERVAL_CAP_MS = 6e4;
|
|
82578
|
+
function throttledPoll(res, intervalMs) {
|
|
82579
|
+
if (res.status !== 429 && res.status !== 503) return null;
|
|
82580
|
+
const next = Math.max(intervalMs, Math.min(intervalMs + 5e3, THROTTLED_INTERVAL_CAP_MS));
|
|
82581
|
+
return {
|
|
82582
|
+
intervalMs: next,
|
|
82583
|
+
waitMs: Math.max(next, retryAfterMs(res.headers) ?? 0, THROTTLED_POLL_MIN_WAIT_MS)
|
|
82584
|
+
};
|
|
82585
|
+
}
|
|
82586
|
+
function retryAfterMs(headers, now = Date.now()) {
|
|
82587
|
+
for (const name2 of ["retry-after", "x-retry-after"]) {
|
|
82588
|
+
const raw2 = headers.get(name2)?.trim();
|
|
82589
|
+
if (!raw2) continue;
|
|
82590
|
+
if (/^\d+$/.test(raw2)) return Number(raw2) * 1e3;
|
|
82591
|
+
const at = Date.parse(raw2);
|
|
82592
|
+
if (!Number.isNaN(at)) return Math.max(0, at - now);
|
|
82593
|
+
}
|
|
82594
|
+
return null;
|
|
82595
|
+
}
|
|
82596
|
+
|
|
82575
82597
|
// src/oauth-login.ts
|
|
82576
82598
|
init_src7();
|
|
82577
82599
|
init_cloud_auth();
|
|
82578
82600
|
import { createServer } from "node:http";
|
|
82579
82601
|
var DEFAULT_OAUTH_SCOPE = "openid profile graph:read graph:write mcp:tools";
|
|
82580
82602
|
var strip = (u) => u.replace(/\/+$/, "");
|
|
82581
|
-
function deviceEndpoints(tokenEndpoint) {
|
|
82603
|
+
function deviceEndpoints(tokenEndpoint, deviceAuthorizationEndpoint) {
|
|
82582
82604
|
const token = new URL(tokenEndpoint);
|
|
82583
82605
|
const authRoot = token.pathname.replace(/\/(?:oauth2|mcp)\/token\/?$/, "");
|
|
82584
|
-
if (authRoot === token.pathname)
|
|
82606
|
+
if (authRoot === token.pathname) {
|
|
82607
|
+
if (deviceAuthorizationEndpoint) {
|
|
82608
|
+
const device = new URL(deviceAuthorizationEndpoint);
|
|
82609
|
+
const code = `${device.origin}${device.pathname.replace(/\/+$/, "")}`;
|
|
82610
|
+
return {
|
|
82611
|
+
code,
|
|
82612
|
+
token: `${code}/token`,
|
|
82613
|
+
resource: new URL("/api/gate/session-token", device.origin).toString()
|
|
82614
|
+
};
|
|
82615
|
+
}
|
|
82616
|
+
throw new Error("authorization server exposes no device endpoint");
|
|
82617
|
+
}
|
|
82585
82618
|
const prefix = authRoot.replace(/\/api\/auth\/?$/, "");
|
|
82586
82619
|
const at = (path2) => new URL(`${path2}`, `${token.origin}${prefix || "/"}`).toString();
|
|
82587
82620
|
return {
|
|
@@ -82593,7 +82626,7 @@ function deviceEndpoints(tokenEndpoint) {
|
|
|
82593
82626
|
async function loginOAuthDevice(opts) {
|
|
82594
82627
|
const fetchFn = opts.fetchFn ?? fetch;
|
|
82595
82628
|
const endpoints = await discoverEndpoints(opts.cloudUrl, fetchFn);
|
|
82596
|
-
const device = deviceEndpoints(endpoints.tokenEndpoint);
|
|
82629
|
+
const device = deviceEndpoints(endpoints.tokenEndpoint, endpoints.deviceAuthorizationEndpoint);
|
|
82597
82630
|
const clientId = oauthClientId();
|
|
82598
82631
|
const scope = opts.scope ?? DEFAULT_OAUTH_SCOPE;
|
|
82599
82632
|
const codeResponse = await fetchFn(device.code, {
|
|
@@ -82615,10 +82648,12 @@ async function loginOAuthDevice(opts) {
|
|
|
82615
82648
|
});
|
|
82616
82649
|
const deadline = Date.now() + Math.min(code.expires_in * 1e3, opts.timeoutMs ?? Number.POSITIVE_INFINITY);
|
|
82617
82650
|
let intervalMs = Math.max(2, code.interval ?? 5) * 1e3;
|
|
82651
|
+
let waitMs = intervalMs;
|
|
82618
82652
|
let deviceSession = null;
|
|
82619
82653
|
let approvedInstallation = null;
|
|
82620
82654
|
while (Date.now() < deadline) {
|
|
82621
|
-
await (opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms))))(
|
|
82655
|
+
await (opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms))))(waitMs);
|
|
82656
|
+
waitMs = intervalMs;
|
|
82622
82657
|
const poll = await fetchFn(device.token, {
|
|
82623
82658
|
method: "POST",
|
|
82624
82659
|
headers: { "content-type": "application/json", accept: "application/json" },
|
|
@@ -82630,10 +82665,16 @@ async function loginOAuthDevice(opts) {
|
|
|
82630
82665
|
});
|
|
82631
82666
|
const payload = await poll.json().catch(() => null);
|
|
82632
82667
|
if (!poll.ok) {
|
|
82668
|
+
const throttle = throttledPoll(poll, intervalMs);
|
|
82669
|
+
if (throttle) {
|
|
82670
|
+
({ intervalMs, waitMs } = throttle);
|
|
82671
|
+
continue;
|
|
82672
|
+
}
|
|
82633
82673
|
const error48 = typeof payload?.["error"] === "string" ? payload["error"] : "device_poll_failed";
|
|
82634
82674
|
if (error48 === "authorization_pending") continue;
|
|
82635
82675
|
if (error48 === "slow_down") {
|
|
82636
82676
|
intervalMs += 5e3;
|
|
82677
|
+
waitMs = intervalMs;
|
|
82637
82678
|
continue;
|
|
82638
82679
|
}
|
|
82639
82680
|
throw new Error(`device authorization failed: ${error48}`);
|
|
@@ -82692,7 +82733,8 @@ async function discoverEndpoints(cloudUrl, fetchFn = fetch) {
|
|
|
82692
82733
|
return {
|
|
82693
82734
|
authorizationEndpoint: j.authorization_endpoint,
|
|
82694
82735
|
tokenEndpoint: j.token_endpoint,
|
|
82695
|
-
...j.registration_endpoint ? { registrationEndpoint: j.registration_endpoint } : {}
|
|
82736
|
+
...j.registration_endpoint ? { registrationEndpoint: j.registration_endpoint } : {},
|
|
82737
|
+
...j.device_authorization_endpoint ? { deviceAuthorizationEndpoint: j.device_authorization_endpoint } : {}
|
|
82696
82738
|
};
|
|
82697
82739
|
}
|
|
82698
82740
|
}
|
|
@@ -82809,7 +82851,7 @@ function isDecision(value) {
|
|
|
82809
82851
|
async function linkThroughConsole(opts) {
|
|
82810
82852
|
const fetchFn = opts.fetchFn ?? fetch;
|
|
82811
82853
|
const endpoints = await discoverEndpoints(opts.cloudUrl, fetchFn);
|
|
82812
|
-
const device = deviceEndpoints(endpoints.tokenEndpoint);
|
|
82854
|
+
const device = deviceEndpoints(endpoints.tokenEndpoint, endpoints.deviceAuthorizationEndpoint);
|
|
82813
82855
|
const clientId = oauthClientId();
|
|
82814
82856
|
const link = {
|
|
82815
82857
|
locator: opts.facts.locator,
|
|
@@ -82843,9 +82885,11 @@ async function linkThroughConsole(opts) {
|
|
|
82843
82885
|
});
|
|
82844
82886
|
const deadline = Date.now() + Math.min(code.expires_in * 1e3, opts.timeoutMs ?? Number.POSITIVE_INFINITY);
|
|
82845
82887
|
let intervalMs = Math.max(2, code.interval ?? 5) * 1e3;
|
|
82888
|
+
let waitMs = intervalMs;
|
|
82846
82889
|
const sleep = opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
82847
82890
|
while (Date.now() < deadline) {
|
|
82848
|
-
await sleep(
|
|
82891
|
+
await sleep(waitMs);
|
|
82892
|
+
waitMs = intervalMs;
|
|
82849
82893
|
const poll = await fetchFn(device.token, {
|
|
82850
82894
|
method: "POST",
|
|
82851
82895
|
headers: { "content-type": "application/json", accept: "application/json" },
|
|
@@ -82857,10 +82901,16 @@ async function linkThroughConsole(opts) {
|
|
|
82857
82901
|
});
|
|
82858
82902
|
const payload = await poll.json().catch(() => null);
|
|
82859
82903
|
if (!poll.ok) {
|
|
82904
|
+
const throttle = throttledPoll(poll, intervalMs);
|
|
82905
|
+
if (throttle) {
|
|
82906
|
+
({ intervalMs, waitMs } = throttle);
|
|
82907
|
+
continue;
|
|
82908
|
+
}
|
|
82860
82909
|
const error48 = typeof payload?.["error"] === "string" ? payload["error"] : "device_poll_failed";
|
|
82861
82910
|
if (error48 === "authorization_pending") continue;
|
|
82862
82911
|
if (error48 === "slow_down") {
|
|
82863
82912
|
intervalMs += 5e3;
|
|
82913
|
+
waitMs = intervalMs;
|
|
82864
82914
|
continue;
|
|
82865
82915
|
}
|
|
82866
82916
|
if (error48 === "access_denied") return { status: "denied" };
|
|
@@ -84886,9 +84936,11 @@ async function requestDeviceAuthorization(fetchFn, deviceEndpoint, p) {
|
|
|
84886
84936
|
async function pollDeviceApproval(fetchFn, deviceEndpoint, p, sleep = (ms) => new Promise((r) => setTimeout(r, ms))) {
|
|
84887
84937
|
const deadline = Date.now() + p.timeoutMs;
|
|
84888
84938
|
let intervalMs = Math.max(1, p.intervalSeconds) * 1e3;
|
|
84939
|
+
let waitMs = intervalMs;
|
|
84889
84940
|
for (; ; ) {
|
|
84890
84941
|
if (Date.now() >= deadline) throw new Error("device approval timed out \u2014 run `errata login` again");
|
|
84891
|
-
await sleep(
|
|
84942
|
+
await sleep(waitMs);
|
|
84943
|
+
waitMs = intervalMs;
|
|
84892
84944
|
const res = await fetchFn(`${strip2(deviceEndpoint)}/token`, {
|
|
84893
84945
|
method: "POST",
|
|
84894
84946
|
headers: { "content-type": "application/json", accept: "application/json" },
|
|
@@ -84900,9 +84952,15 @@ async function pollDeviceApproval(fetchFn, deviceEndpoint, p, sleep = (ms) => ne
|
|
|
84900
84952
|
});
|
|
84901
84953
|
const j = await res.json().catch(() => ({}));
|
|
84902
84954
|
if (res.ok && j.access_token) return j.access_token;
|
|
84955
|
+
const throttle = throttledPoll(res, intervalMs);
|
|
84956
|
+
if (throttle) {
|
|
84957
|
+
({ intervalMs, waitMs } = throttle);
|
|
84958
|
+
continue;
|
|
84959
|
+
}
|
|
84903
84960
|
if (j.error === "authorization_pending") continue;
|
|
84904
84961
|
if (j.error === "slow_down") {
|
|
84905
84962
|
intervalMs += 5e3;
|
|
84963
|
+
waitMs = intervalMs;
|
|
84906
84964
|
continue;
|
|
84907
84965
|
}
|
|
84908
84966
|
throw new Error(`device approval failed: ${j.error ?? `HTTP ${res.status}`}`);
|