alegra-data-agent 0.5.0 → 0.5.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/api.js +53 -2
- package/dist/auth.js +12 -0
- package/dist/commands/login.js +8 -0
- package/dist/commands/update.js +13 -7
- package/dist/main.js +6 -2
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
|
-
import { readAuth } from "./auth.js";
|
|
3
|
+
import { authRecordFromToken, authRemainingMs, readAuth, writeAuth } from "./auth.js";
|
|
4
4
|
import { COMMAND_NAME, GATEWAY_URL, getManifestCachePath, getPackageVersion, readLockFile, writeLockFile, } from "./lib.js";
|
|
5
5
|
import { manifestTimestamp, verifyManifestSignature } from "./signature.js";
|
|
6
6
|
export class ManifestSignatureError extends Error {
|
|
@@ -37,8 +37,55 @@ function sleep(ms) {
|
|
|
37
37
|
return new Promise((r) => setTimeout(r, ms));
|
|
38
38
|
}
|
|
39
39
|
let rateLimitCooldownUntil = 0;
|
|
40
|
-
|
|
40
|
+
const REFRESH_AHEAD_MS = 2 * 24 * 3600_000;
|
|
41
|
+
let refreshTriedFor = null;
|
|
42
|
+
export function shouldRefreshAuth() {
|
|
43
|
+
const remaining = authRemainingMs(readAuth());
|
|
44
|
+
return remaining !== null && remaining < REFRESH_AHEAD_MS;
|
|
45
|
+
}
|
|
46
|
+
export async function refreshAuth() {
|
|
41
47
|
const auth = readAuth();
|
|
48
|
+
if (!auth)
|
|
49
|
+
return false;
|
|
50
|
+
refreshTriedFor = auth.token;
|
|
51
|
+
try {
|
|
52
|
+
const res = await fetch(`${GATEWAY_URL}/api/cli/refresh`, {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: {
|
|
55
|
+
Authorization: `Bearer ${auth.token}`,
|
|
56
|
+
Accept: "application/json",
|
|
57
|
+
"User-Agent": userAgent(),
|
|
58
|
+
"X-Request-Id": newRequestId(),
|
|
59
|
+
},
|
|
60
|
+
signal: AbortSignal.timeout(10_000),
|
|
61
|
+
});
|
|
62
|
+
if (!res.ok)
|
|
63
|
+
return false;
|
|
64
|
+
const body = (await res.json());
|
|
65
|
+
if (typeof body.token !== "string")
|
|
66
|
+
return false;
|
|
67
|
+
const record = authRecordFromToken(body.token);
|
|
68
|
+
if (!record)
|
|
69
|
+
return false;
|
|
70
|
+
writeAuth(record);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export async function ensureFreshAuth() {
|
|
78
|
+
if (readAuth()?.token !== refreshTriedFor && shouldRefreshAuth())
|
|
79
|
+
await refreshAuth();
|
|
80
|
+
const auth = readAuth();
|
|
81
|
+
if (!auth)
|
|
82
|
+
return false;
|
|
83
|
+
const remaining = authRemainingMs(auth);
|
|
84
|
+
return remaining === null || remaining > 60_000;
|
|
85
|
+
}
|
|
86
|
+
async function authedFetch(path, opts = {}) {
|
|
87
|
+
await ensureFreshAuth();
|
|
88
|
+
let auth = readAuth();
|
|
42
89
|
if (!auth) {
|
|
43
90
|
if (opts.requireAuth === false) {
|
|
44
91
|
return new Response(null, { status: 401 });
|
|
@@ -84,6 +131,10 @@ async function authedFetch(path, opts = {}) {
|
|
|
84
131
|
clearTimeout(timer);
|
|
85
132
|
}
|
|
86
133
|
if (res.status === 401) {
|
|
134
|
+
if (auth.token !== refreshTriedFor && (await refreshAuth())) {
|
|
135
|
+
auth = readAuth() ?? auth;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
87
138
|
if (opts.requireAuth === false)
|
|
88
139
|
return res;
|
|
89
140
|
throw new AuthRequiredError(`Sesión expirada. Agente: ejecutá vos mismo \`pnpm dlx ${COMMAND_NAME} login\` — al usuario solo le toca el click del navegador.`);
|
package/dist/auth.js
CHANGED
|
@@ -83,6 +83,18 @@ export function isAuthExpired(record) {
|
|
|
83
83
|
return false;
|
|
84
84
|
return Date.now() >= exp * 1000 - 60_000;
|
|
85
85
|
}
|
|
86
|
+
export function authRemainingMs(record) {
|
|
87
|
+
if (!record)
|
|
88
|
+
return null;
|
|
89
|
+
const exp = decodeJwtExp(record.token);
|
|
90
|
+
return exp === null ? null : exp * 1000 - Date.now();
|
|
91
|
+
}
|
|
92
|
+
export function authRecordFromToken(token) {
|
|
93
|
+
const email = decodeJwtEmail(token);
|
|
94
|
+
if (!email)
|
|
95
|
+
return null;
|
|
96
|
+
return { email, token, obtainedAt: new Date().toISOString() };
|
|
97
|
+
}
|
|
86
98
|
export function hasValidAuth() {
|
|
87
99
|
const record = readAuth();
|
|
88
100
|
return record !== null && !isAuthExpired(record);
|
package/dist/commands/login.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { refreshAuth } from "../api.js";
|
|
1
2
|
import { isAuthExpired, performBrowserLogin, readAuth, writeAuth } from "../auth.js";
|
|
2
3
|
import { bold, dim, green, log, logError, logWarn } from "../colors.js";
|
|
3
4
|
import { GATEWAY_URL, getAuthFilePath } from "../lib.js";
|
|
@@ -13,6 +14,13 @@ export async function runLogin(opts = {}) {
|
|
|
13
14
|
log("");
|
|
14
15
|
return 0;
|
|
15
16
|
}
|
|
17
|
+
if (existing && (await refreshAuth())) {
|
|
18
|
+
const renewed = readAuth();
|
|
19
|
+
log(` ${green("✓")} Sesión renovada como ${bold(renewed?.email ?? existing.email)}.`);
|
|
20
|
+
log(dim(` Token: ${getAuthFilePath()}`));
|
|
21
|
+
log("");
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
16
24
|
if (existing) {
|
|
17
25
|
logWarn(`Tu sesión (${existing.email}) expiró — reabro el login.`);
|
|
18
26
|
}
|
package/dist/commands/update.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { appendFileSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
|
-
import { AuthRequiredError, fetchManifest } from "../api.js";
|
|
3
|
+
import { AuthRequiredError, ensureFreshAuth, fetchManifest } from "../api.js";
|
|
4
4
|
import { hasValidAuth } from "../auth.js";
|
|
5
5
|
import { refreshAutoUpdate } from "../autoupdate.js";
|
|
6
6
|
import { cyan, dim, gray, green, log, logError, yellow } from "../colors.js";
|
|
7
7
|
import { detectDrift, installAll, summarize } from "../installer.js";
|
|
8
|
-
import { COMMAND_NAME, getAutoUpdateLogPath, getLastCheckPath } from "../lib.js";
|
|
8
|
+
import { COMMAND_NAME, getAutoUpdateLogPath, getLastCheckPath, getPackageVersion, } from "../lib.js";
|
|
9
9
|
import { banner } from "../ui.js";
|
|
10
10
|
import { runLogin } from "./login.js";
|
|
11
11
|
const BACKGROUND_COOLDOWN_MS = 15 * 60_000;
|
|
@@ -71,14 +71,18 @@ async function loginFromBackground(reason, force = false) {
|
|
|
71
71
|
markAuthFailed();
|
|
72
72
|
return false;
|
|
73
73
|
}
|
|
74
|
+
function warnStaleFromBackground() {
|
|
75
|
+
log(yellow(` ⚠ ${COMMAND_NAME} v${getPackageVersion()}: no pude actualizar las skills porque la sesión venció. Agente: corré vos mismo \`pnpm dlx ${COMMAND_NAME} login\` y después \`pnpm dlx ${COMMAND_NAME} update\` — al usuario solo le toca el clic del navegador.`));
|
|
76
|
+
}
|
|
74
77
|
export async function runUpdate(opts = {}) {
|
|
75
78
|
if (opts.background && !opts.dryRun && checkedRecently())
|
|
76
79
|
return 0;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
const fresh = await ensureFreshAuth();
|
|
81
|
+
if (opts.background && !fresh) {
|
|
82
|
+
if (authFailedRecently() || !(await loginFromBackground("sesión vencida o ausente"))) {
|
|
83
|
+
warnStaleFromBackground();
|
|
81
84
|
return 0;
|
|
85
|
+
}
|
|
82
86
|
}
|
|
83
87
|
banner();
|
|
84
88
|
if (!hasValidAuth()) {
|
|
@@ -94,8 +98,10 @@ export async function runUpdate(opts = {}) {
|
|
|
94
98
|
catch (err) {
|
|
95
99
|
if (err instanceof AuthRequiredError && opts.background && !reauthed) {
|
|
96
100
|
reauthed = true;
|
|
97
|
-
if (!(await loginFromBackground("el gateway rechazó la sesión", true)))
|
|
101
|
+
if (!(await loginFromBackground("el gateway rechazó la sesión", true))) {
|
|
102
|
+
warnStaleFromBackground();
|
|
98
103
|
return 0;
|
|
104
|
+
}
|
|
99
105
|
continue;
|
|
100
106
|
}
|
|
101
107
|
if (err instanceof AuthRequiredError && !reauthed) {
|
package/dist/main.js
CHANGED
|
@@ -83,9 +83,13 @@ async function main() {
|
|
|
83
83
|
log(helpText());
|
|
84
84
|
exitCode = 1;
|
|
85
85
|
}
|
|
86
|
-
|
|
86
|
+
exitGracefully(exitCode);
|
|
87
|
+
}
|
|
88
|
+
function exitGracefully(code) {
|
|
89
|
+
process.exitCode = code;
|
|
90
|
+
setTimeout(() => process.exit(code), 2000).unref();
|
|
87
91
|
}
|
|
88
92
|
main().catch((err) => {
|
|
89
93
|
logError(err instanceof Error ? err.message : String(err));
|
|
90
|
-
|
|
94
|
+
exitGracefully(1);
|
|
91
95
|
});
|