transloadit 4.8.0 → 4.8.1
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/README.md +51 -3
- package/dist/bearerToken.d.ts +1 -0
- package/dist/bearerToken.d.ts.map +1 -1
- package/dist/bearerToken.js +5 -3
- package/dist/bearerToken.js.map +1 -1
- package/dist/cli/commands/BaseCommand.d.ts +0 -1
- package/dist/cli/commands/BaseCommand.d.ts.map +1 -1
- package/dist/cli/commands/BaseCommand.js +7 -9
- package/dist/cli/commands/BaseCommand.js.map +1 -1
- package/dist/cli/commands/auth.d.ts.map +1 -1
- package/dist/cli/commands/auth.js +49 -29
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/generateIntentDocs.d.ts.map +1 -1
- package/dist/cli/generateIntentDocs.js +2 -0
- package/dist/cli/generateIntentDocs.js.map +1 -1
- package/dist/cli/helpers.d.ts +19 -4
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/helpers.js +232 -10
- package/dist/cli/helpers.js.map +1 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/src/bearerToken.ts +14 -3
- package/src/cli/commands/BaseCommand.ts +7 -9
- package/src/cli/commands/auth.ts +66 -32
- package/src/cli/generateIntentDocs.ts +2 -0
- package/src/cli/helpers.ts +278 -13
- package/src/cli.ts +3 -2
package/src/cli/helpers.ts
CHANGED
|
@@ -1,30 +1,295 @@
|
|
|
1
1
|
import fs from 'node:fs'
|
|
2
2
|
import fsp from 'node:fs/promises'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
import path from 'node:path'
|
|
3
5
|
import type { Readable } from 'node:stream'
|
|
6
|
+
import { parse as parseDotenv } from 'dotenv'
|
|
4
7
|
import { isAPIError } from './types.ts'
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
export type CliKeySecretCredentials = { authKey: string; authSecret: string }
|
|
10
|
+
export type CliAuthToken = { authToken: string }
|
|
11
|
+
export type CliAuth = CliKeySecretCredentials | CliAuthToken
|
|
12
|
+
type CliEnvSource = {
|
|
13
|
+
name: 'env' | 'credentialsFile'
|
|
14
|
+
values: Record<string, string | undefined>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let loadedProjectDotenvPath: string | undefined
|
|
18
|
+
let projectDotenvInjectedValues: Record<string, string> | undefined
|
|
19
|
+
let projectDotenvPreviousValues: Record<string, string | undefined> | undefined
|
|
20
|
+
let shellEnvBeforeProjectDotenv: Record<string, string | undefined> | undefined
|
|
21
|
+
|
|
22
|
+
type LoadCliEnvSourcesResult = {
|
|
23
|
+
loadError?: string
|
|
24
|
+
shellEnvSource: CliEnvSource
|
|
25
|
+
sources: CliEnvSource[]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type ResolvedCliConfig = {
|
|
29
|
+
auth?: CliAuth
|
|
30
|
+
credentials?: CliKeySecretCredentials
|
|
31
|
+
credentialsEndpoint?: string
|
|
32
|
+
endpoint?: string
|
|
33
|
+
loadError?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function normalizeEnvValue(value: string | undefined): string | undefined {
|
|
37
|
+
const trimmed = value?.trim()
|
|
38
|
+
return trimmed ? trimmed : undefined
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getConfiguredCredentialsFilePath(): string {
|
|
42
|
+
const configuredPath = normalizeEnvValue(process.env.TRANSLOADIT_CREDENTIALS_FILE)
|
|
43
|
+
if (configuredPath != null) {
|
|
44
|
+
return path.resolve(configuredPath)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return path.join(homedir(), '.transloadit', 'credentials')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getProjectDotenvPath(): string {
|
|
51
|
+
return path.resolve(process.cwd(), '.env')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getDisplayPath(filePath: string): string {
|
|
55
|
+
const normalizedHome = path.resolve(homedir())
|
|
56
|
+
const normalizedFilePath = path.resolve(filePath)
|
|
57
|
+
if (normalizedFilePath === normalizedHome) return '~'
|
|
58
|
+
if (normalizedFilePath.startsWith(`${normalizedHome}${path.sep}`)) {
|
|
59
|
+
return `~${normalizedFilePath.slice(normalizedHome.length)}`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return normalizedFilePath
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function buildMissingCredentialsMessage(): string {
|
|
66
|
+
return [
|
|
67
|
+
'Missing credentials.',
|
|
68
|
+
'',
|
|
69
|
+
'Looked for TRANSLOADIT_KEY + TRANSLOADIT_SECRET in this order:',
|
|
70
|
+
'1. Shell env: TRANSLOADIT_KEY / TRANSLOADIT_SECRET',
|
|
71
|
+
`2. Current directory .env: ${getProjectDotenvPath()}`,
|
|
72
|
+
`3. Credentials file: ${getDisplayPath(getConfiguredCredentialsFilePath())}`,
|
|
73
|
+
].join('\n')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function buildMissingAuthMessage(): string {
|
|
77
|
+
return [
|
|
78
|
+
'Missing authentication.',
|
|
79
|
+
'',
|
|
80
|
+
'Looked for TRANSLOADIT_AUTH_TOKEN or TRANSLOADIT_KEY + TRANSLOADIT_SECRET in this order:',
|
|
81
|
+
'1. Shell env: TRANSLOADIT_AUTH_TOKEN, or TRANSLOADIT_KEY / TRANSLOADIT_SECRET',
|
|
82
|
+
`2. Current directory .env: ${getProjectDotenvPath()}`,
|
|
83
|
+
`3. Credentials file: ${getDisplayPath(getConfiguredCredentialsFilePath())}`,
|
|
84
|
+
].join('\n')
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function readEnvFile(
|
|
88
|
+
filePath: string,
|
|
89
|
+
): { ok: true; source: CliEnvSource } | { ok: false; error: string } | null {
|
|
90
|
+
if (!fs.existsSync(filePath)) return null
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
return {
|
|
94
|
+
ok: true,
|
|
95
|
+
source: {
|
|
96
|
+
name: 'credentialsFile',
|
|
97
|
+
values: parseDotenv(fs.readFileSync(filePath)),
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
} catch (err) {
|
|
101
|
+
if (!(err instanceof Error)) {
|
|
102
|
+
throw new Error(`Was thrown a non-error: ${err}`)
|
|
103
|
+
}
|
|
104
|
+
return { ok: false, error: `Failed to read ${filePath}: ${err.message}` }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function loadProjectDotenvIntoProcessEnv(): string | undefined {
|
|
109
|
+
const projectDotenvPath = getProjectDotenvPath()
|
|
110
|
+
if (loadedProjectDotenvPath !== projectDotenvPath) {
|
|
111
|
+
restoreProjectDotenvFromProcessEnv()
|
|
112
|
+
shellEnvBeforeProjectDotenv = { ...process.env }
|
|
113
|
+
loadedProjectDotenvPath = projectDotenvPath
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const projectDotenvResult = readEnvFile(projectDotenvPath)
|
|
117
|
+
if (projectDotenvResult == null) {
|
|
118
|
+
restoreProjectDotenvFromProcessEnv()
|
|
119
|
+
projectDotenvInjectedValues = undefined
|
|
120
|
+
projectDotenvPreviousValues = undefined
|
|
121
|
+
return undefined
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!projectDotenvResult.ok) return projectDotenvResult.error
|
|
125
|
+
if (projectDotenvInjectedValues != null) return undefined
|
|
126
|
+
|
|
127
|
+
const previousValues: Record<string, string | undefined> = {}
|
|
128
|
+
const injectedValues: Record<string, string> = {}
|
|
129
|
+
for (const [key, value] of Object.entries(projectDotenvResult.source.values)) {
|
|
130
|
+
if (value == null) continue
|
|
131
|
+
if (normalizeEnvValue(process.env[key]) != null) continue
|
|
132
|
+
previousValues[key] = process.env[key]
|
|
133
|
+
process.env[key] = value
|
|
134
|
+
injectedValues[key] = value
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
projectDotenvPreviousValues = previousValues
|
|
138
|
+
projectDotenvInjectedValues = injectedValues
|
|
139
|
+
return undefined
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function getShellEnvValues(): Record<string, string | undefined> {
|
|
143
|
+
if (loadedProjectDotenvPath === getProjectDotenvPath() && shellEnvBeforeProjectDotenv != null) {
|
|
144
|
+
return shellEnvBeforeProjectDotenv
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return { ...process.env }
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function restoreProjectDotenvFromProcessEnv(): void {
|
|
151
|
+
if (projectDotenvInjectedValues == null || projectDotenvPreviousValues == null) return
|
|
152
|
+
|
|
153
|
+
for (const [key, injectedValue] of Object.entries(projectDotenvInjectedValues)) {
|
|
154
|
+
if (process.env[key] !== injectedValue) continue
|
|
155
|
+
|
|
156
|
+
const previousValue = projectDotenvPreviousValues[key]
|
|
157
|
+
if (previousValue == null) {
|
|
158
|
+
delete process.env[key]
|
|
159
|
+
continue
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
process.env[key] = previousValue
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
projectDotenvInjectedValues = undefined
|
|
166
|
+
projectDotenvPreviousValues = undefined
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function loadCliEnvSources(): LoadCliEnvSourcesResult {
|
|
170
|
+
const shellEnvSource: CliEnvSource = {
|
|
171
|
+
name: 'env',
|
|
172
|
+
values: getShellEnvValues(),
|
|
173
|
+
}
|
|
174
|
+
const loadErrors: string[] = []
|
|
175
|
+
|
|
176
|
+
const projectDotenvLoadError = loadProjectDotenvIntoProcessEnv()
|
|
177
|
+
if (projectDotenvLoadError != null) {
|
|
178
|
+
loadErrors.push(projectDotenvLoadError)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const sources: CliEnvSource[] = [
|
|
182
|
+
{
|
|
183
|
+
name: 'env',
|
|
184
|
+
values: { ...process.env },
|
|
185
|
+
},
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
const credentialsFilePath = getConfiguredCredentialsFilePath()
|
|
189
|
+
const credentialsFileResult = readEnvFile(credentialsFilePath)
|
|
190
|
+
if (credentialsFileResult?.ok === true) {
|
|
191
|
+
sources.push(credentialsFileResult.source)
|
|
192
|
+
} else if (credentialsFileResult?.ok === false) {
|
|
193
|
+
loadErrors.push(credentialsFileResult.error)
|
|
194
|
+
} else if (normalizeEnvValue(process.env.TRANSLOADIT_CREDENTIALS_FILE) != null) {
|
|
195
|
+
loadErrors.push(`Configured credentials file does not exist: ${credentialsFilePath}`)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
shellEnvSource,
|
|
200
|
+
sources,
|
|
201
|
+
...(loadErrors[0] ? { loadError: loadErrors[0] } : {}),
|
|
202
|
+
}
|
|
203
|
+
}
|
|
8
204
|
|
|
9
|
-
|
|
205
|
+
function getSourceValue(source: CliEnvSource, keys: string[]): string | undefined {
|
|
206
|
+
for (const key of keys) {
|
|
207
|
+
const value = normalizeEnvValue(source.values[key])
|
|
208
|
+
if (value != null) return value
|
|
209
|
+
}
|
|
10
210
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const authSecret = process.env.TRANSLOADIT_SECRET ?? process.env.TRANSLOADIT_AUTH_SECRET
|
|
211
|
+
return undefined
|
|
212
|
+
}
|
|
14
213
|
|
|
15
|
-
|
|
214
|
+
function getSourceCredentials(source: CliEnvSource): CliKeySecretCredentials | undefined {
|
|
215
|
+
const authKey = getSourceValue(source, ['TRANSLOADIT_KEY', 'TRANSLOADIT_AUTH_KEY'])
|
|
216
|
+
const authSecret = getSourceValue(source, ['TRANSLOADIT_SECRET', 'TRANSLOADIT_AUTH_SECRET'])
|
|
217
|
+
if (authKey == null || authSecret == null) return undefined
|
|
16
218
|
|
|
17
219
|
return { authKey, authSecret }
|
|
18
220
|
}
|
|
19
221
|
|
|
20
|
-
|
|
21
|
-
|
|
222
|
+
function getSourceAuthToken(source: CliEnvSource): CliAuthToken | undefined {
|
|
223
|
+
const authToken = getSourceValue(source, ['TRANSLOADIT_AUTH_TOKEN'])
|
|
224
|
+
if (authToken == null) return undefined
|
|
225
|
+
|
|
226
|
+
return { authToken }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function resolveEndpointForSource(
|
|
230
|
+
source: CliEnvSource | undefined,
|
|
231
|
+
shellEnvSource: CliEnvSource,
|
|
232
|
+
): string | undefined {
|
|
233
|
+
const shellEndpoint = getSourceValue(shellEnvSource, ['TRANSLOADIT_ENDPOINT'])
|
|
234
|
+
if (shellEndpoint != null) return shellEndpoint
|
|
235
|
+
if (source == null) return undefined
|
|
236
|
+
|
|
237
|
+
return getSourceValue(source, ['TRANSLOADIT_ENDPOINT'])
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function resolveCliConfig(): ResolvedCliConfig {
|
|
241
|
+
const { loadError, shellEnvSource, sources } = loadCliEnvSources()
|
|
242
|
+
let auth: CliAuth | undefined
|
|
243
|
+
let authSource: CliEnvSource | undefined
|
|
244
|
+
let credentials: CliKeySecretCredentials | undefined
|
|
245
|
+
let credentialsSource: CliEnvSource | undefined
|
|
246
|
+
|
|
247
|
+
for (const source of sources) {
|
|
248
|
+
if (auth == null) {
|
|
249
|
+
const authToken = getSourceAuthToken(source)
|
|
250
|
+
if (authToken != null) {
|
|
251
|
+
auth = authToken
|
|
252
|
+
authSource = source
|
|
253
|
+
} else {
|
|
254
|
+
const sourceCredentials = getSourceCredentials(source)
|
|
255
|
+
if (sourceCredentials != null) {
|
|
256
|
+
auth = sourceCredentials
|
|
257
|
+
authSource = source
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (credentials != null) continue
|
|
263
|
+
|
|
264
|
+
const sourceCredentials = getSourceCredentials(source)
|
|
265
|
+
if (sourceCredentials != null) {
|
|
266
|
+
credentials = sourceCredentials
|
|
267
|
+
credentialsSource = source
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
...(auth != null ? { auth } : {}),
|
|
273
|
+
...(credentials != null ? { credentials } : {}),
|
|
274
|
+
...(authSource != null
|
|
275
|
+
? { endpoint: resolveEndpointForSource(authSource, shellEnvSource) }
|
|
276
|
+
: {}),
|
|
277
|
+
...(credentialsSource != null
|
|
278
|
+
? { credentialsEndpoint: resolveEndpointForSource(credentialsSource, shellEnvSource) }
|
|
279
|
+
: {}),
|
|
280
|
+
...(loadError != null ? { loadError } : {}),
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
type RequireCliCredentialsResult =
|
|
285
|
+
| { ok: true; credentials: CliKeySecretCredentials }
|
|
22
286
|
| { ok: false; error: string }
|
|
23
287
|
|
|
24
|
-
export function
|
|
25
|
-
const credentials =
|
|
26
|
-
if (credentials
|
|
27
|
-
return { ok:
|
|
288
|
+
export function requireCliCredentials(): RequireCliCredentialsResult {
|
|
289
|
+
const { credentials, loadError } = resolveCliConfig()
|
|
290
|
+
if (credentials != null) return { ok: true, credentials }
|
|
291
|
+
if (loadError != null) return { ok: false, error: loadError }
|
|
292
|
+
return { ok: false, error: buildMissingCredentialsMessage() }
|
|
28
293
|
}
|
|
29
294
|
|
|
30
295
|
export function createReadStream(file: string): Readable {
|
package/src/cli.ts
CHANGED
|
@@ -4,8 +4,7 @@ import { realpathSync } from 'node:fs'
|
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import process from 'node:process'
|
|
6
6
|
import { fileURLToPath } from 'node:url'
|
|
7
|
-
import '
|
|
8
|
-
import { createCli } from './cli/commands/index.ts'
|
|
7
|
+
import { loadProjectDotenvIntoProcessEnv } from './cli/helpers.ts'
|
|
9
8
|
import { ensureError } from './cli/types.ts'
|
|
10
9
|
|
|
11
10
|
const currentFile = realpathSync(fileURLToPath(import.meta.url))
|
|
@@ -26,6 +25,8 @@ export function shouldRunCli(invoked?: string): boolean {
|
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
export async function main(args = process.argv.slice(2)): Promise<void> {
|
|
28
|
+
loadProjectDotenvIntoProcessEnv()
|
|
29
|
+
const { createCli } = await import('./cli/commands/index.ts')
|
|
29
30
|
const cli = createCli()
|
|
30
31
|
const exitCode = await cli.run(args)
|
|
31
32
|
if (exitCode !== 0) {
|