@metaplay/metaplay-auth 1.9.2 → 1.9.3
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/CHANGELOG.md +7 -0
- package/dist/index.cjs +154 -218
- package/dist/sshcrypto-TINMEJXV.node +0 -0
- package/index.ts +40 -26
- package/package.json +16 -17
- package/src/auth.ts +59 -27
- package/src/buildCommand.ts +3 -3
- package/src/deployment.ts +9 -9
- package/src/secret_store.ts +5 -5
- package/src/targetenvironment.ts +5 -5
- package/src/utils.ts +9 -9
- package/src/version.ts +1 -1
- package/dist/sshcrypto-47ANNZZ5.node +0 -0
|
Binary file
|
package/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander'
|
|
3
3
|
import Docker from 'dockerode'
|
|
4
|
-
import { writeFile } from 'fs/promises'
|
|
5
|
-
import { exit } from 'process'
|
|
4
|
+
import { writeFile } from 'node:fs/promises'
|
|
5
|
+
import { exit } from 'node:process'
|
|
6
6
|
import * as semver from 'semver'
|
|
7
7
|
|
|
8
8
|
import { KubeConfig } from '@kubernetes/client-node'
|
|
@@ -279,29 +279,34 @@ program
|
|
|
279
279
|
.description('login to the Metaplay cloud using a machine account (using credentials in environment variable METAPLAY_CREDENTIALS)')
|
|
280
280
|
.option('--dev-credentials', 'machine user credentials to use, only for dev purposes, use METAPLAY_CREDENTIALS env variable for better safety!')
|
|
281
281
|
.action(async (options) => {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
282
|
+
try {
|
|
283
|
+
// Get credentials from command line or from METAPLAY_CREDENTIALS environment variable
|
|
284
|
+
let credentials: string
|
|
285
|
+
if (options.devCredentials) {
|
|
286
|
+
credentials = options.devCredentials
|
|
287
|
+
} else {
|
|
288
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
289
|
+
credentials = process.env.METAPLAY_CREDENTIALS!
|
|
290
|
+
if (!credentials || credentials === '') {
|
|
291
|
+
throw new Error('Unable to find the credentials, the environment variable METAPLAY_CREDENTIALS is not defined!')
|
|
292
|
+
}
|
|
291
293
|
}
|
|
292
|
-
}
|
|
293
294
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
295
|
+
// Parse the clientId and clientSecret from the credentials (separate by a '+' character)
|
|
296
|
+
// \note We can't be certain that the secret does not contain pluses so split at the first occurrence
|
|
297
|
+
const splitOffset = credentials.indexOf('+')
|
|
298
|
+
if (splitOffset === -1) {
|
|
299
|
+
throw new Error('Invalid format for credentials, you should copy-paste the value from the developer portal verbatim')
|
|
300
|
+
}
|
|
301
|
+
const clientId = credentials.substring(0, splitOffset)
|
|
302
|
+
const clientSecret = credentials.substring(splitOffset + 1)
|
|
302
303
|
|
|
303
|
-
|
|
304
|
-
|
|
304
|
+
// Login with machine user and save the tokens
|
|
305
|
+
await machineLoginAndSaveTokens(clientId, clientSecret)
|
|
306
|
+
} catch (error) {
|
|
307
|
+
console.error(`Error during machine login: ${error instanceof Error ? error.message : String(error)}`)
|
|
308
|
+
exit(1)
|
|
309
|
+
}
|
|
305
310
|
})
|
|
306
311
|
|
|
307
312
|
program
|
|
@@ -720,7 +725,10 @@ program
|
|
|
720
725
|
})
|
|
721
726
|
} catch (error) {
|
|
722
727
|
const errMessage = error instanceof Error ? error.message : String(error)
|
|
723
|
-
throw new Error(
|
|
728
|
+
throw new Error(
|
|
729
|
+
`Failed to fetch docker image ${imageName} from target environment registry: ${errMessage}`,
|
|
730
|
+
{ cause: error }
|
|
731
|
+
)
|
|
724
732
|
}
|
|
725
733
|
|
|
726
734
|
// Resolve the labels
|
|
@@ -730,7 +738,10 @@ program
|
|
|
730
738
|
imageLabels = (await localDockerImage.inspect()).Config.Labels || {}
|
|
731
739
|
} catch (error) {
|
|
732
740
|
const errMessage = error instanceof Error ? error.message : String(error)
|
|
733
|
-
throw new Error(
|
|
741
|
+
throw new Error(
|
|
742
|
+
`Failed to resolve docker image metadata from pulled image ${imageName}: ${errMessage}`,
|
|
743
|
+
{ cause: error }
|
|
744
|
+
)
|
|
734
745
|
}
|
|
735
746
|
}
|
|
736
747
|
|
|
@@ -767,7 +778,10 @@ program
|
|
|
767
778
|
try {
|
|
768
779
|
helmChartRange = new semver.Range(helmChartVersionSpec)
|
|
769
780
|
} catch (error) {
|
|
770
|
-
throw new Error(
|
|
781
|
+
throw new Error(
|
|
782
|
+
`Helm chart version '${helmChartVersionSpec}' is not a valid SemVer range: ${String(error)}`,
|
|
783
|
+
{ cause: error }
|
|
784
|
+
)
|
|
771
785
|
}
|
|
772
786
|
}
|
|
773
787
|
|
|
@@ -925,7 +939,7 @@ program
|
|
|
925
939
|
kubeconfig.loadFromString(kubeconfigPayload)
|
|
926
940
|
} catch (error) {
|
|
927
941
|
const errMessage = error instanceof Error ? error.message : String(error)
|
|
928
|
-
throw new Error(`Failed to load or validate kubeconfig. ${errMessage}
|
|
942
|
+
throw new Error(`Failed to load or validate kubeconfig. ${errMessage}`, { cause: error })
|
|
929
943
|
}
|
|
930
944
|
|
|
931
945
|
// Resolve Helm deployment
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaplay/metaplay-auth",
|
|
3
3
|
"description": "Utility CLI for authenticating with the Metaplay Auth and making authenticated calls to infrastructure endpoints.",
|
|
4
|
-
"version": "1.9.
|
|
4
|
+
"version": "1.9.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
7
7
|
"homepage": "https://metaplay.io",
|
|
@@ -17,29 +17,28 @@
|
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@metaplay/eslint-config": "workspace:*",
|
|
20
|
-
"@types/dockerode": "3.3.
|
|
21
|
-
"@types/express": "5.0.
|
|
20
|
+
"@types/dockerode": "3.3.44",
|
|
21
|
+
"@types/express": "5.0.3",
|
|
22
22
|
"@types/js-yaml": "4.0.9",
|
|
23
|
-
"@types/jsonwebtoken": "9.0.
|
|
23
|
+
"@types/jsonwebtoken": "9.0.10",
|
|
24
24
|
"@types/jwk-to-pem": "2.0.3",
|
|
25
|
-
"@types/node": "
|
|
26
|
-
"@types/semver": "7.7.
|
|
27
|
-
"esbuild": "0.25.
|
|
28
|
-
"tsx": "4.
|
|
29
|
-
"typescript": "5.
|
|
30
|
-
"vitest": "3.
|
|
31
|
-
"@aws-sdk/client-ecr": "3.
|
|
32
|
-
"@kubernetes/client-node": "1.
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"h3": "1.15.3",
|
|
25
|
+
"@types/node": "24.5.2",
|
|
26
|
+
"@types/semver": "7.7.1",
|
|
27
|
+
"esbuild": "0.25.10",
|
|
28
|
+
"tsx": "4.20.5",
|
|
29
|
+
"typescript": "5.9.2",
|
|
30
|
+
"vitest": "3.2.4",
|
|
31
|
+
"@aws-sdk/client-ecr": "3.891.0",
|
|
32
|
+
"@kubernetes/client-node": "1.3.0",
|
|
33
|
+
"commander": "14.0.1",
|
|
34
|
+
"dockerode": "4.0.8",
|
|
35
|
+
"h3": "1.15.4",
|
|
37
36
|
"js-yaml": "4.1.0",
|
|
38
37
|
"jsonwebtoken": "9.0.2",
|
|
39
38
|
"jwk-to-pem": "2.0.7",
|
|
40
39
|
"open": "8.4.2",
|
|
41
40
|
"semver": "7.7.2",
|
|
42
41
|
"tslog": "4.9.3",
|
|
43
|
-
"eslint": "9.
|
|
42
|
+
"eslint": "9.35.0"
|
|
44
43
|
}
|
|
45
44
|
}
|
package/src/auth.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
|
|
1
2
|
|
|
2
3
|
import { toNodeListener, createApp, defineEventHandler, getQuery, sendError } from 'h3'
|
|
3
4
|
import jwt, { JwtPayload } from 'jsonwebtoken'
|
|
@@ -6,8 +7,6 @@ import { randomBytes, createHash } from 'node:crypto'
|
|
|
6
7
|
import { createServer } from 'node:http'
|
|
7
8
|
import open from 'open'
|
|
8
9
|
|
|
9
|
-
import { Configuration, OidcApi } from '@ory/client'
|
|
10
|
-
|
|
11
10
|
import { portalBaseUrl } from './config.js'
|
|
12
11
|
import { logger } from './logging.js'
|
|
13
12
|
import { setSecret, getSecret, removeSecret } from './secret_store.js'
|
|
@@ -23,11 +22,6 @@ const clientId = 'c16ea663-ced3-46c6-8f85-38c9681fe1f0'
|
|
|
23
22
|
const baseURL = 'https://auth.metaplay.dev'
|
|
24
23
|
const authorizationEndpoint = `${baseURL}/oauth2/auth`
|
|
25
24
|
const tokenEndpoint = `${baseURL}/oauth2/token`
|
|
26
|
-
const oidcApi = new OidcApi(
|
|
27
|
-
new Configuration({
|
|
28
|
-
basePath: baseURL,
|
|
29
|
-
})
|
|
30
|
-
)
|
|
31
25
|
|
|
32
26
|
/**
|
|
33
27
|
* A helper function which generates a code verifier and challenge for exchanging code from Ory server.
|
|
@@ -45,16 +39,9 @@ function generateCodeVerifierAndChallenge(): { verifier: string; challenge: stri
|
|
|
45
39
|
* @returns An object containing the user's info.
|
|
46
40
|
*/
|
|
47
41
|
export async function getUserinfo(token: string): Promise<any> {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const userinfoEndpoint = oidcRes.data?.userinfo_endpoint
|
|
52
|
-
if (!userinfoEndpoint) {
|
|
53
|
-
throw new Error('No userinfo endpoint found in OIDC configuration')
|
|
54
|
-
}
|
|
55
|
-
logger.debug(`Found userinfo endpoint: ${userinfoEndpoint}`)
|
|
56
|
-
|
|
57
|
-
const userinfoRes = await fetch(userinfoEndpoint, {
|
|
42
|
+
// To relieve pressure on Ory endpoints, get the userinfo directly from portal,
|
|
43
|
+
// instead of discovering OIDC endpoints from Ory first. Portal is where Ory would redirect the request anyway.
|
|
44
|
+
const userinfoRes = await fetch(`${portalBaseUrl}/api/external/userinfo`, {
|
|
58
45
|
headers: {
|
|
59
46
|
Authorization: `Bearer ${token}`,
|
|
60
47
|
},
|
|
@@ -201,8 +188,30 @@ export async function machineLoginAndSaveTokens(clientId: string, clientSecret:
|
|
|
201
188
|
body: params.toString(),
|
|
202
189
|
})
|
|
203
190
|
|
|
204
|
-
//
|
|
205
|
-
|
|
191
|
+
// Improved error handling for response
|
|
192
|
+
let tokens: { access_token: string; token_type: string; expires_in: number; scope: string }
|
|
193
|
+
if (!res.ok) {
|
|
194
|
+
let message: string | undefined = undefined
|
|
195
|
+
try {
|
|
196
|
+
const errorBody: any = await res.json()
|
|
197
|
+
message = errorBody && (errorBody.error_description || errorBody.error || errorBody.message)
|
|
198
|
+
} catch (_error) {
|
|
199
|
+
try {
|
|
200
|
+
message = await res.text()
|
|
201
|
+
} catch (_error) {
|
|
202
|
+
message = undefined
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
throw new Error(`Machine login failed: ${message || `HTTP ${res.status}`}`)
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
tokens = (await res.json()) as { access_token: string; token_type: string; expires_in: number; scope: string }
|
|
209
|
+
} catch (error) {
|
|
210
|
+
throw new Error(
|
|
211
|
+
"Invalid response from authentication server. Please check your network connection and credentials and try again.",
|
|
212
|
+
{ cause: error }
|
|
213
|
+
)
|
|
214
|
+
}
|
|
206
215
|
|
|
207
216
|
logger.debug('Received machine authentication tokens, saving them for future use...')
|
|
208
217
|
|
|
@@ -214,7 +223,29 @@ export async function machineLoginAndSaveTokens(clientId: string, clientSecret:
|
|
|
214
223
|
},
|
|
215
224
|
})
|
|
216
225
|
|
|
217
|
-
|
|
226
|
+
let userInfo: { given_name: string; family_name: string }
|
|
227
|
+
if (!userInfoResponse.ok) {
|
|
228
|
+
let message: string | undefined = undefined
|
|
229
|
+
try {
|
|
230
|
+
const errorBody: any = await userInfoResponse.json()
|
|
231
|
+
message = errorBody && (errorBody.error_description || errorBody.error || errorBody.message)
|
|
232
|
+
} catch (_error) {
|
|
233
|
+
try {
|
|
234
|
+
message = await userInfoResponse.text()
|
|
235
|
+
} catch (_error) {
|
|
236
|
+
message = undefined
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
throw new Error(`Failed to fetch user info: ${message || `HTTP ${userInfoResponse.status}`}`)
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
userInfo = (await userInfoResponse.json()) as { given_name: string; family_name: string }
|
|
243
|
+
} catch (error) {
|
|
244
|
+
throw new Error(
|
|
245
|
+
"Invalid response from user info endpoint. Please check your network connection and try again.",
|
|
246
|
+
{ cause: error }
|
|
247
|
+
)
|
|
248
|
+
}
|
|
218
249
|
|
|
219
250
|
console.log(
|
|
220
251
|
`You are now logged in with machine user ${userInfo.given_name} ${userInfo.family_name} (clientId=${clientId}) and can execute the other commands.`
|
|
@@ -267,7 +298,6 @@ export async function extendCurrentSession(): Promise<void> {
|
|
|
267
298
|
async function extendCurrentSessionWithRefreshToken(
|
|
268
299
|
refreshToken: string
|
|
269
300
|
): Promise<{ id_token: string; access_token: string; refresh_token: string }> {
|
|
270
|
-
// TODO: similar to the todo task in getTokensWithAuthorizationCode, http request can be handled by ory/client.
|
|
271
301
|
const params = new URLSearchParams({
|
|
272
302
|
grant_type: 'refresh_token',
|
|
273
303
|
refresh_token: refreshToken,
|
|
@@ -292,9 +322,12 @@ async function extendCurrentSessionWithRefreshToken(
|
|
|
292
322
|
logger.error(`Failed to refresh tokens via endpoint ${tokenEndpoint}`)
|
|
293
323
|
logger.error('Fetch error details:', error)
|
|
294
324
|
if (error.cause?.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
|
|
295
|
-
throw new Error(
|
|
325
|
+
throw new Error(
|
|
326
|
+
`Failed to refresh tokens: SSL certificate validation failed for ${tokenEndpoint}. Is someone trying to tamper with your internet connection?`,
|
|
327
|
+
{ cause: error }
|
|
328
|
+
)
|
|
296
329
|
}
|
|
297
|
-
throw new Error(`Failed to refresh tokens via ${tokenEndpoint}: ${error}
|
|
330
|
+
throw new Error(`Failed to refresh tokens via ${tokenEndpoint}: ${error}`, { cause: error })
|
|
298
331
|
}
|
|
299
332
|
|
|
300
333
|
// Check if the response is OK
|
|
@@ -329,7 +362,6 @@ async function getTokensWithAuthorizationCode(
|
|
|
329
362
|
verifier: string,
|
|
330
363
|
code: string
|
|
331
364
|
): Promise<{ id_token: string; access_token: string; refresh_token: string }> {
|
|
332
|
-
// TODO: the authorization code exchange flow might be better to be handled by ory/client, could check if there's any useful tools there.
|
|
333
365
|
try {
|
|
334
366
|
const response = await fetch(tokenEndpoint, {
|
|
335
367
|
method: 'POST',
|
|
@@ -363,7 +395,7 @@ export async function loadTokens(): Promise<TokenSet> {
|
|
|
363
395
|
return tokens
|
|
364
396
|
} catch (error) {
|
|
365
397
|
if (error instanceof Error) {
|
|
366
|
-
throw new Error(`Error loading tokens: ${error.message}
|
|
398
|
+
throw new Error(`Error loading tokens: ${error.message}`, { cause: error })
|
|
367
399
|
}
|
|
368
400
|
|
|
369
401
|
throw error
|
|
@@ -392,7 +424,7 @@ export async function saveTokens(tokens: Record<string, string>): Promise<void>
|
|
|
392
424
|
showTokenInfo(tokens.access_token)
|
|
393
425
|
} catch (error) {
|
|
394
426
|
if (error instanceof Error) {
|
|
395
|
-
throw new Error(`Failed to save tokens: ${error.message}
|
|
427
|
+
throw new Error(`Failed to save tokens: ${error.message}`, { cause: error })
|
|
396
428
|
}
|
|
397
429
|
|
|
398
430
|
throw error
|
|
@@ -408,7 +440,7 @@ export async function removeTokens(): Promise<void> {
|
|
|
408
440
|
logger.debug('Removed tokens.')
|
|
409
441
|
} catch (error) {
|
|
410
442
|
if (error instanceof Error) {
|
|
411
|
-
throw new Error(`Error removing tokens: ${error.message}
|
|
443
|
+
throw new Error(`Error removing tokens: ${error.message}`, { cause: error })
|
|
412
444
|
}
|
|
413
445
|
|
|
414
446
|
throw error
|
package/src/buildCommand.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
-
import { readFileSync, existsSync } from 'fs'
|
|
3
|
-
import path from 'path'
|
|
4
|
-
import { exit } from 'process'
|
|
2
|
+
import { readFileSync, existsSync } from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { exit } from 'node:process'
|
|
5
5
|
import * as semver from 'semver'
|
|
6
6
|
|
|
7
7
|
import { pathJoin, executeCommand, ExecuteCommandResult } from './utils.js'
|
package/src/deployment.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { unlink, writeFile } from 'fs/promises'
|
|
2
|
-
import os from 'os'
|
|
3
|
-
import path from 'path'
|
|
4
|
-
import { exit } from 'process'
|
|
1
|
+
import { unlink, writeFile } from 'node:fs/promises'
|
|
2
|
+
import os from 'node:os'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { exit } from 'node:process'
|
|
5
5
|
import { EnvironmentDetails, TargetEnvironment } from 'targetenvironment.js'
|
|
6
|
-
import { promises as dns } from 'dns'
|
|
7
|
-
import tls from 'tls'
|
|
6
|
+
import { promises as dns } from 'node:dns'
|
|
7
|
+
import tls from 'node:tls'
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
KubeConfig,
|
|
@@ -48,7 +48,7 @@ async function fetchGameServerPods(k8sApi: CoreV1Api, namespace: string): Promis
|
|
|
48
48
|
} catch (error) {
|
|
49
49
|
// \todo Better error handling ..
|
|
50
50
|
console.error('Failed to fetch pods from Kubernetes:', error)
|
|
51
|
-
throw new Error('Failed to fetch pods from Kubernetes')
|
|
51
|
+
throw new Error('Failed to fetch pods from Kubernetes', { cause: error })
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -337,7 +337,7 @@ async function fetchPodLogs(k8sApi: CoreV1Api, pod: V1Pod): Promise<string> {
|
|
|
337
337
|
} catch (error) {
|
|
338
338
|
// \todo Better error handling ..
|
|
339
339
|
console.log('Failed to fetch pod logs from Kubernetes:', error)
|
|
340
|
-
throw new Error('Failed to fetch pod logs from Kubernetes')
|
|
340
|
+
throw new Error('Failed to fetch pod logs from Kubernetes', { cause: error })
|
|
341
341
|
}
|
|
342
342
|
}
|
|
343
343
|
|
|
@@ -457,7 +457,7 @@ async function waitForDomainResolution(hostname: string): Promise<void> {
|
|
|
457
457
|
return
|
|
458
458
|
} catch (err) {
|
|
459
459
|
if (Date.now() > timeoutAt) {
|
|
460
|
-
throw new Error(`Could not resolve domain ${hostname} before timeout
|
|
460
|
+
throw new Error(`Could not resolve domain ${hostname} before timeout.`, { cause: err })
|
|
461
461
|
}
|
|
462
462
|
|
|
463
463
|
if (err instanceof Error && (err as NodeJS.ErrnoException).code === 'ENOTFOUND') {
|
package/src/secret_store.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { randomBytes, createCipheriv, createDecipheriv, scryptSync } from 'crypto'
|
|
2
|
-
import { promises as fs } from 'fs'
|
|
3
|
-
import { homedir } from 'os'
|
|
4
|
-
import { join } from 'path'
|
|
1
|
+
import { randomBytes, createCipheriv, createDecipheriv, scryptSync } from 'node:crypto'
|
|
2
|
+
import { promises as fs } from 'node:fs'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
5
|
|
|
6
6
|
import { logger } from './logging.js'
|
|
7
7
|
|
|
@@ -36,7 +36,7 @@ async function loadSecrets(): Promise<Secrets> {
|
|
|
36
36
|
return {}
|
|
37
37
|
}
|
|
38
38
|
if (password.length === 0) {
|
|
39
|
-
throw new Error('The file is encrypted. Please set the METAPLAY_AUTH_PASSWORD environment variable.')
|
|
39
|
+
throw new Error('The file is encrypted. Please set the METAPLAY_AUTH_PASSWORD environment variable.', { cause: error })
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
throw error
|
package/src/targetenvironment.ts
CHANGED
|
@@ -133,9 +133,9 @@ export class TargetEnvironment {
|
|
|
133
133
|
} catch (error: any) {
|
|
134
134
|
logger.error(`Failed to fetch ${method} ${url}:`, error)
|
|
135
135
|
if (error.cause?.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
|
|
136
|
-
throw new Error(`Failed to to fetch ${url}: SSL certificate validation failed. Is someone trying to tamper with your internet connection
|
|
136
|
+
throw new Error(`Failed to to fetch ${url}: SSL certificate validation failed. Is someone trying to tamper with your internet connection?`, { cause: error })
|
|
137
137
|
}
|
|
138
|
-
throw new Error(`Failed to fetch ${url}: ${error}
|
|
138
|
+
throw new Error(`Failed to fetch ${url}: ${error}`, { cause: error })
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
if (response.status !== 200) {
|
|
@@ -183,13 +183,13 @@ export class TargetEnvironment {
|
|
|
183
183
|
// User-friendly error messages for well-known HTTP errors.
|
|
184
184
|
if (error instanceof FetchJsonHttpError) {
|
|
185
185
|
if (error.response.status === 404) {
|
|
186
|
-
throw new Error(`Environment ${this.humanId} does not exist
|
|
186
|
+
throw new Error(`Environment ${this.humanId} does not exist.`, { cause: error })
|
|
187
187
|
} else if (error.response.status === 403) {
|
|
188
|
-
throw new Error(`Your account does not have permissions to access environment ${this.humanId}
|
|
188
|
+
throw new Error(`Your account does not have permissions to access environment ${this.humanId}.`, { cause: error })
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
const errorMessage = (error instanceof Error) ? error.message : String(error)
|
|
192
|
-
throw new Error(`Failed to fetch Kubernetes KubeConfig: ${errorMessage}
|
|
192
|
+
throw new Error(`Failed to fetch Kubernetes KubeConfig: ${errorMessage}`, { cause: error })
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
if (!kubeExecCredential.spec.cluster) {
|
package/src/utils.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { spawn } from 'child_process'
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
2
|
import yaml from 'js-yaml'
|
|
3
|
-
import path from 'path'
|
|
3
|
+
import path from 'node:path'
|
|
4
4
|
import * as semver from 'semver'
|
|
5
5
|
|
|
6
6
|
import { logger } from './logging.js'
|
|
7
|
-
import { tmpdir } from 'os'
|
|
8
|
-
import { randomBytes } from 'crypto'
|
|
9
|
-
import { unlink, writeFile } from 'fs/promises'
|
|
7
|
+
import { tmpdir } from 'node:os'
|
|
8
|
+
import { randomBytes } from 'node:crypto'
|
|
9
|
+
import { unlink, writeFile } from 'node:fs/promises'
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Checks if the given string is a fully qualified domain name (FQDN).
|
|
@@ -44,9 +44,9 @@ export function splitUrlComponents(urlString: string): {
|
|
|
44
44
|
const subpaths = url.pathname.slice(1) ?? null
|
|
45
45
|
|
|
46
46
|
return { scheme, hostname, port, subpaths }
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
} catch (error) {
|
|
49
|
-
throw new Error('Invalid URL')
|
|
49
|
+
throw new Error('Invalid URL', { cause: error })
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -266,7 +266,7 @@ export async function checkHelmVersion(): Promise<void> {
|
|
|
266
266
|
logger.debug(`Helm version ${helmVersion} is compatible`)
|
|
267
267
|
} catch (error) {
|
|
268
268
|
if (error instanceof Error && error.message.includes('ENOENT')) {
|
|
269
|
-
throw new Error('Helm is not installed or not found in PATH. Please install Helm version >= 3.18.0 and < 3.18.5')
|
|
269
|
+
throw new Error('Helm is not installed or not found in PATH. Please install Helm version >= 3.18.0 and < 3.18.5', { cause: error })
|
|
270
270
|
}
|
|
271
271
|
throw error
|
|
272
272
|
}
|
|
@@ -293,7 +293,7 @@ export async function executeHelmCommand(kubeconfigPayload: string, args: string
|
|
|
293
293
|
// \todo output something from Helm result?
|
|
294
294
|
} catch (error) {
|
|
295
295
|
const errMessage = error instanceof Error ? error.message : String(error)
|
|
296
|
-
throw new Error(`Failed to execute 'helm': ${errMessage}. You need to have Helm v3 installed to deploy a game server with metaplay-auth
|
|
296
|
+
throw new Error(`Failed to execute 'helm': ${errMessage}. You need to have Helm v3 installed to deploy a game server with metaplay-auth.`, { cause: error })
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
// Throw on Helm non-success exit code
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = "1.9.
|
|
1
|
+
export const PACKAGE_VERSION = "1.9.3"
|
|
Binary file
|