@voxli/cli 0.6.0 → 0.6.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/commands/listen.js +15 -0
- package/dist/lib/oauth.d.ts +5 -0
- package/dist/lib/oauth.js +16 -0
- package/package.json +1 -1
package/dist/commands/listen.js
CHANGED
|
@@ -3,7 +3,9 @@ import { spawn } from "node:child_process";
|
|
|
3
3
|
import { resolveApiKey, resolveConfig, attemptTokenRefresh, } from "../lib/config.js";
|
|
4
4
|
import { buildAgentIdentifier, getStableHostname } from "../lib/hostname.js";
|
|
5
5
|
import { register, ApiError } from "../lib/api.js";
|
|
6
|
+
import { getJwtExpiry } from "../lib/oauth.js";
|
|
6
7
|
const POLL_INTERVAL = 5_000;
|
|
8
|
+
const REFRESH_BUFFER_SECONDS = 30 * 60;
|
|
7
9
|
export async function listenCommand(options) {
|
|
8
10
|
const isEnvToken = !!resolveApiKey();
|
|
9
11
|
let apiKey = null;
|
|
@@ -40,6 +42,19 @@ export async function listenCommand(options) {
|
|
|
40
42
|
console.log(`Listening as ${displayName} (${uniqueIdentifier}) using credentials from ${credentialSource}`);
|
|
41
43
|
while (true) {
|
|
42
44
|
try {
|
|
45
|
+
// Proactively refresh if the token expires within the buffer window so
|
|
46
|
+
// newly-spawned subprocesses inherit a token that will outlast the test.
|
|
47
|
+
if (!isEnvToken) {
|
|
48
|
+
const exp = getJwtExpiry(apiKey);
|
|
49
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
50
|
+
if (exp !== null && exp - nowSec < REFRESH_BUFFER_SECONDS) {
|
|
51
|
+
const newToken = await attemptTokenRefresh(apiKey);
|
|
52
|
+
if (newToken && newToken !== apiKey) {
|
|
53
|
+
apiKey = newToken;
|
|
54
|
+
console.log("Access token refreshed proactively.");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
43
58
|
const data = await register(apiKey, {
|
|
44
59
|
name: displayName,
|
|
45
60
|
unique_identifier: uniqueIdentifier,
|
package/dist/lib/oauth.d.ts
CHANGED
|
@@ -13,6 +13,11 @@ export declare function refreshAccessToken(baseUrl: string, refreshToken: string
|
|
|
13
13
|
accessToken: string;
|
|
14
14
|
refreshToken?: string;
|
|
15
15
|
}>;
|
|
16
|
+
/**
|
|
17
|
+
* Read the `exp` claim (seconds since epoch) from a JWT access token.
|
|
18
|
+
* Returns null if the token isn't a parseable JWT or has no `exp`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getJwtExpiry(token: string): number | null;
|
|
16
21
|
export declare function buildAuthorizeUrl(baseUrl: string, params: {
|
|
17
22
|
clientId: string;
|
|
18
23
|
redirectUri: string;
|
package/dist/lib/oauth.js
CHANGED
|
@@ -66,6 +66,22 @@ export async function refreshAccessToken(baseUrl, refreshToken, clientId) {
|
|
|
66
66
|
refreshToken: data.refresh_token,
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Read the `exp` claim (seconds since epoch) from a JWT access token.
|
|
71
|
+
* Returns null if the token isn't a parseable JWT or has no `exp`.
|
|
72
|
+
*/
|
|
73
|
+
export function getJwtExpiry(token) {
|
|
74
|
+
const parts = token.split(".");
|
|
75
|
+
if (parts.length !== 3)
|
|
76
|
+
return null;
|
|
77
|
+
try {
|
|
78
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf-8"));
|
|
79
|
+
return typeof payload.exp === "number" ? payload.exp : null;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
69
85
|
export function buildAuthorizeUrl(baseUrl, params) {
|
|
70
86
|
const url = new URL("/oauth/authorize", baseUrl);
|
|
71
87
|
url.searchParams.set("response_type", "code");
|