diff --git a/extensions/clickclack/src/setup-claim.ts b/extensions/clickclack/src/setup-claim.ts index 9bc4ff3de031..148fd891a3ce 100644 --- a/extensions/clickclack/src/setup-claim.ts +++ b/extensions/clickclack/src/setup-claim.ts @@ -13,7 +13,7 @@ const CLICKCLACK_ERROR_BODY_LIMIT_BYTES = 8 * 1024; const CLICKCLACK_SETUP_CODE_CLAIM_JSON_LIMIT_BYTES = 64 * 1024; const CLICKCLACK_SETUP_CODE_CLAIM_TIMEOUT_MS = 30_000; -export class ClickClackSetupCodeClaimError extends Error { +class ClickClackSetupCodeClaimError extends Error { constructor( readonly status: number, detail: string, diff --git a/extensions/clickclack/src/setup-core.test.ts b/extensions/clickclack/src/setup-core.test.ts index 4daee6ab28c6..d714d5b4e902 100644 --- a/extensions/clickclack/src/setup-core.test.ts +++ b/extensions/clickclack/src/setup-core.test.ts @@ -14,13 +14,18 @@ vi.mock("./setup-claim.js", async (importOriginal) => ({ vi.mock("./setup-verify.js", () => ({ verifyClickClackAccountAfterSetup, })); -import { ClickClackSetupCodeClaimError } from "./setup-claim.js"; import { applyClickClackCredentialConfig, clickClackSetupAdapter, normalizeClickClackBaseUrl, } from "./setup-core.js"; +// Structural stand-in for the internal claim error: the setup formatter +// duck-types on a numeric `status`, so tests need only that shape. +function makeClaimError(status: number, detail: string): Error { + return Object.assign(new Error(`claim failed (${status}): ${detail}`), { status }); +} + function validate(params: { cfg?: OpenClawConfig; accountId?: string; @@ -163,16 +168,12 @@ describe("ClickClack setup adapter", () => { }); it("maps invalid and rate-limited claims to actionable errors", async () => { - claimClickClackSetupCode.mockRejectedValueOnce( - new ClickClackSetupCodeClaimError(404, "not found"), - ); + claimClickClackSetupCode.mockRejectedValueOnce(makeClaimError(404, "not found")); await expect( prepare({ code: "ABCD-EFGH-JKMN", baseUrl: "https://clickclack.example" }), ).rejects.toThrow("invalid, expired, or already used"); - claimClickClackSetupCode.mockRejectedValueOnce( - new ClickClackSetupCodeClaimError(429, "retry later"), - ); + claimClickClackSetupCode.mockRejectedValueOnce(makeClaimError(429, "retry later")); await expect( prepare({ code: "ABCD-EFGH-JKMN", baseUrl: "https://clickclack.example" }), ).rejects.toThrow("Too many ClickClack setup code attempts"); diff --git a/extensions/clickclack/src/setup-core.ts b/extensions/clickclack/src/setup-core.ts index 089581bd6f7a..09db51db7733 100644 --- a/extensions/clickclack/src/setup-core.ts +++ b/extensions/clickclack/src/setup-core.ts @@ -42,7 +42,7 @@ function normalizeClickClackSetupCode(value: string): string | undefined { const normalized = value.trim().toUpperCase().replaceAll("-", "").replaceAll(" ", ""); if ( normalized.length !== SETUP_CODE_LENGTH || - [...normalized].some((character) => !SETUP_CODE_ALPHABET.includes(character)) + Array.from(normalized).some((character) => !SETUP_CODE_ALPHABET.includes(character)) ) { return undefined; } @@ -57,7 +57,7 @@ function requireHttpsClickClackBaseUrl(value: string | undefined): string { return baseUrl; } -export function parseClickClackSetupCodeInput(params: { code: string; baseUrl?: string }): { +function parseClickClackSetupCodeInput(params: { code: string; baseUrl?: string }): { code: string; baseUrl: string; } { @@ -263,7 +263,7 @@ export const clickClackSetupAdapter: ChannelSetupAdapter = { return { ...remainingInput, baseUrl: setup.baseUrl, - ["token"]: claim.token, + token: claim.token, workspace: claim.workspace.id, ...(claim.defaults.defaultTo !== undefined ? { defaultTo: claim.defaults.defaultTo } : {}), ...(claim.defaults.allowFrom !== undefined