Files
hyperframes/packages/cli/src/auth/errors.ts
T
Miguel Ángel de9bf487d4 fix(cli): publish with a refused login refreshes or asks you to log in again (#4964)
* fix(cli): publish with an expired login stops and asks you to log in again

The server now answers 401 to a rejected credential instead of publishing
anonymously, so the CLI says so and drops the warning for the old fallback.

* fix(cli): publish refreshes an expired login first, and names a rejected API key

An expired access token with a refresh token is refreshed (the cloud commands
already do) instead of being sent and refused. Only the requests that carry the
credential map a 401; an environment API key is named, since logging in would
not replace it.

* fix(cli): an expired login without a refresh token asks you to log in again

A stored login past expiry with no refresh token now resolves as
LOGIN_EXPIRED instead of "not signed in", so publish stops with the
re-login message before sending anything. A signed-in publish that the
server answers with an unclaimed project fails the same way and links nothing.

* fix(cli): keep the resolver comment share at its base

* fix(cli): an API-key publish still succeeds, and only an owned publish is linked

* fix(cli): --update and --space refuse an API key instead of being ignored

* fix(cli): publish uploads with the credential it checked, so --update and --space are never dropped

* fix(cli): a login that expires during the bake is refreshed, not reported as expired

* fix(cli): an expired login that cannot refresh stops publish before anything is sent

* fix(cli): a token refresh never writes over a login that replaced it

* fix(cli): a refresh that cannot read the saved login reports that, not a changed login
2026-10-04 04:56:23 +00:00

91 lines
2.5 KiB
TypeScript

/**
* Typed errors for the auth layer. Callers branch on `code` so commands
* can map specific failures to friendly UX without parsing messages.
*/
export type AuthErrorCode =
| "NOT_CONFIGURED"
| "INVALID_STORE"
| "API_ERROR"
| "UNAUTHENTICATED"
| "OAUTH_NOT_CONFIGURED"
| "DEVICE_AUTH_FAILED"
| "REFRESH_FAILED"
| "LOGIN_EXPIRED"
| "LOGIN_CHANGED";
export class AuthError extends Error {
readonly code: AuthErrorCode;
readonly hint?: string;
constructor(code: AuthErrorCode, message: string, hint?: string) {
super(message);
this.name = "AuthError";
this.code = code;
this.hint = hint;
}
}
export const ErrNotConfigured = () =>
new AuthError(
"NOT_CONFIGURED",
"No HeyGen credentials found",
"Run `hyperframes auth login` to sign in.",
);
export const ErrInvalidStore = (detail: string) =>
new AuthError(
"INVALID_STORE",
`Credential file is unreadable: ${detail}`,
"Delete ~/.heygen/credentials and run `hyperframes auth login` to re-create it.",
);
export const ErrUnauthenticated = (detail?: string) =>
new AuthError(
"UNAUTHENTICATED",
detail ? `HeyGen rejected the credential: ${detail}` : "HeyGen rejected the credential",
"Run `hyperframes auth login` to re-authenticate.",
);
export const ErrApi = (status: number, detail: string) =>
new AuthError("API_ERROR", `HeyGen API error (${status}): ${detail}`);
export const ErrOAuthNotConfigured = () =>
new AuthError(
"OAUTH_NOT_CONFIGURED",
"OAuth client is not configured",
"Set HYPERFRAMES_OAUTH_CLIENT_ID, or run `hyperframes auth login --api-key`.",
);
export const ErrRefreshFailed = (detail?: string) =>
new AuthError(
"REFRESH_FAILED",
detail ? `Failed to refresh OAuth tokens: ${detail}` : "Failed to refresh OAuth tokens",
"Run `hyperframes auth login` to re-authenticate.",
);
export const ErrLoginExpired = () =>
new AuthError(
"LOGIN_EXPIRED",
"Your HeyGen login expired",
"Run `hyperframes auth login` to sign in again.",
);
export const ErrLoginChanged = () =>
new AuthError(
"LOGIN_CHANGED",
"Your HeyGen login changed while this command ran",
"Run the command again.",
);
export const ErrDeviceAuthFailed = (detail: string) =>
new AuthError(
"DEVICE_AUTH_FAILED",
`Device authorization failed: ${detail}`,
"Run `hyperframes auth login --device` to start a new code.",
);
export function isAuthError(err: unknown): err is AuthError {
return err instanceof AuthError;
}