15
15
*/
16
16
17
17
import * as superstruct from 'superstruct' ;
18
+ import express from 'express' ;
18
19
19
20
import * as utils from '../utils' ;
20
21
import { Operation , OperationAction , OperationBuilder } from '../types' ;
@@ -48,6 +49,15 @@ const structFromUrl = superstruct.object({
48
49
url : superstruct . string ( ) ,
49
50
} ) ;
50
51
52
+ /**
53
+ * A path url of an image. The request hostname will be prepended to this path.
54
+ */
55
+ const structFromPath = superstruct . object ( {
56
+ operation : superstruct . literal ( name ) ,
57
+ type : superstruct . literal ( 'path' ) ,
58
+ path : superstruct . string ( ) ,
59
+ } ) ;
60
+
51
61
/**
52
62
* Create a new image.
53
63
*/
@@ -110,18 +120,21 @@ const structCreateNewImage = superstruct.object({
110
120
const struct = superstruct . union ( [
111
121
structFromGcs ,
112
122
structFromUrl ,
123
+ structFromPath ,
113
124
structCreateNewImage ,
114
125
] ) ;
115
126
116
127
export type OperationInputGcs = superstruct . Infer < typeof structFromGcs > ;
117
128
export type OperationInputUrl = superstruct . Infer < typeof structFromUrl > ;
129
+ export type OperationInputPath = superstruct . Infer < typeof structFromPath > ;
118
130
export type OperationInputCreateNew = superstruct . Infer <
119
131
typeof structCreateNewImage
120
132
> ;
121
133
122
134
export type OperationInput =
123
135
| OperationInputGcs
124
136
| OperationInputUrl
137
+ | OperationInputPath
125
138
| OperationInputCreateNew ;
126
139
127
140
export const operationInput : OperationBuilder = {
@@ -135,12 +148,14 @@ export const operationInput: OperationBuilder = {
135
148
return structFromGcs . create ( rawOptions ) ;
136
149
case 'url' :
137
150
return structFromUrl . create ( rawOptions ) ;
151
+ case 'path' :
152
+ return structFromPath . create ( rawOptions ) ;
138
153
}
139
154
throw new AssertionError ( {
140
155
message : `'${ rawOptions . type } ' is not a valid input 'type'.` ,
141
156
} ) ;
142
157
} ,
143
- async build ( operation ) {
158
+ async build ( operation , _fileMetadata , req ) {
144
159
const options = operation . options as OperationInput ;
145
160
146
161
switch ( options . type ) {
@@ -150,6 +165,8 @@ export const operationInput: OperationBuilder = {
150
165
return await fetchGcsFile ( options ) ;
151
166
case 'url' :
152
167
return await fetchUrl ( options ) ;
168
+ case 'path' :
169
+ return await fetchPathUrl ( options , req ) ;
153
170
}
154
171
} ,
155
172
} ;
@@ -169,6 +186,57 @@ async function fetchUrl(options: OperationInput): Promise<OperationAction[]> {
169
186
] ;
170
187
}
171
188
189
+ async function fetchPathUrl (
190
+ options : OperationInput ,
191
+ req ?: express . Request ,
192
+ ) : Promise < OperationAction [ ] > {
193
+ if ( options . type !== 'path' ) return [ ] ;
194
+
195
+ if ( ! req ) {
196
+ throw new AssertionError ( {
197
+ message : 'Request object is required for path type inputs.' ,
198
+ } ) ;
199
+ }
200
+
201
+ // Extract hostname from request
202
+ const origin = ( req . headers . origin as string ) || '' ;
203
+ const referer = ( req . headers . referer as string ) || '' ;
204
+ const host = req . headers . host || '' ;
205
+
206
+ let baseUrl = '' ;
207
+
208
+ // Try to get the base URL from various sources
209
+ if ( origin ) {
210
+ baseUrl = origin ;
211
+ } else if ( referer ) {
212
+ try {
213
+ const url = new URL ( referer ) ;
214
+ baseUrl = `${ url . protocol } //${ url . host } ` ;
215
+ } catch ( e ) {
216
+ // Invalid URL format in referer
217
+ }
218
+ } else if ( host ) {
219
+ const protocol = req . secure ? 'https:' : 'http:' ;
220
+ baseUrl = `${ protocol } //${ host } ` ;
221
+ }
222
+
223
+ if ( ! baseUrl ) {
224
+ throw new AssertionError ( {
225
+ message : `Could not determine request hostname for path URL.` ,
226
+ } ) ;
227
+ }
228
+
229
+ // Construct the full URL
230
+ const fullUrl = `${ baseUrl } ${ options . path } ` ;
231
+
232
+ return [
233
+ {
234
+ method : 'constructor' ,
235
+ arguments : [ await fetchImageBufferFromUrl ( fullUrl ) ] ,
236
+ } ,
237
+ ] ;
238
+ }
239
+
172
240
async function fetchGcsFile (
173
241
options : OperationInput ,
174
242
) : Promise < OperationAction [ ] > {
0 commit comments