@metaplay/metaplay-auth 1.4.2 → 1.6.0
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/.prettierignore +2 -0
- package/CHANGELOG.md +69 -28
- package/dist/index.cjs +292 -0
- package/dist/sshcrypto-OMBCGRSN.node +0 -0
- package/eslint.config.js +3 -0
- package/index.ts +763 -437
- package/package.json +22 -21
- package/prettier.config.js +3 -0
- package/src/auth.ts +121 -80
- package/src/buildCommand.ts +267 -0
- package/src/config.ts +12 -0
- package/src/deployment.ts +285 -52
- package/src/logging.ts +4 -4
- package/src/secret_store.ts +10 -7
- package/src/stackapi.ts +5 -381
- package/src/targetenvironment.ts +311 -0
- package/src/utils.ts +162 -31
- package/src/version.ts +1 -0
- package/dist/index.js +0 -644
- package/dist/index.js.map +0 -1
- package/dist/src/auth.js +0 -373
- package/dist/src/auth.js.map +0 -1
- package/dist/src/deployment.js +0 -250
- package/dist/src/deployment.js.map +0 -1
- package/dist/src/logging.js +0 -18
- package/dist/src/logging.js.map +0 -1
- package/dist/src/secret_store.js +0 -79
- package/dist/src/secret_store.js.map +0 -1
- package/dist/src/stackapi.js +0 -302
- package/dist/src/stackapi.js.map +0 -1
- package/dist/src/utils.js +0 -62
- package/dist/src/utils.js.map +0 -1
- package/dist/tests/utils.spec.js +0 -18
- package/dist/tests/utils.spec.js.map +0 -1
- package/tests/utils.spec.ts +0 -20
- package/vitest.config.ts +0 -7
package/src/utils.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { spawn } from 'child_process'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { logger } from './logging.js'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import yaml from 'js-yaml'
|
|
5
|
+
import * as semver from 'semver'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Checks if the given string is a fully qualified domain name (FQDN).
|
|
@@ -10,7 +10,7 @@ export function stackApiBaseFromOptions (arg: string, options: Record<string, an
|
|
|
10
10
|
* @param domain The domain name to check.
|
|
11
11
|
* @returns true if the domain is a valid FQDN, false otherwise.
|
|
12
12
|
*/
|
|
13
|
-
export function isValidFQDN
|
|
13
|
+
export function isValidFQDN(domain: string): boolean {
|
|
14
14
|
const fqdnRegex = /^(?=.{1,253}$)(([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,})$/
|
|
15
15
|
|
|
16
16
|
return fqdnRegex.test(domain)
|
|
@@ -22,7 +22,12 @@ export function isValidFQDN (domain: string): boolean {
|
|
|
22
22
|
* @param urlString The HTTP URL string to be split.
|
|
23
23
|
* @returns An object containing the scheme, hostname, port, and subpaths.
|
|
24
24
|
*/
|
|
25
|
-
export function splitUrlComponents
|
|
25
|
+
export function splitUrlComponents(urlString: string): {
|
|
26
|
+
scheme: string
|
|
27
|
+
hostname: string
|
|
28
|
+
port: string | null
|
|
29
|
+
subpaths: string | null
|
|
30
|
+
} {
|
|
26
31
|
try {
|
|
27
32
|
const url = new URL(urlString)
|
|
28
33
|
|
|
@@ -35,51 +40,177 @@ export function splitUrlComponents (urlString: string): { scheme: string, hostna
|
|
|
35
40
|
const subpaths = url.pathname.slice(1) ?? null
|
|
36
41
|
|
|
37
42
|
return { scheme, hostname, port, subpaths }
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
38
44
|
} catch (error) {
|
|
39
45
|
throw new Error('Invalid URL')
|
|
40
46
|
}
|
|
41
47
|
}
|
|
42
48
|
|
|
43
|
-
export
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const hostname = parts[0]
|
|
47
|
-
const domain = uri.substring(hostname.length + 1)
|
|
48
|
-
|
|
49
|
-
return `${hostname}-admin.${domain}`
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
interface CommandResult {
|
|
53
|
-
code: number | null
|
|
49
|
+
export interface ExecuteCommandResult {
|
|
50
|
+
exitCode: number | null
|
|
54
51
|
stdout: any[]
|
|
55
52
|
stderr: any[]
|
|
56
53
|
}
|
|
57
54
|
|
|
58
|
-
export
|
|
55
|
+
export interface ExecuteCommandOptions {
|
|
56
|
+
/**
|
|
57
|
+
* Should the stdin/stdout/stderr be inherited from the parent process? If false, the outputs are buffered for reading later.
|
|
58
|
+
*/
|
|
59
|
+
inheritStdio?: boolean
|
|
60
|
+
/**
|
|
61
|
+
* Environment variables to pass in. Does not inherit parent process env. Use current process env if not specified.
|
|
62
|
+
*/
|
|
63
|
+
env?: NodeJS.ProcessEnv
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Run a child process and return an awaitable Promise.
|
|
68
|
+
*
|
|
69
|
+
* @param command Name of the command/binary to execute.
|
|
70
|
+
* @param args List of arguments to pass to the child process.
|
|
71
|
+
* @returns Awaitable promise with the result of the execution.
|
|
72
|
+
*/
|
|
73
|
+
export async function executeCommand(
|
|
74
|
+
command: string,
|
|
75
|
+
args: string[],
|
|
76
|
+
options?: { inheritStdio?: boolean; env?: NodeJS.ProcessEnv }
|
|
77
|
+
): Promise<ExecuteCommandResult> {
|
|
59
78
|
return await new Promise((resolve, reject) => {
|
|
60
|
-
const childProcess = spawn(command, args
|
|
61
|
-
|
|
62
|
-
|
|
79
|
+
const childProcess = spawn(command, args, {
|
|
80
|
+
stdio: options?.inheritStdio ? 'inherit' : undefined,
|
|
81
|
+
env: options?.env,
|
|
82
|
+
})
|
|
83
|
+
const stdout: string[] = []
|
|
84
|
+
const stderr: string[] = []
|
|
63
85
|
|
|
64
|
-
childProcess.stdout?.on('data', (data) => {
|
|
65
|
-
stdout
|
|
86
|
+
childProcess.stdout?.on('data', (data: string) => {
|
|
87
|
+
stdout.push(data)
|
|
66
88
|
})
|
|
67
89
|
|
|
68
|
-
childProcess.stderr?.on('data', (data) => {
|
|
69
|
-
stderr
|
|
90
|
+
childProcess.stderr?.on('data', (data: string) => {
|
|
91
|
+
stderr.push(data)
|
|
70
92
|
})
|
|
71
93
|
|
|
72
94
|
// If program runs to completion, resolve promise with success
|
|
73
95
|
childProcess.on('close', (code) => {
|
|
74
|
-
resolve({ code, stdout, stderr })
|
|
96
|
+
resolve({ exitCode: code, stdout, stderr })
|
|
75
97
|
})
|
|
76
98
|
|
|
77
99
|
childProcess.on('error', (err) => {
|
|
78
|
-
reject(
|
|
79
|
-
new Error(
|
|
80
|
-
`Failed to execute command '${command} ${args.join(' ')}': ${err.message}`
|
|
81
|
-
)
|
|
82
|
-
)
|
|
100
|
+
reject(new Error(`Failed to execute command '${command} ${args.join(' ')}': ${err.message}`))
|
|
83
101
|
})
|
|
84
102
|
})
|
|
85
103
|
}
|
|
104
|
+
|
|
105
|
+
export function isRunningUnderNpx(): boolean {
|
|
106
|
+
// console.log('process.argv:', process.argv)
|
|
107
|
+
const matchBinary = (binaryPath: string, binaryName: string): boolean => {
|
|
108
|
+
const binary = path.basename(binaryPath, path.extname(binaryPath)) // drop path and extension
|
|
109
|
+
return binary === binaryName
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check if 'npx' is the invoked binary (this check is not sufficient as it can also be 'node')
|
|
113
|
+
if (matchBinary(process.argv[0], 'npx')) {
|
|
114
|
+
return true
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Check if the script path contains a known npx temporary directory pattern
|
|
118
|
+
const scriptPath = process.argv[1]
|
|
119
|
+
if (scriptPath?.includes(`${path.sep}_npx${path.sep}`)) {
|
|
120
|
+
return true
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Check if the environment variable 'npm_execpath' is exactly 'npx'
|
|
124
|
+
if (process.env.npm_execpath && matchBinary(process.env.npm_execpath, 'npx')) {
|
|
125
|
+
return true
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Check if the environment variable '_' ends with 'npx' (specific to npx usage)
|
|
129
|
+
if (process.env._ && matchBinary(process.env._, 'npx')) {
|
|
130
|
+
return true
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return false
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Join a set of path segments and return result with Unix path separators ('/').
|
|
138
|
+
* @param paths Individual path segments to join
|
|
139
|
+
* @returns Joined path
|
|
140
|
+
*/
|
|
141
|
+
export function pathJoin(...paths: string[]): string {
|
|
142
|
+
return path.join(...paths).replaceAll('\\', '/')
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Remove a trailing slash from a URL.
|
|
147
|
+
* @param url URL to remove the trailing slash from.
|
|
148
|
+
* @returns URL without a trailing slash.
|
|
149
|
+
*/
|
|
150
|
+
export function removeTrailingSlash(url: string): string {
|
|
151
|
+
return url.replace(/\/+$/, '')
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Entry in the Helm chart repository index.
|
|
156
|
+
*/
|
|
157
|
+
interface HelmChartEntry {
|
|
158
|
+
name: string
|
|
159
|
+
version: string
|
|
160
|
+
description?: string
|
|
161
|
+
apiVersion?: string
|
|
162
|
+
appVersion?: string
|
|
163
|
+
urls: string[]
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The index of the Helm chart repository. Contains an entry for each of published chart version.
|
|
168
|
+
*/
|
|
169
|
+
interface HelmChartRepoIndex {
|
|
170
|
+
apiVersion: string
|
|
171
|
+
entries: Record<string, HelmChartEntry[]>
|
|
172
|
+
generated: string
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Fetch the available versions of a specific Helm chart from a repository.
|
|
177
|
+
* @param repository URL of the Helm chart repository. No trailing slash allowed.
|
|
178
|
+
* @param chartName Name of the Helm chart.
|
|
179
|
+
* @returns List of available Helm chart versions.
|
|
180
|
+
*/
|
|
181
|
+
export async function fetchHelmChartVersions(repository: string, chartName: string): Promise<string[]> {
|
|
182
|
+
// Fetch the index.yaml file from the repository
|
|
183
|
+
logger.debug(`Fetching Helm chart versions from '${repository}'...`)
|
|
184
|
+
const response: Response = await fetch(`${repository}/index.yaml`)
|
|
185
|
+
const indexYaml: string = await response.text()
|
|
186
|
+
|
|
187
|
+
// Parse the YAML index file
|
|
188
|
+
const repoIndex: HelmChartRepoIndex = yaml.load(indexYaml) as HelmChartRepoIndex
|
|
189
|
+
|
|
190
|
+
// Grab all versions >= 0.5.0 -- older are considered legacy
|
|
191
|
+
const chartVersions = repoIndex.entries[chartName]
|
|
192
|
+
.map((entry) => entry.version)
|
|
193
|
+
.filter((version) => semver.gte(version, '0.5.0'))
|
|
194
|
+
return chartVersions
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Resolve the best matching version from a list of versions that satisfy a semver range.
|
|
199
|
+
* @param versions List of versions to resolve from.
|
|
200
|
+
* @param range Semver range to satisfy.
|
|
201
|
+
* @returns The best (latest) matching version or null if no versions satisfy the range.
|
|
202
|
+
*/
|
|
203
|
+
export function resolveBestMatchingVersion(versions: string[], range: semver.Range | null): string | null {
|
|
204
|
+
// Filter versions that satisfy the range -- range==null means 'latest' == include all versions
|
|
205
|
+
const satisfyingVersions = range ? versions.filter((version) => semver.satisfies(version, range)) : versions
|
|
206
|
+
logger.debug(`Satisfying versions: ${satisfyingVersions.join(', ')}`)
|
|
207
|
+
|
|
208
|
+
// If no versions satisfy the range, return null
|
|
209
|
+
if (satisfyingVersions.length === 0) {
|
|
210
|
+
return null
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Sort the versions to get the highest one that matches the range
|
|
214
|
+
const sortedVersions = satisfyingVersions.sort(semver.rcompare)
|
|
215
|
+
return sortedVersions[0]
|
|
216
|
+
}
|
package/src/version.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const PACKAGE_VERSION = "1.6.0"
|