Skip to content

Commit cc46ff4

Browse files
authored
feat: print backend error notices for managing client version phase out (#6992)
1 parent 647c6de commit cc46ff4

File tree

6 files changed

+93
-12
lines changed

6 files changed

+93
-12
lines changed

core/src/cloud/grow/api.ts

+4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import type { CloudApiFactoryParams, CloudApiParams } from "../api.js"
3030
import { deline } from "../../util/string.js"
3131
import { TRPCClientError } from "@trpc/client"
3232
import type { InferrableClientTypes } from "@trpc/server/unstable-core-do-not-import"
33+
import { handleServerNotices } from "./notices.js"
3334

3435
const refreshThreshold = 10 // Threshold (in seconds) subtracted to jwt validity when checking if a refresh is needed
3536

@@ -159,6 +160,9 @@ export class GrowCloudApi {
159160
const verificationResult = await getNonAuthenticatedApiClient({ hostUrl: cloudDomain }).token.verifyToken.query({
160161
token: authToken,
161162
})
163+
164+
handleServerNotices(verificationResult.notices, cloudLog)
165+
162166
if (!verificationResult.valid) {
163167
log.debug({ msg: `The stored token was not valid.` })
164168
return undefined

core/src/cloud/grow/auth.ts

+7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { CloudApiError } from "../../exceptions.js"
1717
import { clearAuthToken, saveAuthToken } from "../auth.js"
1818
import { getCloudDistributionName } from "../util.js"
1919
import dedent from "dedent"
20+
import { handleServerNotices } from "./notices.js"
2021

2122
export function isTokenExpired(token: ClientAuthToken) {
2223
const now = new Date()
@@ -42,6 +43,9 @@ export async function isTokenValid({
4243
const verificationResult = await getNonAuthenticatedApiClient({ hostUrl: cloudDomain }).token.verifyToken.query({
4344
token: authToken,
4445
})
46+
47+
handleServerNotices(verificationResult.notices, log)
48+
4549
valid = verificationResult.valid
4650
} catch (err) {
4751
if (!(err instanceof TRPCError)) {
@@ -73,6 +77,9 @@ export async function refreshAuthTokenAndWriteToConfigStore(
7377
const result = await getNonAuthenticatedApiClient({ hostUrl: cloudDomain }).token.refreshToken.mutate({
7478
refreshToken,
7579
})
80+
81+
handleServerNotices(result.notices, log)
82+
7683
await saveAuthToken({
7784
log,
7885
globalConfigStore,

core/src/cloud/grow/notices.ts

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (C) 2018-2024 Garden Technologies, Inc. <[email protected]>
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
7+
*/
8+
9+
import { CloudApiError } from "../../exceptions.js"
10+
import type { Log } from "../../logger/log-entry.js"
11+
12+
type ServerNotice = {
13+
message: string
14+
severity: "warning" | "error" | "info"
15+
}
16+
17+
export function handleServerNotices(notices: ServerNotice[], log: Log) {
18+
for (const notice of notices) {
19+
switch (notice.severity) {
20+
case "warning":
21+
log.warn(`WARNING: ${notice.message}`)
22+
break
23+
case "error":
24+
log.error(`ERROR: ${notice.message}`)
25+
break
26+
case "info":
27+
log.info(notice.message)
28+
break
29+
}
30+
}
31+
32+
const errors = notices.filter((notice) => notice.severity === "error")
33+
if (errors.length > 0) {
34+
throw new CloudApiError({
35+
message: `There ${errors.length > 1 ? `were ${errors.length} errors` : "was an error"} connecting to Garden Cloud (See error logs above).`,
36+
})
37+
}
38+
}

core/src/cloud/grow/trpc-schema.ts

+38-10
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export declare const appRouter: import("@trpc/server/unstable-core-do-not-import
110110
email: string
111111
role: "admin" | "member"
112112
expiresAt: Date | null
113+
isOwner: boolean
113114
kind: "account" | "invitation"
114115
}[]
115116
nextCursor?: number | undefined
@@ -127,6 +128,7 @@ export declare const appRouter: import("@trpc/server/unstable-core-do-not-import
127128
updatedAt: Date
128129
email: string
129130
role: "admin" | "member"
131+
isOwner: boolean
130132
}
131133
}>
132134
update: import("@trpc/server").TRPCMutationProcedure<{
@@ -142,6 +144,7 @@ export declare const appRouter: import("@trpc/server/unstable-core-do-not-import
142144
updatedAt: Date
143145
email: string
144146
role: "admin" | "member"
147+
isOwner: boolean
145148
}
146149
}>
147150
remove: import("@trpc/server").TRPCMutationProcedure<{
@@ -362,6 +365,7 @@ export declare const appRouter: import("@trpc/server/unstable-core-do-not-import
362365
agentConfigurationId: string
363366
}
364367
output: {
368+
status: string
365369
id: string
366370
createdAt: Date
367371
updatedAt: Date
@@ -384,13 +388,6 @@ export declare const appRouter: import("@trpc/server/unstable-core-do-not-import
384388
}
385389
}[]
386390
}>
387-
getStatus: import("@trpc/server").TRPCQueryProcedure<{
388-
input: {
389-
organizationId: string
390-
agentInstanceId: string
391-
}
392-
output: string
393-
}>
394391
restart: import("@trpc/server").TRPCMutationProcedure<{
395392
input: {
396393
organizationId: string
@@ -414,12 +411,13 @@ export declare const appRouter: import("@trpc/server/unstable-core-do-not-import
414411
title: string
415412
userAgent: string
416413
url: string
417-
referrer: string
418414
pathNameClean: string
415+
referrer: string
419416
prevPage?:
420417
| {
421418
path: string
422419
title: string
420+
pathNameClean: string
423421
}
424422
| undefined
425423
}
@@ -474,7 +472,8 @@ export declare const appRouter: import("@trpc/server/unstable-core-do-not-import
474472
| "trialing"
475473
| "unpaid"
476474
| undefined
477-
priceQuantity?: number | undefined
475+
currentPriceQuantity?: number | undefined
476+
maximumPriceQuantity?: number | undefined
478477
billingInterval?: "month" | "year" | undefined
479478
currentPeriodStart?: Date | undefined
480479
currentPeriodEnd?: Date | undefined
@@ -1029,6 +1028,15 @@ export declare const appRouter: import("@trpc/server/unstable-core-do-not-import
10291028
transformer: true
10301029
},
10311030
import("@trpc/server/unstable-core-do-not-import").DecorateCreateRouterOptions<{
1031+
getByToken: import("@trpc/server").TRPCQueryProcedure<{
1032+
input: {
1033+
token: string
1034+
}
1035+
output: {
1036+
organizationName: string
1037+
inviterName: string
1038+
}
1039+
}>
10321040
create: import("@trpc/server").TRPCMutationProcedure<{
10331041
input: {
10341042
organizationId: string
@@ -1223,6 +1231,10 @@ export declare const appRouter: import("@trpc/server/unstable-core-do-not-import
12231231
}
12241232
output: {
12251233
valid: boolean
1234+
notices: {
1235+
message: string
1236+
severity: "info" | "error" | "warning"
1237+
}[]
12261238
}
12271239
}>
12281240
refreshToken: import("@trpc/server").TRPCMutationProcedure<{
@@ -1233,6 +1245,10 @@ export declare const appRouter: import("@trpc/server/unstable-core-do-not-import
12331245
accessToken: string
12341246
refreshToken: string
12351247
tokenValidity: number
1248+
notices: {
1249+
message: string
1250+
severity: "info" | "error" | "warning"
1251+
}[]
12361252
}
12371253
}>
12381254
revokeToken: import("@trpc/server").TRPCMutationProcedure<{
@@ -1245,7 +1261,7 @@ export declare const appRouter: import("@trpc/server/unstable-core-do-not-import
12451261
}>
12461262
createAccessToken: import("@trpc/server").TRPCMutationProcedure<{
12471263
input: {
1248-
label: string
1264+
name: string
12491265
}
12501266
output: {
12511267
value: string
@@ -1263,6 +1279,18 @@ export declare const appRouter: import("@trpc/server/unstable-core-do-not-import
12631279
}
12641280
output: void
12651281
}>
1282+
listAccessTokens: import("@trpc/server").TRPCQueryProcedure<{
1283+
input: void
1284+
output: {
1285+
value: string
1286+
type: "access" | "refresh" | "web"
1287+
createdAt: Date
1288+
updatedAt: Date
1289+
accountId: string
1290+
expiresAt: Date
1291+
label: string | null
1292+
}[]
1293+
}>
12661294
listTokens: import("@trpc/server").TRPCQueryProcedure<{
12671295
input: {
12681296
type?: "access" | "refresh" | "web" | undefined

core/src/cloud/grow/trpc.ts

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { createTRPCClient, httpLink, loggerLink } from "@trpc/client"
1111
import type { inferRouterInputs, inferRouterOutputs } from "@trpc/server"
1212
import superjson from "superjson"
1313
import type { AppRouter } from "./trpc-schema.js"
14+
import { getPackageVersion } from "../../util/util.js"
1415

1516
export type RouterOutput = inferRouterOutputs<AppRouter>
1617
export type RouterInput = inferRouterInputs<AppRouter>
@@ -50,6 +51,9 @@ function getTrpcConfig({ hostUrl, tokenGetter }: TrpcConfigParams) {
5051
headers.set("Authorization", `token ${tokenGetter()}`)
5152
}
5253

54+
headers.set("x-client-name", "garden-core")
55+
headers.set("x-client-version", getPackageVersion())
56+
5357
// Use standard fetch instead of bunFetch from Grow
5458
return await fetch(url, { ...options, headers })
5559
},

project.garden.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ environments:
1212
show-log: true
1313
providers:
1414
- name: kubernetes
15-
environments: [testing]
15+
environments: [ testing ]
1616
context: gke_garden-ci_europe-west1-b_core-ci
1717
namespace: e2e-tests
1818
defaultHostname: dev-1.sys.garden
1919
buildMode: cluster-buildkit
2020
setupIngressController: nginx
2121
- name: local-kubernetes
22-
environments: [local]
22+
environments: [ local ]
2323
variables:
2424
timeout: 360
2525
show-log: false

0 commit comments

Comments
 (0)