1
1
import zod from 'zod' ;
2
2
import type { Analytics } from './analytics' ;
3
3
import { AwsClient } from './aws' ;
4
+ import type { Breadcrumb } from './breadcrumbs' ;
4
5
5
6
export function buildArtifactStorageKey (
6
7
targetId : string ,
@@ -56,6 +57,8 @@ export function buildAppDeploymentIsEnabledKey(
56
57
* Read an artifact/app deployment operation from S3.
57
58
*/
58
59
export class ArtifactStorageReader {
60
+ private breadcrumb : Breadcrumb ;
61
+
59
62
constructor (
60
63
private s3 : {
61
64
client : AwsClient ;
@@ -68,9 +71,12 @@ export class ArtifactStorageReader {
68
71
bucketName : string ;
69
72
} | null ,
70
73
private analytics : Analytics | null ,
74
+ breadcrumb : Breadcrumb | null ,
71
75
/** Timeout in milliseconds for S3 read calls. */
72
76
private timeout : number = 5_000 ,
73
- ) { }
77
+ ) {
78
+ this . breadcrumb = breadcrumb ?? ( ( ) => { } ) ;
79
+ }
74
80
75
81
/**
76
82
* Perform a request to S3, with retries and optional mirror.
@@ -122,9 +128,11 @@ export class ArtifactStorageReader {
122
128
} ,
123
129
} )
124
130
. catch ( err => {
131
+ this . breadcrumb ( 'Failed to fetch from primary' ) ;
125
132
if ( ! this . s3Mirror ) {
126
133
return Promise . reject ( err ) ;
127
134
}
135
+ this . breadcrumb ( 'Fetching from primary and mirror now' ) ;
128
136
// Use two AbortSignals to avoid a situation
129
137
// where Response.body is consumed,
130
138
// but the request was aborted after being resolved.
@@ -201,11 +209,18 @@ export class ArtifactStorageReader {
201
209
artifactType = 'sdl' ;
202
210
}
203
211
212
+ this . breadcrumb (
213
+ `Reading artifact (targetId=${ targetId } , artifactType=${ artifactType } , contractName=${ contractName } )` ,
214
+ ) ;
215
+
204
216
const key = buildArtifactStorageKey ( targetId , artifactType , contractName ) ;
205
217
218
+ this . breadcrumb ( `Reading artifact from S3 key: ${ key } ` ) ;
219
+
206
220
const headers : HeadersInit = { } ;
207
221
208
222
if ( etagValue ) {
223
+ this . breadcrumb ( 'if-none-match detected' ) ;
209
224
headers [ 'if-none-match' ] = etagValue ;
210
225
}
211
226
@@ -246,6 +261,8 @@ export class ArtifactStorageReader {
246
261
} as const ;
247
262
}
248
263
264
+ this . breadcrumb ( `Failed to read artifact` ) ;
265
+
249
266
const body = await response . text ( ) ;
250
267
throw new Error ( `GET request failed with status ${ response . status } : ${ body } ` ) ;
251
268
}
@@ -330,8 +347,10 @@ export class ArtifactStorageReader {
330
347
}
331
348
332
349
async readLegacyAccessKey ( targetId : string ) {
350
+ const key = [ 'cdn-legacy-keys' , targetId ] . join ( '/' ) ;
351
+ this . breadcrumb ( `Reading from S3 key: ${ key } ` ) ;
333
352
const response = await this . request ( {
334
- key : [ 'cdn-legacy-keys' , targetId ] . join ( '/' ) ,
353
+ key,
335
354
method : 'GET' ,
336
355
onAttempt : args => {
337
356
this . analytics ?. track (
@@ -353,10 +372,11 @@ export class ArtifactStorageReader {
353
372
}
354
373
355
374
async readAccessKey ( targetId : string , keyId : string ) {
356
- const s3KeyParts = [ 'cdn-keys' , targetId , keyId ] ;
375
+ const key = [ 'cdn-keys' , targetId , keyId ] . join ( '/' ) ;
376
+ this . breadcrumb ( `Reading from S3 key: ${ key } ` ) ;
357
377
358
378
const response = await this . request ( {
359
- key : s3KeyParts . join ( '/' ) ,
379
+ key,
360
380
method : 'GET' ,
361
381
onAttempt : args => {
362
382
this . analytics ?. track (
0 commit comments