@devicecloud.dev/dcd 4.1.7 → 4.2.0

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/dist/methods.js CHANGED
@@ -77,7 +77,8 @@ const verifyAppZip = async (zipPath) => {
77
77
  zip.close();
78
78
  };
79
79
  exports.verifyAppZip = verifyAppZip;
80
- const uploadBinary = async (filePath, apiUrl, apiKey, ignoreShaCheck = false, log = true, debug = false) => {
80
+ const uploadBinary = async (config) => {
81
+ const { filePath, apiUrl, apiKey, ignoreShaCheck = false, log = true, debug = false } = config;
81
82
  if (log) {
82
83
  core_1.ux.action.start(styling_1.colors.bold('Checking and uploading binary'), styling_1.colors.dim('Initializing'), {
83
84
  stdout: true,
@@ -107,7 +108,7 @@ const uploadBinary = async (filePath, apiUrl, apiKey, ignoreShaCheck = false, lo
107
108
  }
108
109
  }
109
110
  // Perform the upload
110
- const uploadId = await performUpload(filePath, apiUrl, apiKey, file, sha, debug, startTime);
111
+ const uploadId = await performUpload({ apiKey, apiUrl, debug, file, filePath, sha, startTime });
111
112
  if (log) {
112
113
  core_1.ux.action.stop(styling_1.colors.success('\n✓ Binary uploaded with ID: ') + (0, styling_1.formatId)(uploadId));
113
114
  }
@@ -232,162 +233,240 @@ async function checkExistingUpload(apiUrl, apiKey, sha, debug) {
232
233
  }
233
234
  }
234
235
  /**
235
- * Performs the actual file upload
236
- * @param filePath Path to the file being uploaded
237
- * @param apiUrl API base URL
238
- * @param apiKey API authentication key
239
- * @param file Prepared file to upload
240
- * @param sha SHA-256 hash of the file
241
- * @param debug Whether debug logging is enabled
242
- * @param startTime Timestamp when upload started
243
- * @returns Promise resolving to upload ID
236
+ * Uploads file to Supabase using resumable uploads
237
+ * @param env - Environment (dev or prod)
238
+ * @param tempPath - Temporary staging path for upload
239
+ * @param file - File to upload
240
+ * @param debug - Enable debug logging
241
+ * @returns Upload result with success status and any error
244
242
  */
245
- async function performUpload(filePath, apiUrl, apiKey, file, sha, debug, startTime) {
243
+ async function uploadToSupabase(env, tempPath, file, debug) {
246
244
  if (debug) {
247
- console.log('[DEBUG] Requesting upload URL...');
248
- console.log(`[DEBUG] Target endpoint: ${apiUrl}/uploads/getBinaryUploadUrl`);
249
- console.log(`[DEBUG] Platform: ${filePath?.endsWith('.apk') ? 'android' : 'ios'}`);
250
- }
251
- const urlRequestStartTime = Date.now();
252
- const { id, message, path, token, b2 } = await api_gateway_1.ApiGateway.getBinaryUploadUrl(apiUrl, apiKey, filePath?.endsWith('.apk') ? 'android' : 'ios', file.size);
253
- if (debug) {
254
- console.log(`[DEBUG] Upload URL request completed in ${Date.now() - urlRequestStartTime}ms`);
255
- console.log(`[DEBUG] Upload ID: ${id}`);
256
- console.log(`[DEBUG] Upload path: ${path}`);
257
- console.log(`[DEBUG] Backblaze upload URL provided: ${Boolean(b2)}`);
258
- if (b2) {
259
- console.log(`[DEBUG] Backblaze strategy: ${b2.strategy}`);
260
- }
261
- }
262
- if (!path)
263
- throw new Error(message);
264
- // Extract app metadata using the service
265
- if (debug) {
266
- console.log('[DEBUG] Extracting app metadata...');
267
- }
268
- const metadataExtractor = new metadata_extractor_service_1.MetadataExtractorService();
269
- const metadata = await metadataExtractor.extract(filePath);
270
- if (!metadata) {
271
- throw new Error(`Failed to extract metadata from ${filePath}. Supported formats: .apk, .app, .zip`);
272
- }
273
- if (debug) {
274
- console.log(`[DEBUG] Metadata extracted: ${JSON.stringify(metadata)}`);
275
- }
276
- const env = apiUrl === 'https://api.devicecloud.dev' ? 'prod' : 'dev';
277
- let supabaseSuccess = false;
278
- let backblazeSuccess = false;
279
- let lastError = null;
280
- // Try Supabase upload first
281
- if (debug) {
282
- console.log(`[DEBUG] Uploading to Supabase storage (${env})...`);
245
+ console.log(`[DEBUG] Uploading to Supabase storage (${env}) using resumable uploads...`);
246
+ console.log(`[DEBUG] Staging path: ${tempPath}`);
283
247
  console.log(`[DEBUG] File size: ${(file.size / 1024 / 1024).toFixed(2)} MB`);
284
248
  }
285
249
  try {
286
250
  const uploadStartTime = Date.now();
287
- await supabase_gateway_1.SupabaseGateway.uploadToSignedUrl(env, path, token, file, debug);
288
- supabaseSuccess = true;
251
+ await supabase_gateway_1.SupabaseGateway.uploadResumable(env, tempPath, file, debug);
289
252
  if (debug) {
290
253
  const uploadDuration = Date.now() - uploadStartTime;
291
- const uploadSpeed = (file.size / 1024 / 1024) / (uploadDuration / 1000);
292
- console.log(`[DEBUG] Supabase upload completed in ${uploadDuration}ms`);
254
+ const uploadDurationSeconds = uploadDuration / 1000;
255
+ const uploadSpeed = (file.size / 1024 / 1024) / uploadDurationSeconds;
256
+ console.log(`[DEBUG] Supabase resumable upload completed in ${uploadDurationSeconds.toFixed(2)}s (${uploadDuration}ms)`);
293
257
  console.log(`[DEBUG] Average upload speed: ${uploadSpeed.toFixed(2)} MB/s`);
294
258
  }
259
+ return { error: null, success: true };
295
260
  }
296
261
  catch (error) {
297
- lastError = error instanceof Error ? error : new Error(String(error));
262
+ const uploadError = error instanceof Error ? error : new Error(String(error));
298
263
  if (debug) {
299
- console.error(`[DEBUG] === SUPABASE UPLOAD FAILED ===`);
300
- console.error(`[DEBUG] Error message: ${lastError.message}`);
301
- console.error(`[DEBUG] Error name: ${lastError.name}`);
302
- if (lastError.stack) {
303
- console.error(`[DEBUG] Error stack:\n${lastError.stack}`);
264
+ console.error(`[DEBUG] === SUPABASE RESUMABLE UPLOAD FAILED ===`);
265
+ console.error(`[DEBUG] Error message: ${uploadError.message}`);
266
+ console.error(`[DEBUG] Error name: ${uploadError.name}`);
267
+ if (uploadError.stack) {
268
+ console.error(`[DEBUG] Error stack:\n${uploadError.stack}`);
304
269
  }
305
- console.error(`[DEBUG] Upload path: ${path}`);
270
+ console.error(`[DEBUG] Staging path: ${tempPath}`);
306
271
  console.error(`[DEBUG] File size: ${file.size} bytes`);
307
272
  console.log('[DEBUG] Will attempt Backblaze fallback if available...');
308
273
  }
274
+ return { error: uploadError, success: false };
309
275
  }
310
- // Try Backblaze upload (either as backup or fallback)
311
- if (b2) {
312
- if (debug) {
313
- if (supabaseSuccess) {
314
- console.log('[DEBUG] Starting Backblaze backup upload...');
315
- }
316
- else {
317
- console.log('[DEBUG] Starting Backblaze fallback upload...');
318
- }
276
+ }
277
+ /**
278
+ * Handles Backblaze upload with appropriate strategy
279
+ * @param config - Configuration object for Backblaze upload
280
+ * @returns Upload result with success status and any error
281
+ */
282
+ async function handleBackblazeUpload(config) {
283
+ const { b2, apiUrl, apiKey, finalPath, file, filePath, debug, supabaseSuccess } = config;
284
+ if (!b2) {
285
+ if (debug && !supabaseSuccess) {
286
+ console.log('[DEBUG] Backblaze not configured, cannot fallback');
319
287
  }
320
- try {
321
- const b2UploadStartTime = Date.now();
322
- if (b2.strategy === 'simple' && b2.simple) {
323
- // Simple upload for files < 100MB
324
- backblazeSuccess = await uploadToBackblaze(b2.simple.uploadUrl, b2.simple.authorizationToken, `organizations/${path}`, file, debug);
325
- }
326
- else if (b2.strategy === 'large' && b2.large) {
327
- // Multi-part upload for files >= 100MB (uses streaming to avoid memory issues)
328
- backblazeSuccess = await uploadLargeFileToBackblaze(apiUrl, apiKey, b2.large.fileId, b2.large.uploadPartUrls, `organizations/${path}`, filePath, file.size, debug, file);
329
- }
330
- if (debug) {
331
- const b2UploadDuration = Date.now() - b2UploadStartTime;
332
- if (backblazeSuccess) {
333
- console.log(`[DEBUG] Backblaze upload completed successfully in ${b2UploadDuration}ms`);
334
- }
335
- else {
336
- console.log(`[DEBUG] Backblaze upload failed after ${b2UploadDuration}ms`);
337
- }
338
- }
288
+ return { error: null, success: false };
289
+ }
290
+ if (debug) {
291
+ console.log(supabaseSuccess ? '[DEBUG] Starting Backblaze backup upload...' : '[DEBUG] Starting Backblaze fallback upload...');
292
+ }
293
+ try {
294
+ const b2UploadStartTime = Date.now();
295
+ let backblazeSuccess = false;
296
+ if (b2.strategy === 'simple' && b2.simple) {
297
+ const simple = b2.simple;
298
+ backblazeSuccess = await uploadToBackblaze(simple.uploadUrl, simple.authorizationToken, `organizations/${finalPath}`, file, debug);
299
+ }
300
+ else if (b2.strategy === 'large' && b2.large) {
301
+ const large = b2.large;
302
+ backblazeSuccess = await uploadLargeFileToBackblaze({
303
+ apiKey,
304
+ apiUrl,
305
+ debug,
306
+ fileId: large.fileId,
307
+ fileName: `organizations/${finalPath}`,
308
+ fileObject: file,
309
+ filePath,
310
+ fileSize: file.size,
311
+ uploadPartUrls: large.uploadPartUrls,
312
+ });
339
313
  }
340
- catch (error) {
341
- // This catch block should rarely be reached now since upload functions handle their own errors
342
- const b2Error = error instanceof Error ? error : new Error(String(error));
343
- if (debug) {
344
- console.error(`[DEBUG] === UNEXPECTED BACKBLAZE UPLOAD ERROR ===`);
345
- console.error(`[DEBUG] Error message: ${b2Error.message}`);
346
- console.error(`[DEBUG] Error name: ${b2Error.name}`);
347
- if (b2Error.stack) {
348
- console.error(`[DEBUG] Error stack:\n${b2Error.stack}`);
349
- }
350
- console.error(`[DEBUG] Upload strategy: ${b2.strategy}`);
351
- }
352
- backblazeSuccess = false;
353
- // Only update lastError if Supabase also failed
354
- if (!supabaseSuccess) {
355
- lastError = b2Error;
356
- }
314
+ if (debug) {
315
+ const duration = Date.now() - b2UploadStartTime;
316
+ const durationSeconds = duration / 1000;
317
+ console.log(backblazeSuccess
318
+ ? `[DEBUG] Backblaze upload completed successfully in ${durationSeconds.toFixed(2)}s (${duration}ms)`
319
+ : `[DEBUG] Backblaze upload failed after ${durationSeconds.toFixed(2)}s (${duration}ms)`);
357
320
  }
321
+ return { error: null, success: backblazeSuccess };
358
322
  }
359
- else if (debug && !supabaseSuccess) {
360
- console.log('[DEBUG] Backblaze not configured, cannot fallback');
361
- }
362
- // Check if at least one upload succeeded
363
- if (!supabaseSuccess && !backblazeSuccess) {
323
+ catch (error) {
324
+ const b2Error = error instanceof Error ? error : new Error(String(error));
364
325
  if (debug) {
365
- console.error(`[DEBUG] === ALL UPLOADS FAILED ===`);
366
- console.error(`[DEBUG] Supabase upload: FAILED`);
367
- console.error(`[DEBUG] Backblaze upload: ${b2 ? 'FAILED' : 'NOT CONFIGURED'}`);
368
- if (lastError) {
369
- console.error(`[DEBUG] Final error details:`);
370
- console.error(`[DEBUG] - Message: ${lastError.message}`);
371
- console.error(`[DEBUG] - Name: ${lastError.name}`);
372
- console.error(`[DEBUG] - Stack: ${lastError.stack}`);
326
+ console.error(`[DEBUG] === UNEXPECTED BACKBLAZE UPLOAD ERROR ===`);
327
+ console.error(`[DEBUG] Error message: ${b2Error.message}`);
328
+ console.error(`[DEBUG] Error name: ${b2Error.name}`);
329
+ if (b2Error.stack) {
330
+ console.error(`[DEBUG] Error stack:\n${b2Error.stack}`);
373
331
  }
332
+ console.error(`[DEBUG] Upload strategy: ${b2.strategy}`);
374
333
  }
375
- throw new Error(`All uploads failed. ${lastError ? `Last error: ${JSON.stringify({ message: lastError.message, name: lastError.name, stack: lastError.stack })}` : 'No upload targets available.'}`);
334
+ return { error: b2Error, success: false };
376
335
  }
336
+ }
337
+ /**
338
+ * Requests upload URL and paths from API
339
+ * @param apiUrl - API base URL
340
+ * @param apiKey - API authentication key
341
+ * @param filePath - Path to the file being uploaded
342
+ * @param fileSize - Size of the file in bytes
343
+ * @param debug - Enable debug logging
344
+ * @returns Promise resolving to upload paths and configuration
345
+ */
346
+ async function requestUploadPaths(apiUrl, apiKey, filePath, fileSize, debug) {
347
+ const platform = filePath?.endsWith('.apk') ? 'android' : 'ios';
377
348
  if (debug) {
378
- console.log(`[DEBUG] Upload summary - Supabase: ${supabaseSuccess ? '✓' : '✗'}, Backblaze: ${backblazeSuccess ? '✓' : '✗'}`);
379
- if (!supabaseSuccess && backblazeSuccess) {
380
- console.log('[DEBUG] ⚠ Warning: File only exists in Backblaze (Supabase failed)');
349
+ console.log('[DEBUG] Requesting upload URL...');
350
+ console.log(`[DEBUG] Target endpoint: ${apiUrl}/uploads/getBinaryUploadUrl`);
351
+ console.log(`[DEBUG] Platform: ${platform}`);
352
+ }
353
+ const urlRequestStartTime = Date.now();
354
+ const { id, tempPath, finalPath, b2 } = await api_gateway_1.ApiGateway.getBinaryUploadUrl(apiUrl, apiKey, platform, fileSize);
355
+ if (debug) {
356
+ const hasStrategy = b2 && typeof b2 === 'object' && 'strategy' in b2;
357
+ console.log(`[DEBUG] Upload URL request completed in ${Date.now() - urlRequestStartTime}ms`);
358
+ console.log(`[DEBUG] Upload ID: ${id}`);
359
+ console.log(`[DEBUG] Temp path (TUS upload): ${tempPath}`);
360
+ console.log(`[DEBUG] Final path (after finalize): ${finalPath}`);
361
+ console.log(`[DEBUG] Backblaze upload URL provided: ${Boolean(b2)}`);
362
+ if (hasStrategy)
363
+ console.log(`[DEBUG] Backblaze strategy: ${b2.strategy}`);
364
+ }
365
+ if (!tempPath)
366
+ throw new Error('No upload path provided by API');
367
+ return { b2, finalPath, id, tempPath };
368
+ }
369
+ /**
370
+ * Extracts metadata from the binary file
371
+ * @param filePath - Path to the binary file
372
+ * @param debug - Enable debug logging
373
+ * @returns Promise resolving to extracted metadata containing appId and platform
374
+ */
375
+ async function extractBinaryMetadata(filePath, debug) {
376
+ if (debug)
377
+ console.log('[DEBUG] Extracting app metadata...');
378
+ const metadataExtractor = new metadata_extractor_service_1.MetadataExtractorService();
379
+ const metadata = await metadataExtractor.extract(filePath);
380
+ if (!metadata) {
381
+ throw new Error(`Failed to extract metadata from ${filePath}. Supported formats: .apk, .app, .zip`);
382
+ }
383
+ if (debug)
384
+ console.log(`[DEBUG] Metadata extracted: ${JSON.stringify(metadata)}`);
385
+ return metadata;
386
+ }
387
+ /**
388
+ * Validates upload results and throws if all uploads failed
389
+ * @param supabaseSuccess - Whether Supabase upload succeeded
390
+ * @param backblazeSuccess - Whether Backblaze upload succeeded
391
+ * @param lastError - Last error encountered during uploads
392
+ * @param b2 - Backblaze configuration
393
+ * @param debug - Enable debug logging
394
+ * @returns void - throws error if all uploads failed
395
+ */
396
+ function validateUploadResults(supabaseSuccess, backblazeSuccess, lastError, b2, debug) {
397
+ if (supabaseSuccess || backblazeSuccess) {
398
+ return;
399
+ }
400
+ if (debug) {
401
+ console.error(`[DEBUG] === ALL UPLOADS FAILED ===`);
402
+ console.error(`[DEBUG] Supabase upload: FAILED`);
403
+ console.error(`[DEBUG] Backblaze upload: ${b2 ? 'FAILED' : 'NOT CONFIGURED'}`);
404
+ if (lastError) {
405
+ console.error(`[DEBUG] Final error details:`);
406
+ console.error(`[DEBUG] - Message: ${lastError.message}`);
407
+ console.error(`[DEBUG] - Name: ${lastError.name}`);
408
+ console.error(`[DEBUG] - Stack: ${lastError.stack}`);
381
409
  }
382
410
  }
411
+ throw new Error(`All uploads failed. ${lastError ? `Last error: ${JSON.stringify({ message: lastError.message, name: lastError.name, stack: lastError.stack })}` : 'No upload targets available.'}`);
412
+ }
413
+ /**
414
+ * Performs the actual file upload
415
+ * @param config Configuration object for the upload
416
+ * @returns Promise resolving to upload ID
417
+ */
418
+ async function performUpload(config) {
419
+ const { filePath, apiUrl, apiKey, file, sha, debug, startTime } = config;
420
+ // Request upload URL and paths
421
+ const { id, tempPath, finalPath, b2 } = await requestUploadPaths(apiUrl, apiKey, filePath, file.size, debug);
422
+ // Extract app metadata
423
+ const metadata = await extractBinaryMetadata(filePath, debug);
424
+ const env = apiUrl === 'https://api.devicecloud.dev' ? 'prod' : 'dev';
425
+ // Upload to Supabase
426
+ const supabaseResult = await uploadToSupabase(env, tempPath, file, debug);
427
+ let lastError = supabaseResult.error;
428
+ // Upload to Backblaze
429
+ const backblazeResult = await handleBackblazeUpload({
430
+ apiKey,
431
+ apiUrl,
432
+ b2: b2,
433
+ debug,
434
+ file,
435
+ filePath,
436
+ finalPath,
437
+ supabaseSuccess: supabaseResult.success,
438
+ });
439
+ // Update lastError if Supabase also failed
440
+ if (!supabaseResult.success && backblazeResult.error) {
441
+ lastError = backblazeResult.error;
442
+ }
443
+ // Validate results
444
+ validateUploadResults(supabaseResult.success, backblazeResult.success, lastError, b2, debug);
445
+ // Log upload summary
383
446
  if (debug) {
447
+ const hasWarning = !supabaseResult.success && backblazeResult.success;
448
+ console.log(`[DEBUG] Upload summary - Supabase: ${supabaseResult.success ? '✓' : '✗'}, Backblaze: ${backblazeResult.success ? '✓' : '✗'}`);
384
449
  console.log('[DEBUG] Finalizing upload...');
385
450
  console.log(`[DEBUG] Target endpoint: ${apiUrl}/uploads/finaliseUpload`);
386
- console.log(`[DEBUG] Supabase upload status: ${supabaseSuccess ? 'SUCCESS' : 'FAILED'}`);
387
- console.log(`[DEBUG] Backblaze upload status: ${backblazeSuccess ? 'SUCCESS' : 'FAILED'}`);
451
+ console.log(`[DEBUG] Uploaded to staging path: ${tempPath}`);
452
+ console.log(`[DEBUG] API will move to final path: ${finalPath}`);
453
+ console.log(`[DEBUG] Supabase upload status: ${supabaseResult.success ? 'SUCCESS' : 'FAILED'}`);
454
+ console.log(`[DEBUG] Backblaze upload status: ${backblazeResult.success ? 'SUCCESS' : 'FAILED'}`);
455
+ if (hasWarning)
456
+ console.log('[DEBUG] ⚠ Warning: File only exists in Backblaze (Supabase failed)');
388
457
  }
458
+ // Finalize upload
389
459
  const finalizeStartTime = Date.now();
390
- await api_gateway_1.ApiGateway.finaliseUpload(apiUrl, apiKey, id, metadata, path, sha, supabaseSuccess, backblazeSuccess);
460
+ await api_gateway_1.ApiGateway.finaliseUpload({
461
+ apiKey,
462
+ backblazeSuccess: backblazeResult.success,
463
+ baseUrl: apiUrl,
464
+ id,
465
+ metadata,
466
+ path: tempPath,
467
+ sha: sha,
468
+ supabaseSuccess: supabaseResult.success,
469
+ });
391
470
  if (debug) {
392
471
  console.log(`[DEBUG] Upload finalization completed in ${Date.now() - finalizeStartTime}ms`);
393
472
  console.log(`[DEBUG] Total upload time: ${Date.now() - startTime}ms`);
@@ -494,18 +573,11 @@ async function readFileObjectChunk(file, start, end) {
494
573
  /**
495
574
  * Upload large file to Backblaze using multi-part upload with streaming (for files >= 5MB)
496
575
  * Uses file streaming to avoid loading entire file into memory, preventing OOM errors on large files
497
- * @param apiUrl - API base URL
498
- * @param apiKey - API key for authentication
499
- * @param fileId - Backblaze file ID
500
- * @param uploadPartUrls - Array of upload URLs for each part
501
- * @param fileName - Name/path of the file in Backblaze
502
- * @param filePath - Local file path to upload from (used when fileObject is not provided)
503
- * @param fileSize - Total size of the file in bytes
504
- * @param debug - Whether debug logging is enabled
505
- * @param fileObject - Optional File/Blob object to upload from (used for .app bundles that are compressed in memory)
576
+ * @param config - Configuration object for the large file upload
506
577
  * @returns Promise that resolves when upload completes or fails gracefully
507
578
  */
508
- async function uploadLargeFileToBackblaze(apiUrl, apiKey, fileId, uploadPartUrls, _fileName, filePath, fileSize, debug, fileObject) {
579
+ async function uploadLargeFileToBackblaze(config) {
580
+ const { apiUrl, apiKey, fileId, uploadPartUrls, filePath, fileSize, debug, fileObject } = config;
509
581
  try {
510
582
  const partSha1Array = [];
511
583
  // Calculate part size (divide file evenly across all parts)
@@ -34,10 +34,10 @@ class DeviceValidationService {
34
34
  throw new Error(`${androidDeviceID} ${googlePlay ? '(Play Store) ' : ''}only supports these Android API levels: ${supportedAndroidVersions.join(', ')}`);
35
35
  }
36
36
  if (debug && logger) {
37
- logger(`DEBUG: Android device: ${androidDeviceID}`);
38
- logger(`DEBUG: Android API level: ${version}`);
39
- logger(`DEBUG: Google Play enabled: ${googlePlay}`);
40
- logger(`DEBUG: Supported Android versions: ${supportedAndroidVersions.join(', ')}`);
37
+ logger(`[DEBUG] Android device: ${androidDeviceID}`);
38
+ logger(`[DEBUG] Android API level: ${version}`);
39
+ logger(`[DEBUG] Google Play enabled: ${googlePlay}`);
40
+ logger(`[DEBUG] Supported Android versions: ${supportedAndroidVersions.join(', ')}`);
41
41
  }
42
42
  }
43
43
  /**
@@ -65,9 +65,9 @@ class DeviceValidationService {
65
65
  throw new Error(`${iOSDeviceID} only supports these iOS versions: ${supportediOSVersions.join(', ')}`);
66
66
  }
67
67
  if (debug && logger) {
68
- logger(`DEBUG: iOS device: ${iOSDeviceID}`);
69
- logger(`DEBUG: iOS version: ${version}`);
70
- logger(`DEBUG: Supported iOS versions: ${supportediOSVersions.join(', ')}`);
68
+ logger(`[DEBUG] iOS device: ${iOSDeviceID}`);
69
+ logger(`[DEBUG] iOS version: ${version}`);
70
+ logger(`[DEBUG] Supported iOS versions: ${supportediOSVersions.join(', ')}`);
71
71
  }
72
72
  }
73
73
  }
@@ -18,8 +18,8 @@ class MoropoService {
18
18
  */
19
19
  async downloadAndExtract(options) {
20
20
  const { apiKey, branchName = 'main', debug = false, quiet = false, json = false, logger } = options;
21
- this.logDebug(debug, logger, 'DEBUG: Moropo v1 API key detected, downloading tests from Moropo API');
22
- this.logDebug(debug, logger, `DEBUG: Using branch name: ${branchName}`);
21
+ this.logDebug(debug, logger, '[DEBUG] Moropo v1 API key detected, downloading tests from Moropo API');
22
+ this.logDebug(debug, logger, `[DEBUG] Using branch name: ${branchName}`);
23
23
  try {
24
24
  if (!quiet && !json) {
25
25
  core_1.ux.action.start('Downloading Moropo tests', 'Initializing', {
@@ -37,7 +37,7 @@ class MoropoService {
37
37
  throw new Error(`Failed to download Moropo tests: ${response.statusText}`);
38
38
  }
39
39
  const moropoDir = path.join(os.tmpdir(), `moropo-tests-${Date.now()}`);
40
- this.logDebug(debug, logger, `DEBUG: Extracting Moropo tests to: ${moropoDir}`);
40
+ this.logDebug(debug, logger, `[DEBUG] Extracting Moropo tests to: ${moropoDir}`);
41
41
  // Create moropo directory if it doesn't exist
42
42
  if (!fs.existsSync(moropoDir)) {
43
43
  fs.mkdirSync(moropoDir, { recursive: true });
@@ -51,17 +51,17 @@ class MoropoService {
51
51
  if (!quiet && !json) {
52
52
  core_1.ux.action.stop('completed');
53
53
  }
54
- this.logDebug(debug, logger, 'DEBUG: Successfully extracted Moropo tests');
54
+ this.logDebug(debug, logger, '[DEBUG] Successfully extracted Moropo tests');
55
55
  // Create config.yaml file
56
56
  this.createConfigFile(moropoDir);
57
- this.logDebug(debug, logger, 'DEBUG: Created config.yaml file');
57
+ this.logDebug(debug, logger, '[DEBUG] Created config.yaml file');
58
58
  return moropoDir;
59
59
  }
60
60
  catch (error) {
61
61
  if (!quiet && !json) {
62
62
  core_1.ux.action.stop('failed');
63
63
  }
64
- this.logDebug(debug, logger, `DEBUG: Error downloading/extracting Moropo tests: ${error}`);
64
+ this.logDebug(debug, logger, `[DEBUG] Error downloading/extracting Moropo tests: ${error}`);
65
65
  throw new Error(`Failed to download/extract Moropo tests: ${error}`);
66
66
  }
67
67
  }
@@ -16,7 +16,7 @@ class ReportDownloadService {
16
16
  const { apiUrl, apiKey, uploadId, downloadType, artifactsPath = './artifacts.zip', debug = false, logger, warnLogger, } = options;
17
17
  try {
18
18
  if (debug && logger) {
19
- logger(`DEBUG: Downloading artifacts: ${downloadType}`);
19
+ logger(`[DEBUG] Downloading artifacts: ${downloadType}`);
20
20
  }
21
21
  await api_gateway_1.ApiGateway.downloadArtifactsZip(apiUrl, apiKey, uploadId, downloadType, artifactsPath);
22
22
  if (logger) {
@@ -26,7 +26,7 @@ class ReportDownloadService {
26
26
  }
27
27
  catch (error) {
28
28
  if (debug && logger) {
29
- logger(`DEBUG: Error downloading artifacts: ${error}`);
29
+ logger(`[DEBUG] Error downloading artifacts: ${error}`);
30
30
  }
31
31
  if (warnLogger) {
32
32
  warnLogger('Failed to download artifacts');
@@ -83,7 +83,7 @@ class ReportDownloadService {
83
83
  const { apiUrl, apiKey, uploadId, debug = false, logger, warnLogger } = options;
84
84
  try {
85
85
  if (debug && logger) {
86
- logger(`DEBUG: Downloading ${type.toUpperCase()} report`);
86
+ logger(`[DEBUG] Downloading ${type.toUpperCase()} report`);
87
87
  }
88
88
  await api_gateway_1.ApiGateway.downloadReportGeneric(apiUrl, apiKey, uploadId, type, filePath);
89
89
  if (logger) {
@@ -92,7 +92,7 @@ class ReportDownloadService {
92
92
  }
93
93
  catch (error) {
94
94
  if (debug && logger) {
95
- logger(`DEBUG: Error downloading ${type.toUpperCase()} report: ${error}`);
95
+ logger(`[DEBUG] Error downloading ${type.toUpperCase()} report: ${error}`);
96
96
  }
97
97
  const errorMessage = error instanceof Error ? error.message : String(error);
98
98
  if (warnLogger) {
@@ -37,7 +37,7 @@ class ResultsPollingService {
37
37
  let sequentialPollFailures = 0;
38
38
  let previousSummary = '';
39
39
  if (debug && logger) {
40
- logger(`DEBUG: Starting polling loop for results`);
40
+ logger(`[DEBUG] Starting polling loop for results`);
41
41
  }
42
42
  // Poll in a loop until all tests complete
43
43
  // eslint-disable-next-line no-constant-condition
@@ -186,16 +186,16 @@ class ResultsPollingService {
186
186
  */
187
187
  async fetchAndLogResults(apiUrl, apiKey, uploadId, debug, logger) {
188
188
  if (debug && logger) {
189
- logger(`DEBUG: Polling for results: ${uploadId}`);
189
+ logger(`[DEBUG] Polling for results: ${uploadId}`);
190
190
  }
191
191
  const { results: updatedResults } = await api_gateway_1.ApiGateway.getResultsForUpload(apiUrl, apiKey, uploadId);
192
192
  if (!updatedResults) {
193
193
  throw new Error('no results');
194
194
  }
195
195
  if (debug && logger) {
196
- logger(`DEBUG: Poll received ${updatedResults.length} results`);
196
+ logger(`[DEBUG] Poll received ${updatedResults.length} results`);
197
197
  for (const result of updatedResults) {
198
- logger(`DEBUG: Result status: ${result.test_file_name} - ${result.status}`);
198
+ logger(`[DEBUG] Result status: ${result.test_file_name} - ${result.status}`);
199
199
  }
200
200
  }
201
201
  return updatedResults;
@@ -216,39 +216,39 @@ class ResultsPollingService {
216
216
  async handleCompletedTests(updatedResults, options) {
217
217
  const { uploadId, consoleUrl, json, debug, logger } = options;
218
218
  if (debug && logger) {
219
- logger(`DEBUG: All tests completed, stopping poll`);
219
+ logger(`[DEBUG] All tests completed, stopping poll`);
220
220
  }
221
221
  this.displayFinalResults(updatedResults, consoleUrl, json, logger);
222
222
  const output = this.buildPollingResult(updatedResults, uploadId, consoleUrl);
223
223
  if (output.status === 'FAILED') {
224
224
  if (debug && logger) {
225
- logger(`DEBUG: Some tests failed, returning failed status`);
225
+ logger(`[DEBUG] Some tests failed, returning failed status`);
226
226
  }
227
227
  throw new RunFailedError(output);
228
228
  }
229
229
  if (debug && logger) {
230
- logger(`DEBUG: All tests passed, returning success status`);
230
+ logger(`[DEBUG] All tests passed, returning success status`);
231
231
  }
232
232
  return output;
233
233
  }
234
234
  async handlePollingError(error, sequentialPollFailures, debug, logger) {
235
235
  if (debug && logger) {
236
- logger(`DEBUG: Error polling for results: ${error}`);
237
- logger(`DEBUG: Sequential poll failures: ${sequentialPollFailures}`);
236
+ logger(`[DEBUG] Error polling for results: ${error}`);
237
+ logger(`[DEBUG] Sequential poll failures: ${sequentialPollFailures}`);
238
238
  }
239
239
  if (sequentialPollFailures > this.MAX_SEQUENTIAL_FAILURES) {
240
240
  if (debug && logger) {
241
- logger('DEBUG: Checking internet connectivity...');
241
+ logger('[DEBUG] Checking internet connectivity...');
242
242
  }
243
243
  const connectivityCheck = await (0, connectivity_1.checkInternetConnectivity)();
244
244
  if (debug && logger) {
245
- logger(`DEBUG: ${connectivityCheck.message}`);
245
+ logger(`[DEBUG] ${connectivityCheck.message}`);
246
246
  for (const result of connectivityCheck.endpointResults) {
247
247
  if (result.success) {
248
- logger(`DEBUG: ✓ ${result.endpoint} - ${result.statusCode} (${result.latencyMs}ms)`);
248
+ logger(`[DEBUG] ✓ ${result.endpoint} - ${result.statusCode} (${result.latencyMs}ms)`);
249
249
  }
250
250
  else {
251
- logger(`DEBUG: ✗ ${result.endpoint} - ${result.error} (${result.latencyMs}ms)`);
251
+ logger(`[DEBUG] ✗ ${result.endpoint} - ${result.error} (${result.latencyMs}ms)`);
252
252
  }
253
253
  }
254
254
  }
@@ -26,7 +26,6 @@ export interface TestSubmissionConfig {
26
26
  retry?: number;
27
27
  runnerType?: string;
28
28
  showCrosshairs?: boolean;
29
- skipChromeOnboarding?: boolean;
30
29
  }
31
30
  /**
32
31
  * Service for building test submission form data