@transloadit/node 4.7.2 → 4.7.4

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.
@@ -7,8 +7,9 @@ import {
7
7
  assemblyInstructionsSchema,
8
8
  } from '../../alphalib/types/template.ts'
9
9
  import type { OptionalAuthParams } from '../../apiTypes.ts'
10
+ import { mintBearerTokenWithCredentials } from '../../bearerToken.ts'
10
11
  import { Transloadit } from '../../Transloadit.ts'
11
- import { getEnvCredentials, readCliInput } from '../helpers.ts'
12
+ import { readCliInput, requireEnvCredentials } from '../helpers.ts'
12
13
  import { UnauthenticatedCommand } from './BaseCommand.ts'
13
14
 
14
15
  type UrlParamPrimitive = string | number | boolean
@@ -68,40 +69,51 @@ function normalizeUrlParams(params?: Record<string, unknown>): NormalizedUrlPara
68
69
  return normalized
69
70
  }
70
71
 
71
- const getCredentials = getEnvCredentials
72
+ type OutputResult = { ok: true; output: string } | { ok: false; error: string }
72
73
 
73
- // Result type for signature operations
74
- type SigResult = { ok: true; output: string } | { ok: false; error: string }
74
+ type Result<T> = { ok: true; value: T } | { ok: false; error: string }
75
+
76
+ function parseJsonObject<TSchema extends z.ZodTypeAny>(
77
+ input: string,
78
+ schema: TSchema,
79
+ ): Result<z.infer<TSchema>> {
80
+ let parsed: unknown
81
+ try {
82
+ parsed = JSON.parse(input)
83
+ } catch (error) {
84
+ return { ok: false, error: `Failed to parse JSON from stdin: ${(error as Error).message}` }
85
+ }
86
+
87
+ if (parsed == null || typeof parsed !== 'object' || Array.isArray(parsed)) {
88
+ return { ok: false, error: 'Invalid params provided via stdin. Expected a JSON object.' }
89
+ }
90
+
91
+ const parsedResult = schema.safeParse(parsed)
92
+ if (!parsedResult.success) {
93
+ return { ok: false, error: `Invalid params: ${formatIssues(parsedResult.error.issues)}` }
94
+ }
95
+
96
+ return { ok: true, value: parsedResult.data }
97
+ }
75
98
 
76
99
  // Core logic for signature generation
