Skip to content

Commit b9a855c

Browse files
committed
update
Signed-off-by: raj-subhankar <subhankar.rj@gmail.com>
1 parent 2d60102 commit b9a855c

File tree

9 files changed

+89
-61
lines changed

9 files changed

+89
-61
lines changed

crates/goose-server/src/routes/setup.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::routes::errors::ErrorResponse;
22
use crate::state::AppState;
3-
use axum::{http::StatusCode, routing::post, Json, Router};
3+
use axum::{routing::post, Json, Router};
44
use goose::config::signup_openrouter::OpenRouterAuth;
55
use goose::config::signup_tetrate::{configure_tetrate, TetrateAuth};
66
use goose::config::{configure_openrouter, Config};
@@ -72,7 +72,7 @@ async fn start_openrouter_setup() -> Result<Json<SetupResponse>, ErrorResponse>
7272
)]
7373
async fn verify_tetrate_setup(
7474
Json(request): Json<TetrateVerifyRequest>,
75-
) -> Result<Json<SetupResponse>, StatusCode> {
75+
) -> Result<Json<SetupResponse>, ErrorResponse> {
7676
let api_key =
7777
match TetrateAuth::exchange_code_with_verifier(request.code, request.code_verifier).await {
7878
Ok(api_key) => api_key,

ui/desktop/openapi.json

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3236,6 +3236,36 @@
32363236
}
32373237
}
32383238
},
3239+
"/tetrate/verify": {
3240+
"post": {
3241+
"tags": [
3242+
"super::routes::setup"
3243+
],
3244+
"operationId": "verify_tetrate_setup",
3245+
"requestBody": {
3246+
"content": {
3247+
"application/json": {
3248+
"schema": {
3249+
"$ref": "#/components/schemas/TetrateVerifyRequest"
3250+
}
3251+
}
3252+
},
3253+
"required": true
3254+
},
3255+
"responses": {
3256+
"200": {
3257+
"description": "",
3258+
"content": {
3259+
"application/json": {
3260+
"schema": {
3261+
"$ref": "#/components/schemas/SetupResponse"
3262+
}
3263+
}
3264+
}
3265+
}
3266+
}
3267+
}
3268+
},
32393269
"/tunnel/start": {
32403270
"post": {
32413271
"tags": [
@@ -6859,6 +6889,21 @@
68596889
}
68606890
}
68616891
},
6892+
"TetrateVerifyRequest": {
6893+
"type": "object",
6894+
"required": [
6895+
"code",
6896+
"code_verifier"
6897+
],
6898+
"properties": {
6899+
"code": {
6900+
"type": "string"
6901+
},
6902+
"code_verifier": {
6903+
"type": "string"
6904+
}
6905+
}
6906+
},
68626907
"TextContent": {
68636908
"type": "object",
68646909
"required": [

ui/desktop/src/api/index.ts

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

ui/desktop/src/api/sdk.gen.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import type { Client, Options as Options2, TDataShape } from './client';
44
import { client } from './client.gen';
5-
import type { AddExtensionData, AddExtensionErrors, AddExtensionResponses, AgentAddExtensionData, AgentAddExtensionErrors, AgentAddExtensionResponses, AgentRemoveExtensionData, AgentRemoveExtensionErrors, AgentRemoveExtensionResponses, BackupConfigData, BackupConfigErrors, BackupConfigResponses, CallToolData, CallToolErrors, CallToolResponses, CancelDownloadData, CancelDownloadErrors, CancelDownloadResponses, CheckProviderData, ConfigureProviderOauthData, ConfigureProviderOauthErrors, ConfigureProviderOauthResponses, ConfirmToolActionData, ConfirmToolActionErrors, ConfirmToolActionResponses, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponses, CreateRecipeData, CreateRecipeErrors, CreateRecipeResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleResponses, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeResponses, DeleteModelData, DeleteModelErrors, DeleteModelResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponses, DeleteSessionData, DeleteSessionErrors, DeleteSessionResponses, DetectProviderData, DetectProviderErrors, DetectProviderResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponses, DownloadModelData, DownloadModelErrors, DownloadModelResponses, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeResponses, ExportAppData, ExportAppErrors, ExportAppResponses, ExportSessionData, ExportSessionErrors, ExportSessionResponses, ForkSessionData, ForkSessionErrors, ForkSessionResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponses, GetDictationConfigData, GetDictationConfigResponses, GetDownloadProgressData, GetDownloadProgressErrors, GetDownloadProgressResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponses, GetPricingData, GetPricingResponses, GetPromptData, GetPromptErrors, GetPromptResponses, GetPromptsData, GetPromptsResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponses, GetSessionData, GetSessionErrors, GetSessionExtensionsData, GetSessionExtensionsErrors, GetSessionExtensionsResponses, GetSessionInsightsData, GetSessionInsightsErrors, GetSessionInsightsResponses, GetSessionResponses, GetSlashCommandsData, GetSlashCommandsResponses, GetToolsData, GetToolsErrors, GetToolsResponses, GetTunnelStatusData, GetTunnelStatusResponses, ImportAppData, ImportAppErrors, ImportAppResponses, ImportSessionData, ImportSessionErrors, ImportSessionResponses, InitConfigData, InitConfigErrors, InitConfigResponses, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponses, KillRunningJobData, KillRunningJobResponses, ListAppsData, ListAppsErrors, ListAppsResponses, ListModelsData, ListModelsResponses, ListRecipesData, ListRecipesErrors, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponses, ListSessionsData, ListSessionsErrors, ListSessionsResponses, McpUiProxyData, McpUiProxyErrors, McpUiProxyResponses, ParseRecipeData, ParseRecipeErrors, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponses, ProvidersData, ProvidersResponses, ReadAllConfigData, ReadAllConfigResponses, ReadConfigData, ReadConfigErrors, ReadConfigResponses, ReadResourceData, ReadResourceErrors, ReadResourceResponses, RecipeToYamlData, RecipeToYamlErrors, RecipeToYamlResponses, RecoverConfigData, RecoverConfigErrors, RecoverConfigResponses, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponses, ResetPromptData, ResetPromptErrors, ResetPromptResponses, RestartAgentData, RestartAgentErrors, RestartAgentResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentResponses, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponses, SavePromptData, SavePromptErrors, SavePromptResponses, SaveRecipeData, SaveRecipeErrors, SaveRecipeResponses, ScanRecipeData, ScanRecipeResponses, ScheduleRecipeData, ScheduleRecipeErrors, ScheduleRecipeResponses, SearchSessionsData, SearchSessionsErrors, SearchSessionsResponses, SendTelemetryEventData, SendTelemetryEventResponses, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponses, SetConfigProviderData, SetRecipeSlashCommandData, SetRecipeSlashCommandErrors, SetRecipeSlashCommandResponses, StartAgentData, StartAgentErrors, StartAgentResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponses, StartTunnelData, StartTunnelErrors, StartTunnelResponses, StatusData, StatusResponses, StopAgentData, StopAgentErrors, StopAgentResponses, StopTunnelData, StopTunnelErrors, StopTunnelResponses, SystemInfoData, SystemInfoResponses, TranscribeDictationData, TranscribeDictationErrors, TranscribeDictationResponses, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionResponses, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleResponses, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesResponses, UpdateWorkingDirData, UpdateWorkingDirErrors, UpdateWorkingDirResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsResponses, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponses } from './types.gen';
5+
import type { AddExtensionData, AddExtensionErrors, AddExtensionResponses, AgentAddExtensionData, AgentAddExtensionErrors, AgentAddExtensionResponses, AgentRemoveExtensionData, AgentRemoveExtensionErrors, AgentRemoveExtensionResponses, BackupConfigData, BackupConfigErrors, BackupConfigResponses, CallToolData, CallToolErrors, CallToolResponses, CancelDownloadData, CancelDownloadErrors, CancelDownloadResponses, CheckProviderData, ConfigureProviderOauthData, ConfigureProviderOauthErrors, ConfigureProviderOauthResponses, ConfirmToolActionData, ConfirmToolActionErrors, ConfirmToolActionResponses, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponses, CreateRecipeData, CreateRecipeErrors, CreateRecipeResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleResponses, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeResponses, DeleteModelData, DeleteModelErrors, DeleteModelResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponses, DeleteSessionData, DeleteSessionErrors, DeleteSessionResponses, DetectProviderData, DetectProviderErrors, DetectProviderResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponses, DownloadModelData, DownloadModelErrors, DownloadModelResponses, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeResponses, ExportAppData, ExportAppErrors, ExportAppResponses, ExportSessionData, ExportSessionErrors, ExportSessionResponses, ForkSessionData, ForkSessionErrors, ForkSessionResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponses, GetDictationConfigData, GetDictationConfigResponses, GetDownloadProgressData, GetDownloadProgressErrors, GetDownloadProgressResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponses, GetPricingData, GetPricingResponses, GetPromptData, GetPromptErrors, GetPromptResponses, GetPromptsData, GetPromptsResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponses, GetSessionData, GetSessionErrors, GetSessionExtensionsData, GetSessionExtensionsErrors, GetSessionExtensionsResponses, GetSessionInsightsData, GetSessionInsightsErrors, GetSessionInsightsResponses, GetSessionResponses, GetSlashCommandsData, GetSlashCommandsResponses, GetToolsData, GetToolsErrors, GetToolsResponses, GetTunnelStatusData, GetTunnelStatusResponses, ImportAppData, ImportAppErrors, ImportAppResponses, ImportSessionData, ImportSessionErrors, ImportSessionResponses, InitConfigData, InitConfigErrors, InitConfigResponses, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponses, KillRunningJobData, KillRunningJobResponses, ListAppsData, ListAppsErrors, ListAppsResponses, ListModelsData, ListModelsResponses, ListRecipesData, ListRecipesErrors, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponses, ListSessionsData, ListSessionsErrors, ListSessionsResponses, McpUiProxyData, McpUiProxyErrors, McpUiProxyResponses, ParseRecipeData, ParseRecipeErrors, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponses, ProvidersData, ProvidersResponses, ReadAllConfigData, ReadAllConfigResponses, ReadConfigData, ReadConfigErrors, ReadConfigResponses, ReadResourceData, ReadResourceErrors, ReadResourceResponses, RecipeToYamlData, RecipeToYamlErrors, RecipeToYamlResponses, RecoverConfigData, RecoverConfigErrors, RecoverConfigResponses, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponses, ResetPromptData, ResetPromptErrors, ResetPromptResponses, RestartAgentData, RestartAgentErrors, RestartAgentResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentResponses, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponses, SavePromptData, SavePromptErrors, SavePromptResponses, SaveRecipeData, SaveRecipeErrors, SaveRecipeResponses, ScanRecipeData, ScanRecipeResponses, ScheduleRecipeData, ScheduleRecipeErrors, ScheduleRecipeResponses, SearchSessionsData, SearchSessionsErrors, SearchSessionsResponses, SendTelemetryEventData, SendTelemetryEventResponses, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponses, SetConfigProviderData, SetRecipeSlashCommandData, SetRecipeSlashCommandErrors, SetRecipeSlashCommandResponses, StartAgentData, StartAgentErrors, StartAgentResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponses, StartTunnelData, StartTunnelErrors, StartTunnelResponses, StatusData, StatusResponses, StopAgentData, StopAgentErrors, StopAgentResponses, StopTunnelData, StopTunnelErrors, StopTunnelResponses, SystemInfoData, SystemInfoResponses, TranscribeDictationData, TranscribeDictationErrors, TranscribeDictationResponses, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionResponses, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleResponses, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesResponses, UpdateWorkingDirData, UpdateWorkingDirErrors, UpdateWorkingDirResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsResponses, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponses, VerifyTetrateSetupData, VerifyTetrateSetupResponses } from './types.gen';
66

77
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = Options2<TData, ThrowOnError> & {
88
/**
@@ -508,6 +508,15 @@ export const sendTelemetryEvent = <ThrowOnError extends boolean = false>(options
508508
}
509509
});
510510

511+
export const verifyTetrateSetup = <ThrowOnError extends boolean = false>(options: Options<VerifyTetrateSetupData, ThrowOnError>) => (options.client ?? client).post<VerifyTetrateSetupResponses, unknown, ThrowOnError>({
512+
url: '/tetrate/verify',
513+
...options,
514+
headers: {
515+
'Content-Type': 'application/json',
516+
...options.headers
517+
}
518+
});
519+
511520
/**
512521
* Start the tunnel
513522
*/

ui/desktop/src/api/types.gen.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,11 @@ export type Template = {
11821182
user_content?: string | null;
11831183
};
11841184

1185+
export type TetrateVerifyRequest = {
1186+
code: string;
1187+
code_verifier: string;
1188+
};
1189+
11851190
export type TextContent = {
11861191
_meta?: {
11871192
[key: string]: unknown;
@@ -3907,6 +3912,19 @@ export type SendTelemetryEventResponses = {
39073912
202: unknown;
39083913
};
39093914

3915+
export type VerifyTetrateSetupData = {
3916+
body: TetrateVerifyRequest;
3917+
path?: never;
3918+
query?: never;
3919+
url: '/tetrate/verify';
3920+
};
3921+
3922+
export type VerifyTetrateSetupResponses = {
3923+
200: SetupResponse;
3924+
};
3925+
3926+
export type VerifyTetrateSetupResponse = VerifyTetrateSetupResponses[keyof VerifyTetrateSetupResponses];
3927+
39103928
export type StartTunnelData = {
39113929
body?: never;
39123930
path?: never;

ui/desktop/src/components/ProviderGuard.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ import { useNavigate } from 'react-router-dom';
33
import { useConfig } from './ConfigContext';
44
import { SetupModal } from './SetupModal';
55
import { startOpenRouterSetup } from '../utils/openRouterSetup';
6-
import { startTetrateSetup } from '../utils/tetrateSetup';
6+
import { cancelTetrateSetup, startTetrateSetup } from '../utils/tetrateSetup';
77
import { startChatGptCodexSetup } from '../utils/chatgptCodexSetup';
8-
import { cancelTetrateSetup } from '../utils/tetrateSetup';
98
import WelcomeGooseLogo from './WelcomeGooseLogo';
109
import { toastService } from '../toasts';
1110
import { OllamaSetup } from './OllamaSetup';

ui/desktop/src/tetrateAuth.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,16 @@ describe('tetrateAuth', () => {
5454
expect(parsed.searchParams.get('client')).toBe('goose');
5555
});
5656

57-
it('parses valid callback URLs and rejects invalid ones', () => {
57+
it('matches valid callback URLs and rejects invalid ones', () => {
5858
const url = 'goose://auth/tetrate?flow_id=flow&state=state&code=code';
59-
expect(__test.parseTetrateCallbackUrl(url)).toEqual({
60-
code: 'code',
59+
expect(__test.matchTetrateCallbackUrl(url)).toEqual({
6160
flowId: 'flow',
6261
state: 'state',
62+
code: 'code',
6363
});
6464

65-
expect(__test.parseTetrateCallbackUrl('goose://auth/other?flow_id=flow')).toBeNull();
66-
expect(__test.parseTetrateCallbackUrl('https://example.com')).toBeNull();
65+
expect(__test.matchTetrateCallbackUrl('goose://auth/other?flow_id=flow')).toBeNull();
66+
expect(__test.matchTetrateCallbackUrl('https://example.com')).toBeNull();
6767
});
6868

6969
it('resolves the waiting callback when a valid deep link arrives', async () => {

ui/desktop/src/tetrateAuth.ts

Lines changed: 5 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,6 @@ export type TetrateSetupResponse = {
1919
message: string;
2020
};
2121

22-
type TetrateCallbackData = {
23-
code: string;
24-
flowId: string;
25-
state: string;
26-
};
27-
2822
type TetrateCallbackMatch = {
2923
flowId: string;
3024
state: string;
@@ -63,34 +57,6 @@ function buildTetrateAuthUrl(callbackUrl: string, codeChallenge: string): string
6357
return url.toString();
6458
}
6559

66-
function parseTetrateCallbackUrl(callbackUrl: string): TetrateCallbackData | null {
67-
let parsedUrl: URL;
68-
try {
69-
parsedUrl = new URL(callbackUrl);
70-
} catch {
71-
return null;
72-
}
73-
74-
const normalizedPath = parsedUrl.pathname.replace(/\/$/, '');
75-
if (
76-
parsedUrl.protocol !== `${TETRATE_AUTH_CALLBACK_SCHEME}:` ||
77-
parsedUrl.hostname !== 'auth' ||
78-
normalizedPath !== '/tetrate'
79-
) {
80-
return null;
81-
}
82-
83-
const code = parsedUrl.searchParams.get('code');
84-
const flowId = parsedUrl.searchParams.get('flow_id');
85-
const state = parsedUrl.searchParams.get('state');
86-
87-
if (!code || !flowId || !state) {
88-
return null;
89-
}
90-
91-
return { code, flowId, state };
92-
}
93-
9460
function matchTetrateCallbackUrl(callbackUrl: string): TetrateCallbackMatch | null {
9561
let parsedUrl: URL;
9662
try {
@@ -287,30 +253,22 @@ export async function runTetrateAuthFlow(client: Client): Promise<TetrateSetupRe
287253

288254
try {
289255
const callbackUrl = await startTetrateAuthSession(flowId, authUrl);
290-
const callback = parseTetrateCallbackUrl(callbackUrl);
256+
const match = matchTetrateCallbackUrl(callbackUrl);
291257

292-
if (!callback) {
258+
if (!match?.code) {
293259
throw new Error('Invalid authentication response');
294260
}
295261

296-
const flow = tetrateAuthFlows.get(callback.flowId);
262+
const flow = tetrateAuthFlows.get(flowId);
297263
if (!flow) {
298264
throw new Error('Authentication expired');
299265
}
300266

301-
if (flow.state !== callback.state) {
302-
throw new Error('Authentication state mismatch');
303-
}
304-
305-
if (Date.now() > flow.expiresAt) {
306-
throw new Error('Authentication timed out');
307-
}
308-
309267
const codeVerifier = flow.codeVerifier;
310-
cleanupTetrateAuthFlow(callback.flowId);
268+
cleanupTetrateAuthFlow(flowId);
311269

312270
const response = await verifyTetrateSetup({
313-
body: { code: callback.code, code_verifier: codeVerifier },
271+
body: { code: match.code, code_verifier: codeVerifier },
314272
throwOnError: true,
315273
client,
316274
});
@@ -339,7 +297,6 @@ export const __test = {
339297
createTetrateAuthFlow,
340298
getTetrateAuthTtlMs: () => TETRATE_AUTH_TTL_MS,
341299
matchTetrateCallbackUrl,
342-
parseTetrateCallbackUrl,
343300
resetForTests: () => {
344301
for (const flow of tetrateAuthFlows.values()) {
345302
if (flow.timeoutId) {

ui/desktop/src/utils/tetrateSetup.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export async function startTetrateSetup(): Promise<{
77
} catch (e) {
88
return {
99
success: false,
10-
message: `Failed to start Tetrate setup ['${e}]`,
10+
message: `Failed to start Tetrate setup: ${e}`,
1111
};
1212
}
1313
}

0 commit comments

Comments
 (0)