@devicecloud.dev/dcd 4.1.6 → 4.1.9-beta.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.
@@ -16,30 +16,30 @@ class TestSubmissionService {
16
16
  * @returns FormData ready to be submitted to the API
17
17
  */
18
18
  async buildTestFormData(config) {
19
- const { appBinaryId, flowFile, executionPlan, commonRoot, cliVersion, env = [], metadata = [], googlePlay = false, androidApiLevel, androidDevice, iOSVersion, iOSDevice, name, runnerType, maestroVersion, deviceLocale, orientation, mitmHost, mitmPath, retry, continueOnFailure = true, report, showCrosshairs, skipChromeOnboarding, raw, debug = false, logger, } = config;
19
+ const { appBinaryId, flowFile, executionPlan, commonRoot, cliVersion, env = [], metadata = [], googlePlay = false, androidApiLevel, androidDevice, iOSVersion, iOSDevice, name, runnerType, maestroVersion, deviceLocale, orientation, mitmHost, mitmPath, retry, continueOnFailure = true, report, showCrosshairs, raw, debug = false, logger, } = config;
20
20
  const { allExcludeTags, allIncludeTags, flowMetadata, flowOverrides, flowsToRun: testFileNames, referencedFiles, sequence, workspaceConfig, } = executionPlan;
21
21
  const { flows: sequentialFlows = [] } = sequence ?? {};
22
22
  const testFormData = new FormData();
23
23
  const envObject = this.parseKeyValuePairs(env);
24
24
  const metadataObject = this.parseKeyValuePairs(metadata);
25
25
  if (Object.keys(envObject).length > 0) {
26
- this.logDebug(debug, logger, `DEBUG: Environment variables: ${JSON.stringify(envObject)}`);
26
+ this.logDebug(debug, logger, `[DEBUG] Environment variables: ${JSON.stringify(envObject)}`);
27
27
  }
28
28
  if (Object.keys(metadataObject).length > 0) {
29
- this.logDebug(debug, logger, `DEBUG: User metadata: ${JSON.stringify(metadataObject)}`);
29
+ this.logDebug(debug, logger, `[DEBUG] User metadata: ${JSON.stringify(metadataObject)}`);
30
30
  }
31
31
  // Log non-YAML file assets being uploaded
32
32
  if (referencedFiles.length > 0) {
33
33
  const nonYamlFiles = referencedFiles.filter((file) => !file.endsWith('.yaml') && !file.endsWith('.yml'));
34
34
  if (nonYamlFiles.length > 0) {
35
- this.logDebug(debug, logger, `DEBUG: Uploading ${nonYamlFiles.length} non-YAML file asset(s):`);
35
+ this.logDebug(debug, logger, `[DEBUG] Uploading ${nonYamlFiles.length} non-YAML file asset(s):`);
36
36
  for (const file of nonYamlFiles) {
37
37
  const normalizedPath = this.normalizeFilePath(file, commonRoot);
38
- this.logDebug(debug, logger, `DEBUG: - ${normalizedPath}`);
38
+ this.logDebug(debug, logger, `[DEBUG] - ${normalizedPath}`);
39
39
  }
40
40
  }
41
41
  }
42
- this.logDebug(debug, logger, `DEBUG: Compressing files from path: ${flowFile}`);
42
+ this.logDebug(debug, logger, `[DEBUG] Compressing files from path: ${flowFile}`);
43
43
  const buffer = await (0, methods_1.compressFilesFromRelativePath)(flowFile?.endsWith('.yaml') || flowFile?.endsWith('.yml')
44
44
  ? path.dirname(flowFile)
45
45
  : flowFile, [
@@ -49,7 +49,7 @@ class TestSubmissionService {
49
49
  ...sequentialFlows,
50
50
  ]),
51
51
  ], commonRoot);
52
- this.logDebug(debug, logger, `DEBUG: Compressed file size: ${buffer.length} bytes`);
52
+ this.logDebug(debug, logger, `[DEBUG] Compressed file size: ${buffer.length} bytes`);
53
53
  const blob = new Blob([buffer], {
54
54
  type: mimeTypeLookupByExtension.zip,
55
55
  });
@@ -74,14 +74,13 @@ class TestSubmissionService {
74
74
  raw: JSON.stringify(raw),
75
75
  report,
76
76
  showCrosshairs,
77
- skipChromeOnboarding,
78
77
  version: cliVersion,
79
78
  };
80
79
  testFormData.set('config', JSON.stringify(configPayload));
81
80
  if (Object.keys(metadataObject).length > 0) {
82
81
  const metadataPayload = { userMetadata: metadataObject };
83
82
  testFormData.set('metadata', JSON.stringify(metadataPayload));
84
- this.logDebug(debug, logger, `DEBUG: Sending metadata to API: ${JSON.stringify(metadataPayload)}`);
83
+ this.logDebug(debug, logger, `[DEBUG] Sending metadata to API: ${JSON.stringify(metadataPayload)}`);
85
84
  }
86
85
  this.setOptionalFields(testFormData, {
87
86
  androidApiLevel,
@@ -59,13 +59,13 @@ class VersionService {
59
59
  if (requestedVersion === 'latest') {
60
60
  resolvedVersion = latestVersion;
61
61
  if (debug) {
62
- log(`DEBUG: Resolved "latest" to ${latestVersion}`);
62
+ log(`[DEBUG] Resolved "latest" to ${latestVersion}`);
63
63
  }
64
64
  }
65
65
  else if (!requestedVersion) {
66
66
  resolvedVersion = defaultVersion;
67
67
  if (debug) {
68
- log(`DEBUG: Using default Maestro version ${defaultVersion}`);
68
+ log(`[DEBUG] Using default Maestro version ${defaultVersion}`);
69
69
  }
70
70
  }
71
71
  // Validate Maestro version
@@ -73,8 +73,8 @@ class VersionService {
73
73
  throw new Error(`Maestro version ${resolvedVersion} is not supported. Supported versions: ${supportedVersions.join(', ')}`);
74
74
  }
75
75
  if (debug) {
76
- log(`DEBUG: Maestro version validated: ${resolvedVersion}`);
77
- log(`DEBUG: Supported Maestro versions: ${supportedVersions.join(', ')}`);
76
+ log(`[DEBUG] Maestro version validated: ${resolvedVersion}`);
77
+ log(`[DEBUG] Supported Maestro versions: ${supportedVersions.join(', ')}`);
78
78
  }
79
79
  return resolvedVersion;
80
80
  }
@@ -67,6 +67,22 @@ export interface paths {
67
67
  patch?: never;
68
68
  trace?: never;
69
69
  };
70
+ "/uploads/finishLargeFile": {
71
+ parameters: {
72
+ query?: never;
73
+ header?: never;
74
+ path?: never;
75
+ cookie?: never;
76
+ };
77
+ get?: never;
78
+ put?: never;
79
+ post: operations["UploadsController_finishLargeFile"];
80
+ delete?: never;
81
+ options?: never;
82
+ head?: never;
83
+ patch?: never;
84
+ trace?: never;
85
+ };
70
86
  "/uploads/flow": {
71
87
  parameters: {
72
88
  query?: never;
@@ -437,12 +453,38 @@ export interface components {
437
453
  };
438
454
  IGetBinaryUploadUrlArgs: {
439
455
  platform: Record<string, never>;
456
+ fileSize: number;
457
+ };
458
+ B2SimpleUpload: {
459
+ uploadUrl: string;
460
+ authorizationToken: string;
461
+ };
462
+ B2UploadPartUrl: {
463
+ uploadUrl: string;
464
+ authorizationToken: string;
465
+ };
466
+ B2LargeUpload: {
467
+ fileId: string;
468
+ fileName: string;
469
+ uploadPartUrls: components["schemas"]["B2UploadPartUrl"][];
470
+ };
471
+ B2UploadStrategy: {
472
+ /** @enum {string} */
473
+ strategy: "simple" | "large";
474
+ simple?: components["schemas"]["B2SimpleUpload"];
475
+ large?: components["schemas"]["B2LargeUpload"];
440
476
  };
441
477
  IGetBinaryUploadUrlResponse: {
442
- message: string;
478
+ /** @description Temporary upload path in uploads/ folder for TUS upload */
443
479
  path: string;
444
- token: string;
480
+ /** @description Temporary upload path (same as path) */
481
+ tempPath: string;
482
+ /** @description Final path where file will be moved after upload completes */
483
+ finalPath: string;
484
+ /** @description Upload ID */
445
485
  id: string;
486
+ /** @description Backblaze upload strategy if configured */
487
+ b2?: components["schemas"]["B2UploadStrategy"];
446
488
  };
447
489
  ICheckForExistingUploadArgs: {
448
490
  sha: string;
@@ -452,12 +494,43 @@ export interface components {
452
494
  exists: boolean;
453
495
  };
454
496
  IFinaliseUploadArgs: {
497
+ /** @description Final path where file should be moved to (for TUS uploads) */
498
+ finalPath?: string;
499
+ /**
500
+ * @description Whether the Supabase upload was successful
501
+ * @default true
502
+ */
503
+ supabaseSuccess: boolean;
504
+ /**
505
+ * @description Whether the Backblaze upload was successful
506
+ * @default false
507
+ */
508
+ backblazeSuccess: boolean;
455
509
  id: string;
456
510
  path: string;
457
511
  metadata: Record<string, never>;
458
512
  sha: string;
459
513
  };
460
514
  IFinaliseUploadResponse: Record<string, never>;
515
+ IFinishLargeFileArgs: {
516
+ /**
517
+ * @description The Backblaze file ID from the large file upload
518
+ * @example abc123xyz
519
+ */
520
+ fileId: string;
521
+ /**
522
+ * @description Array of SHA1 hashes for each uploaded part
523
+ * @example [
524
+ * "sha1hash1",
525
+ * "sha1hash2"
526
+ * ]
527
+ */
528
+ partSha1Array: string[];
529
+ };
530
+ IFinishLargeFileResponse: {
531
+ success: boolean;
532
+ result: Record<string, never>;
533
+ };
461
534
  ICreateTestUploadArgs: {
462
535
  /**
463
536
  * Format: binary
@@ -507,6 +580,18 @@ export interface components {
507
580
  fail_reason?: string;
508
581
  duration_seconds?: number;
509
582
  };
583
+ UpdateOrgNameDto: {
584
+ /**
585
+ * @description Organization ID
586
+ * @example 123
587
+ */
588
+ orgId: number;
589
+ /**
590
+ * @description Organization name
591
+ * @example Acme Corporation
592
+ */
593
+ name: string;
594
+ };
510
595
  };
511
596
  responses: never;
512
597
  parameters: never;
@@ -632,6 +717,32 @@ export interface operations {
632
717
  };
633
718
  };
634
719
  };
720
+ UploadsController_finishLargeFile: {
721
+ parameters: {
722
+ query?: never;
723
+ header: {
724
+ "x-app-api-key": string;
725
+ };
726
+ path?: never;
727
+ cookie?: never;
728
+ };
729
+ requestBody: {
730
+ content: {
731
+ "application/json": components["schemas"]["IFinishLargeFileArgs"];
732
+ };
733
+ };
734
+ responses: {
735
+ /** @description The large file upload has been completed. */
736
+ 201: {
737
+ headers: {
738
+ [name: string]: unknown;
739
+ };
740
+ content: {
741
+ "application/json": components["schemas"]["IFinishLargeFileResponse"];
742
+ };
743
+ };
744
+ };
745
+ };
635
746
  UploadsController_createTest: {
636
747
  parameters: {
637
748
  query?: never;
@@ -1127,10 +1238,11 @@ export interface operations {
1127
1238
  * "1.41.0",
1128
1239
  * "2.0.2",
1129
1240
  * "2.0.3",
1130
- * "2.0.4"
1241
+ * "2.0.4",
1242
+ * "2.0.9"
1131
1243
  * ],
1132
1244
  * "defaultVersion": "1.41.0",
1133
- * "latestVersion": "2.0.4"
1245
+ * "latestVersion": "2.0.9"
1134
1246
  * }
1135
1247
  * }
1136
1248
  * }
@@ -1357,10 +1469,7 @@ export interface operations {
1357
1469
  };
1358
1470
  requestBody: {
1359
1471
  content: {
1360
- "application/json": {
1361
- orgId: string;
1362
- name: string;
1363
- };
1472
+ "application/json": components["schemas"]["UpdateOrgNameDto"];
1364
1473
  };
1365
1474
  };
1366
1475
  responses: {
@@ -67,6 +67,22 @@ export interface paths {
67
67
  patch?: never;
68
68
  trace?: never;
69
69
  };
70
+ "/uploads/finishLargeFile": {
71
+ parameters: {
72
+ query?: never;
73
+ header?: never;
74
+ path?: never;
75
+ cookie?: never;
76
+ };
77
+ get?: never;
78
+ put?: never;
79
+ post: operations["UploadsController_finishLargeFile"];
80
+ delete?: never;
81
+ options?: never;
82
+ head?: never;
83
+ patch?: never;
84
+ trace?: never;
85
+ };
70
86
  "/uploads/flow": {
71
87
  parameters: {
72
88
  query?: never;
@@ -436,13 +452,44 @@ export interface components {
436
452
  binaryId: string;
437
453
  };
438
454
  IGetBinaryUploadUrlArgs: {
455
+ /** @description File size in bytes (optional, for Backblaze upload strategy) */
456
+ fileSize?: number;
457
+ /** @description Whether client uses TUS resumable uploads (true for new clients, undefined/false for legacy) */
458
+ useTus?: boolean;
439
459
  platform: Record<string, never>;
440
460
  };
461
+ B2SimpleUpload: {
462
+ uploadUrl: string;
463
+ authorizationToken: string;
464
+ };
465
+ B2UploadPartUrl: {
466
+ uploadUrl: string;
467
+ authorizationToken: string;
468
+ };
469
+ B2LargeUpload: {
470
+ fileId: string;
471
+ fileName: string;
472
+ uploadPartUrls: components["schemas"]["B2UploadPartUrl"][];
473
+ };
474
+ B2UploadStrategy: {
475
+ /** @enum {string} */
476
+ strategy: "simple" | "large";
477
+ simple?: components["schemas"]["B2SimpleUpload"];
478
+ large?: components["schemas"]["B2LargeUpload"];
479
+ };
441
480
  IGetBinaryUploadUrlResponse: {
442
- message: string;
481
+ /** @description Temporary upload path in uploads/ folder for TUS upload */
443
482
  path: string;
444
- token: string;
483
+ /** @description Temporary upload path (same as path) */
484
+ tempPath: string;
485
+ /** @description Final path where file will be moved after upload completes */
486
+ finalPath: string;
487
+ /** @description Upload ID */
445
488
  id: string;
489
+ /** @description Backblaze upload strategy if configured */
490
+ b2?: components["schemas"]["B2UploadStrategy"];
491
+ /** @description Signed upload URL token for legacy clients (deprecated) */
492
+ token?: string;
446
493
  };
447
494
  ICheckForExistingUploadArgs: {
448
495
  sha: string;
@@ -452,12 +499,45 @@ export interface components {
452
499
  exists: boolean;
453
500
  };
454
501
  IFinaliseUploadArgs: {
502
+ /** @description File metadata (bundle ID, package name, platform) - required for new clients */
503
+ metadata?: Record<string, never>;
504
+ /** @description SHA-256 hash of the file - required for new clients */
505
+ sha?: string;
506
+ /**
507
+ * @description Whether the Supabase upload was successful
508
+ * @default true
509
+ */
510
+ supabaseSuccess: boolean;
511
+ /**
512
+ * @description Whether the Backblaze upload was successful
513
+ * @default false
514
+ */
515
+ backblazeSuccess: boolean;
516
+ /** @description Whether client uses TUS resumable uploads (true for new clients, undefined/false for legacy) */
517
+ useTus?: boolean;
455
518
  id: string;
456
519
  path: string;
457
- metadata: Record<string, never>;
458
- sha: string;
459
520
  };
460
521
  IFinaliseUploadResponse: Record<string, never>;
522
+ IFinishLargeFileArgs: {
523
+ /**
524
+ * @description The Backblaze file ID from the large file upload
525
+ * @example abc123xyz
526
+ */
527
+ fileId: string;
528
+ /**
529
+ * @description Array of SHA1 hashes for each uploaded part
530
+ * @example [
531
+ * "sha1hash1",
532
+ * "sha1hash2"
533
+ * ]
534
+ */
535
+ partSha1Array: string[];
536
+ };
537
+ IFinishLargeFileResponse: {
538
+ success: boolean;
539
+ result: Record<string, never>;
540
+ };
461
541
  ICreateTestUploadArgs: {
462
542
  /**
463
543
  * Format: binary
@@ -644,6 +724,32 @@ export interface operations {
644
724
  };
645
725
  };
646
726
  };
727
+ UploadsController_finishLargeFile: {
728
+ parameters: {
729
+ query?: never;
730
+ header: {
731
+ "x-app-api-key": string;
732
+ };
733
+ path?: never;
734
+ cookie?: never;
735
+ };
736
+ requestBody: {
737
+ content: {
738
+ "application/json": components["schemas"]["IFinishLargeFileArgs"];
739
+ };
740
+ };
741
+ responses: {
742
+ /** @description The large file upload has been completed. */
743
+ 201: {
744
+ headers: {
745
+ [name: string]: unknown;
746
+ };
747
+ content: {
748
+ "application/json": components["schemas"]["IFinishLargeFileResponse"];
749
+ };
750
+ };
751
+ };
752
+ };
647
753
  UploadsController_createTest: {
648
754
  parameters: {
649
755
  query?: never;
@@ -1139,10 +1245,11 @@ export interface operations {
1139
1245
  * "1.41.0",
1140
1246
  * "2.0.2",
1141
1247
  * "2.0.3",
1142
- * "2.0.4"
1248
+ * "2.0.4",
1249
+ * "2.0.9"
1143
1250
  * ],
1144
1251
  * "defaultVersion": "1.41.0",
1145
- * "latestVersion": "2.0.4"
1252
+ * "latestVersion": "2.0.9"
1146
1253
  * }
1147
1254
  * }
1148
1255
  * }
@@ -168,12 +168,6 @@
168
168
  "allowNo": false,
169
169
  "type": "boolean"
170
170
  },
171
- "skip-chrome-onboarding": {
172
- "description": "[Android only] Skip Chrome browser onboarding screens when running tests",
173
- "name": "skip-chrome-onboarding",
174
- "allowNo": false,
175
- "type": "boolean"
176
- },
177
171
  "env": {
178
172
  "char": "e",
179
173
  "description": "One or more environment variables to inject into your flows",
@@ -572,5 +566,5 @@
572
566
  ]
573
567
  }
574
568
  },
575
- "version": "4.1.6"
569
+ "version": "4.1.9-beta.0"
576
570
  }
package/package.json CHANGED
@@ -7,6 +7,7 @@
7
7
  "@oclif/core": "^3.27.0",
8
8
  "@oclif/plugin-help": "^6.2.36",
9
9
  "@supabase/supabase-js": "^2.81.1",
10
+ "@types/tus-js-client": "^2.1.0",
10
11
  "app-info-parser": "^1.1.6",
11
12
  "archiver": "^7.0.1",
12
13
  "bplist-parser": "^0.3.2",
@@ -14,7 +15,8 @@
14
15
  "glob": "^11.1.0",
15
16
  "js-yaml": "^4.1.1",
16
17
  "node-stream-zip": "^1.15.0",
17
- "plist": "^3.1.0"
18
+ "plist": "^3.1.0",
19
+ "tus-js-client": "^4.3.1"
18
20
  },
19
21
  "description": "Better cloud maestro testing",
20
22
  "devDependencies": {
@@ -66,7 +68,7 @@
66
68
  "type": "git",
67
69
  "url": "https://devicecloud.dev"
68
70
  },
69
- "version": "4.1.6",
71
+ "version": "4.1.9-beta.0",
70
72
  "bugs": {
71
73
  "url": "https://discord.gg/gm3mJwcNw8"
72
74
  },