77
100
  function generateSignature(
78
101
  input: string,
79
102
  credentials: { authKey: string; authSecret: string },
80
103
  algorithm?: string,
81
- ): SigResult {
104
+ ): OutputResult {
82
105
  const { authKey, authSecret } = credentials
83
106
  let params: CliSignatureParams
84
107
 
85
108
  if (input === '') {
86
109
  params = { auth: { key: authKey } }
87
110
  } else {
88
- let parsed: unknown
89
- try {
90
- parsed = JSON.parse(input)
91
- } catch (error) {
92
- return { ok: false, error: `Failed to parse JSON from stdin: ${(error as Error).message}` }
93
- }
94
-
95
- if (parsed == null || typeof parsed !== 'object' || Array.isArray(parsed)) {
96
- return { ok: false, error: 'Invalid params provided via stdin. Expected a JSON object.' }
97
- }
98
-
99
- const parsedResult = cliSignatureParamsSchema.safeParse(parsed)
100
- if (!parsedResult.success) {
101
- return { ok: false, error: `Invalid params: ${formatIssues(parsedResult.error.issues)}` }
111
+ const parsedResult = parseJsonObject(input, cliSignatureParamsSchema)
112
+ if (!parsedResult.ok) {
113
+ return { ok: false, error: parsedResult.error }
102
114
  }
103
115
 
104
- const parsedParams = parsedResult.data
116
+ const parsedParams = parsedResult.value
105
117
  const existingAuth = parsedParams.auth ?? {}
106
118
 
107
119
  params = {
@@ -126,7 +138,7 @@ function generateSignature(
126
138
  function generateSmartCdnUrl(
127
139
  input: string,
128
140
  credentials: { authKey: string; authSecret: string },
129
- ): SigResult {
141
+ ): OutputResult {
130
142
  const { authKey, authSecret } = credentials
131
143
 
132
144
  if (input === '') {
@@ -137,23 +149,12 @@ function generateSmartCdnUrl(
137
149
  }
138
150
  }
139
151
 
140
- let parsed: unknown
141
- try {
142
- parsed = JSON.parse(input)
143
- } catch (error) {
144
- return { ok: false, error: `Failed to parse JSON from stdin: ${(error as Error).message}` }
145
- }
146
-
147
- if (parsed == null || typeof parsed !== 'object' || Array.isArray(parsed)) {
148
- return { ok: false, error: 'Invalid params provided via stdin. Expected a JSON object.' }
149
- }
150
-
151
- const parsedResult = smartCdnParamsSchema.safeParse(parsed)
152
- if (!parsedResult.success) {
153
- return { ok: false, error: `Invalid params: ${formatIssues(parsedResult.error.issues)}` }
152
+ const parsedResult = parseJsonObject(input, smartCdnParamsSchema)
153
+ if (!parsedResult.ok) {
154
+ return { ok: false, error: parsedResult.error }
154
155
  }
155
156
 
156
- const { workspace, template, input: inputFieldRaw, url_params, expire_at_ms } = parsedResult.data
157
+ const { workspace, template, input: inputFieldRaw, url_params, expire_at_ms } = parsedResult.value
157
158
  const urlParams = normalizeUrlParams(url_params)
158
159
 
159
160
  let expiresAt: number | undefined
@@ -195,14 +196,13 @@ export interface RunSmartSigOptions {
195
196
  }
196
197
 
197
198
  export async function runSig(options: RunSigOptions = {}): Promise<void> {
198
- const credentials = getCredentials()
199
- if (credentials == null) {
200
- console.error(
201
- 'Missing credentials. Please set TRANSLOADIT_KEY and TRANSLOADIT_SECRET environment variables.',
202
- )
199
+ const credentialsResult = requireEnvCredentials()
200
+ if (!credentialsResult.ok) {
201
+ console.error(credentialsResult.error)
203
202
  process.exitCode = 1
204
203
  return
205
204
  }
205
+ const credentials = credentialsResult.credentials
206
206
 
207
207
  const { content } = await readCliInput({
208
208
  providedInput: options.providedInput,
@@ -220,14 +220,13 @@ export async function runSig(options: RunSigOptions = {}): Promise<void> {
220
220
  }
221
221
 
222
222
  export async function runSmartSig(options: RunSmartSigOptions = {}): Promise<void> {
223
- const credentials = getCredentials()
224
- if (credentials == null) {
225
- console.error(
226
- 'Missing credentials. Please set TRANSLOADIT_KEY and TRANSLOADIT_SECRET environment variables.',
227
- )
223
+ const credentialsResult = requireEnvCredentials()
224
+ if (!credentialsResult.ok) {
225
+ console.error(credentialsResult.error)
228
226
  process.exitCode = 1
229
227
  return
230
228
  }
229
+ const credentials = credentialsResult.credentials
231
230
 
232
231
  const { content } = await readCliInput({
233
232
  providedInput: options.providedInput,
@@ -274,13 +273,12 @@ export class SignatureCommand extends UnauthenticatedCommand {
274
273
  })
275
274
 
276
275
  protected async run(): Promise<number | undefined> {
277
- const credentials = getCredentials()
278
- if (credentials == null) {
279
- this.output.error(
280
- 'Missing credentials. Please set TRANSLOADIT_KEY and TRANSLOADIT_SECRET environment variables.',
281
- )
276
+ const credentialsResult = requireEnvCredentials()
277
+ if (!credentialsResult.ok) {
278
+ this.output.error(credentialsResult.error)
282
279
  return 1
283
280
  }
281
+ const credentials = credentialsResult.credentials
284
282
 
285
283
  const { content } = await readCliInput({ allowStdinWhenNoPath: true })
286
284
  const rawInput = (content ?? '').trim()
@@ -328,13 +326,12 @@ export class SmartCdnSignatureCommand extends UnauthenticatedCommand {
328
326
  })
329
327
 
330
328
  protected async run(): Promise<number | undefined> {
331
- const credentials = getCredentials()
332
- if (credentials == null) {
333
- this.output.error(
334
- 'Missing credentials. Please set TRANSLOADIT_KEY and TRANSLOADIT_SECRET environment variables.',
335
- )
329
+ const credentialsResult = requireEnvCredentials()
330
+ if (!credentialsResult.ok) {
331
+ this.output.error(credentialsResult.error)
336
332
  return 1
337
333
  }
334
+ const credentials = credentialsResult.credentials
338
335
 
339
336
  const { content } = await readCliInput({ allowStdinWhenNoPath: true })
340
337
  const rawInput = (content ?? '').trim()
@@ -349,3 +346,56 @@ export class SmartCdnSignatureCommand extends UnauthenticatedCommand {
349
346
  return 1
350
347
  }
351
348
  }
349
+
350
+ /**
351
+ * Mint a short-lived bearer token via POST /token (HTTP Basic Auth).
352
+ *
353
+ * This is intentionally stdout-clean JSON so it can be used by agents and scripts.
354
+ */
355
+ export class TokenCommand extends UnauthenticatedCommand {
356
+ static override paths = [['auth', 'token']]
357
+
358
+ static override usage = Command.Usage({
359
+ category: 'Auth',
360
+ description: 'Mint a short-lived bearer token',
361
+ details: `
362
+ Calls POST /token using HTTP Basic Auth (TRANSLOADIT_KEY + TRANSLOADIT_SECRET) and prints the
363
+ JSON response to stdout.
364
+ `,
365
+ examples: [
366
+ ['Mint an MCP token (default aud)', 'transloadit auth token'],
367
+ ['Override audience', 'transloadit auth token --aud api2'],
368
+ ],
369
+ })
370
+
371
+ aud = Option.String('--aud', {
372
+ description: 'Token audience (default: mcp).',
373
+ })
374
+
375
+ scope = Option.String('--scope', {
376
+ description:
377
+ 'Comma-separated list of scopes to request (defaults to auth key scopes). Example: assemblies:write,templates:read',
378
+ })
379
+
380
+ protected override async run(): Promise<number | undefined> {
381
+ const credentialsResult = requireEnvCredentials()
382
+ if (!credentialsResult.ok) {
383
+ this.output.error(credentialsResult.error)
384
+ return 1
385
+ }
386
+
387
+ const result = await mintBearerTokenWithCredentials(credentialsResult.credentials, {
388
+ endpoint: this.endpoint,
389
+ aud: this.aud,
390
+ scope: this.scope,
391
+ })
392
+
393
+ if (result.ok) {
394
+ process.stdout.write(`${result.raw}\n`)
395
+ return undefined
396
+ }
397
+
398
+ this.output.error(result.error)
399
+ return 1
400
+ }
401
+ }
@@ -11,7 +11,7 @@ import {
11
11
  AssembliesReplayCommand,
12
12
  } from './assemblies.ts'
13
13
 
14
- import { SignatureCommand, SmartCdnSignatureCommand } from './auth.ts'
14
+ import { SignatureCommand, SmartCdnSignatureCommand, TokenCommand } from './auth.ts'
15
15
 
16
16
  import { BillsGetCommand } from './bills.ts'
17
17
  import { DocsRobotsGetCommand, DocsRobotsListCommand } from './docs.ts'
@@ -40,6 +40,7 @@ export function createCli(): Cli {
40
40
  // Auth commands (signature generation)
41
41
  cli.register(SignatureCommand)
42
42
  cli.register(SmartCdnSignatureCommand)
43
+ cli.register(TokenCommand)
43
44
 
44
45
  // Assemblies commands
45
46
  cli.register(AssembliesCreateCommand)
@@ -3,7 +3,12 @@ import fsp from 'node:fs/promises'
3
3
  import type { Readable } from 'node:stream'
4
4
  import { isAPIError } from './types.ts'
5
5
 
6
- export function getEnvCredentials(): { authKey: string; authSecret: string } | null {
6
+ const MISSING_CREDENTIALS_MESSAGE =
7
+ 'Missing credentials. Please set TRANSLOADIT_KEY and TRANSLOADIT_SECRET environment variables.'
8
+
9
+ type EnvCredentials = { authKey: string; authSecret: string }
10
+
11
+ function getEnvCredentials(): { authKey: string; authSecret: string } | null {
7
12
  const authKey = process.env.TRANSLOADIT_KEY ?? process.env.TRANSLOADIT_AUTH_KEY
8
13
  const authSecret = process.env.TRANSLOADIT_SECRET ?? process.env.TRANSLOADIT_AUTH_SECRET
9
14
 
@@ -12,6 +17,16 @@ export function getEnvCredentials(): { authKey: string; authSecret: string } | n
12
17
  return { authKey, authSecret }
13
18
  }
14
19
 
20
+ type RequireEnvCredentialsResult =
21
+ | { ok: true; credentials: EnvCredentials }
22
+ | { ok: false; error: string }
23
+
24
+ export function requireEnvCredentials(): RequireEnvCredentialsResult {
25
+ const credentials = getEnvCredentials()
26
+ if (credentials == null) return { ok: false, error: MISSING_CREDENTIALS_MESSAGE }
27
+ return { ok: true, credentials }
28
+ }
29
+
15
30
  export function createReadStream(file: string): Readable {
16
31
  if (file === '-') return process.stdin
17
32
  return fs.createReadStream(file)