@@ -4,14 +4,23 @@ import { realpathSync } from 'node:fs'
44import path from 'node:path'
55import process from 'node:process'
66import { fileURLToPath } from 'node:url'
7- import type { ZodIssue } from 'zod'
8- import {
9- assemblyAuthInstructionsSchema ,
10- assemblyInstructionsSchema ,
11- } from './alphalib/types/template.ts'
12- import type { OptionalAuthParams } from './apiTypes.ts'
7+ import { type ZodIssue , z } from 'zod'
138import { Transloadit } from './Transloadit.ts'
149
10+ type UrlParamPrimitive = string | number | boolean
11+ type UrlParamArray = UrlParamPrimitive [ ]
12+ type NormalizedUrlParams = Record < string , UrlParamPrimitive | UrlParamArray >
13+
14+ const smartCdnParamsSchema = z
15+ . object ( {
16+ workspace : z . string ( ) . min ( 1 , 'workspace is required' ) ,
17+ template : z . string ( ) . min ( 1 , 'template is required' ) ,
18+ input : z . union ( [ z . string ( ) , z . number ( ) , z . boolean ( ) ] ) ,
19+ url_params : z . record ( z . unknown ( ) ) . optional ( ) ,
20+ expire_at_ms : z . union ( [ z . number ( ) , z . string ( ) ] ) . optional ( ) ,
21+ } )
22+ . passthrough ( )
23+
1524export async function readStdin ( ) : Promise < string > {
1625 if ( process . stdin . isTTY ) return ''
1726
@@ -30,11 +39,6 @@ function fail(message: string): void {
3039 process . exitCode = 1
3140}
3241
33- const cliParamsSchema = assemblyInstructionsSchema
34- . extend ( { auth : assemblyAuthInstructionsSchema . partial ( ) . optional ( ) } )
35- . partial ( )
36- . passthrough ( )
37-
3842function formatIssues ( issues : ZodIssue [ ] ) : string {
3943 return issues
4044 . map ( ( issue ) => {
@@ -44,6 +48,33 @@ function formatIssues(issues: ZodIssue[]): string {
4448 . join ( '; ' )
4549}
4650
51+ function normalizeUrlParam ( value : unknown ) : UrlParamPrimitive | UrlParamArray | undefined {
52+ if ( value == null ) return undefined
53+ if ( Array . isArray ( value ) ) {
54+ const normalized = value . filter (
55+ ( item ) : item is UrlParamPrimitive =>
56+ typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean' ,
57+ )
58+ return normalized . length > 0 ? normalized : undefined
59+ }
60+ if ( typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ) {
61+ return value
62+ }
63+ return undefined
64+ }
65+
66+ function normalizeUrlParams ( params ?: Record < string , unknown > ) : NormalizedUrlParams | undefined {
67+ if ( params == null ) return undefined
68+ let normalized : NormalizedUrlParams | undefined
69+ for ( const [ key , value ] of Object . entries ( params ) ) {
70+ const normalizedValue = normalizeUrlParam ( value )
71+ if ( normalizedValue === undefined ) continue
72+ if ( normalized == null ) normalized = { }
73+ normalized [ key ] = normalizedValue
74+ }
75+ return normalized
76+ }
77+
4778export async function runSmartSig ( providedInput ?: string ) : Promise < void > {
4879 const authKey = process . env . TRANSLOADIT_KEY || process . env . TRANSLOADIT_AUTH_KEY
4980 const authSecret = process . env . TRANSLOADIT_SECRET || process . env . TRANSLOADIT_AUTH_SECRET
@@ -57,46 +88,59 @@ export async function runSmartSig(providedInput?: string): Promise<void> {
5788
5889 const rawInput = providedInput ?? ( await readStdin ( ) )
5990 const input = rawInput . trim ( )
60- let params : Record < string , unknown > = { }
61-
62- if ( input !== '' ) {
63- try {
64- const parsed = JSON . parse ( input )
65- if ( parsed == null || typeof parsed !== 'object' || Array . isArray ( parsed ) ) {
66- fail ( 'Invalid params provided via stdin. Expected a JSON object.' )
67- return
68- }
69-
70- const parsedResult = cliParamsSchema . safeParse ( parsed )
71- if ( ! parsedResult . success ) {
72- fail ( `Invalid params: ${ formatIssues ( parsedResult . error . issues ) } ` )
73- return
74- }
75-
76- const parsedParams = parsedResult . data as Record < string , unknown >
77- const existingAuth =
78- typeof parsedParams . auth === 'object' &&
79- parsedParams . auth != null &&
80- ! Array . isArray ( parsedParams . auth )
81- ? ( parsedParams . auth as Record < string , unknown > )
82- : { }
83-
84- params = {
85- ...parsedParams ,
86- auth : {
87- ...existingAuth ,
88- key : authKey ,
89- } ,
90- }
91- } catch ( error : unknown ) {
92- fail ( `Failed to parse JSON from stdin: ${ ( error as Error ) . message } ` )
91+ if ( input === '' ) {
92+ fail (
93+ 'Missing params provided via stdin. Expected a JSON object with workspace, template, input, and optional Smart CDN parameters.' ,
94+ )
95+ return
96+ }
97+
98+ let parsed : unknown
99+ try {
100+ parsed = JSON . parse ( input )
101+ } catch ( error ) {
102+ fail ( `Failed to parse JSON from stdin: ${ ( error as Error ) . message } ` )
103+ return
104+ }
105+
106+ if ( parsed == null || typeof parsed !== 'object' || Array . isArray ( parsed ) ) {
107+ fail ( 'Invalid params provided via stdin. Expected a JSON object.' )
108+ return
109+ }
110+
111+ const parsedResult = smartCdnParamsSchema . safeParse ( parsed )
112+ if ( ! parsedResult . success ) {
113+ fail ( `Invalid params: ${ formatIssues ( parsedResult . error . issues ) } ` )
114+ return
115+ }
116+
117+ const { workspace , template , input : inputFieldRaw , url_params , expire_at_ms } = parsedResult . data
118+
119+ const urlParams = normalizeUrlParams ( url_params as Record < string , unknown > | undefined )
120+
121+ let expiresAt : number | undefined
122+ if ( typeof expire_at_ms === 'string' ) {
123+ const parsedNumber = Number . parseInt ( expire_at_ms , 10 )
124+ if ( Number . isNaN ( parsedNumber ) ) {
125+ fail ( 'Invalid params: expire_at_ms must be a number.' )
93126 return
94127 }
128+ expiresAt = parsedNumber
129+ } else {
130+ expiresAt = expire_at_ms
95131 }
96132
133+ const inputField = typeof inputFieldRaw === 'string' ? inputFieldRaw : String ( inputFieldRaw )
134+
97135 const client = new Transloadit ( { authKey, authSecret } )
98- const signature = client . calcSignature ( params as OptionalAuthParams )
99- process . stdout . write ( `${ JSON . stringify ( signature ) } \n` )
136+ const signedUrl = client . getSignedSmartCDNUrl ( {
137+ workspace,
138+ template,
139+ input : inputField ,
140+ urlParams,
141+ expiresAt,
142+ } )
143+ process . stdout . write ( `${ signedUrl } \n` )
100144}
101145
102146export async function main ( args = process . argv . slice ( 2 ) ) : Promise < void > {
@@ -114,7 +158,12 @@ export async function main(args = process.argv.slice(2)): Promise<void> {
114158 process . stdout . write (
115159 [
116160 'Usage:' ,
117- ' npx transloadit smart_sig Read params JSON from stdin and output signed payload.' ,
161+ ' npx transloadit smart_sig Read Smart CDN params JSON from stdin and output a signed URL.' ,
162+ '' ,
163+ 'Required JSON fields:' ,
164+ ' workspace, template, input' ,
165+ 'Optional JSON fields:' ,
166+ ' expire_at_ms, url_params' ,
118167 '' ,
119168 'Environment variables:' ,
120169 ' TRANSLOADIT_KEY, TRANSLOADIT_SECRET' ,
0 commit comments