@devicecloud.dev/dcd 3.2.2 → 3.3.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.
@@ -50,6 +50,7 @@ export default class Cloud extends Command {
50
50
  'ignore-sha-check': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
51
51
  'ios-device': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
52
52
  'ios-version': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
53
+ 'x86-arch': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
53
54
  'maestro-version': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
54
55
  name: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
55
56
  orientation: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
@@ -38,6 +38,15 @@ var EAndroidDevices;
38
38
  EAndroidDevices["pixel-7"] = "pixel-7";
39
39
  EAndroidDevices["pixel-7-pro"] = "pixel-7-pro";
40
40
  })(EAndroidDevices || (exports.EAndroidDevices = EAndroidDevices = {}));
41
+ // Suppress punycode deprecation warning (caused by whatwg, supabase dependancy)
42
+ process.removeAllListeners('warning');
43
+ process.on('warning', (warning) => {
44
+ if (warning.name === 'DeprecationWarning' &&
45
+ warning.message.includes('punycode')) {
46
+ return;
47
+ }
48
+ console.warn(warning);
49
+ });
41
50
  class Cloud extends core_1.Command {
42
51
  static args = {
43
52
  firstFile: core_1.Args.string({
@@ -62,7 +71,7 @@ class Cloud extends core_1.Command {
62
71
  }
63
72
  await (0, methods_1.versionCheck)(this.config.version);
64
73
  const { args, flags, raw } = await this.parse(Cloud);
65
- const { 'additional-app-binary-ids': nonFlatAdditionalAppBinaryIds, 'additional-app-files': nonFlatAdditionalAppFiles, 'android-api-level': androidApiLevel, 'android-device': androidDevice, apiKey: apiKeyFlag, apiUrl, 'app-binary-id': appBinaryId, 'app-file': appFile, async, 'device-locale': deviceLocale, 'download-artifacts': downloadArtifacts, env, 'exclude-flows': excludeFlows, 'exclude-tags': excludeTags, flows, 'google-play': googlePlay, 'include-tags': includeTags, 'ignore-sha-check': ignoreShaCheck, 'ios-device': iOSDevice, 'ios-version': iOSVersion, 'maestro-version': maestroVersion, name, orientation, quiet, retry, report, ...rest } = flags;
74
+ const { 'additional-app-binary-ids': nonFlatAdditionalAppBinaryIds, 'additional-app-files': nonFlatAdditionalAppFiles, 'android-api-level': androidApiLevel, 'android-device': androidDevice, apiKey: apiKeyFlag, apiUrl, 'app-binary-id': appBinaryId, 'app-file': appFile, async, 'device-locale': deviceLocale, 'download-artifacts': downloadArtifacts, env, 'exclude-flows': excludeFlows, 'exclude-tags': excludeTags, flows, 'google-play': googlePlay, 'include-tags': includeTags, 'ignore-sha-check': ignoreShaCheck, 'ios-device': iOSDevice, 'ios-version': iOSVersion, 'maestro-version': maestroVersion, name, orientation, quiet, retry, report, 'x86-arch': x86Arch, ...rest } = flags;
66
75
  const apiKey = apiKeyFlag || process.env.DEVICE_CLOUD_API_KEY;
67
76
  if (!apiKey)
68
77
  throw new Error('You must provide an API key via --api-key flag or DEVICE_CLOUD_API_KEY environment variable');
@@ -121,9 +130,7 @@ class Cloud extends core_1.Command {
121
130
  executionPlan = await (0, plan_1.plan)(flowFile, includeTags.flat(), excludeTags.flat(), excludeFlows.flat());
122
131
  }
123
132
  catch (error) {
124
- console.error(error);
125
- // eslint-disable-next-line unicorn/no-process-exit
126
- process.exit(2);
133
+ throw error;
127
134
  }
128
135
  const { allExcludeTags, allIncludeTags, flowsToRun: testFileNames, referencedFiles, sequence, workspaceConfig, } = executionPlan;
129
136
  const pathsShortestToLongest = [
@@ -219,6 +226,7 @@ class Cloud extends core_1.Command {
219
226
  deviceLocale,
220
227
  maestroVersion,
221
228
  orientation,
229
+ x86Arch,
222
230
  report,
223
231
  raw: JSON.stringify(raw),
224
232
  uploadedBinaryIds,
@@ -255,91 +263,95 @@ class Cloud extends core_1.Command {
255
263
  const { message, results } = await (0, methods_1.typeSafePost)(apiUrl, '/uploads/flow', options);
256
264
  if (!results?.length)
257
265
  (0, errors_1.error)('No tests created: ' + message);
258
- (0, cli_ux_1.info)(`\nCreated ${results.length} tests: ${results
266
+ this.log(`\nCreated ${results.length} tests: ${results
259
267
  .map((r) => r.test_file_name)
260
268
  .sort((a, b) => a.localeCompare(b))
261
269
  .join(', ')}\n`);
262
- (0, cli_ux_1.info)('Run triggered, you can access the results at:');
270
+ this.log('Run triggered, you can access the results at:');
263
271
  const url = `https://console.devicecloud.dev/results?upload=${results[0].test_upload_id}&result=${results[0].id}`;
264
272
  core_1.ux.url(url, url);
265
273
  if (async) {
266
- (0, cli_ux_1.info)('Not waiting for results as async flag is set to true');
274
+ this.log('Not waiting for results as async flag is set to true');
267
275
  return;
268
276
  }
269
277
  // poll for the run status every 5 seconds
270
278
  core_1.ux.action.start('Waiting for results', 'Initializing', { stdout: true });
271
- (0, cli_ux_1.info)('\nYou can safely close this terminal and the tests will continue\n');
279
+ this.log('\nYou can safely close this terminal and the tests will continue\n');
272
280
  let sequentialPollFaillures = 0;
273
- const intervalId = setInterval(async () => {
274
- try {
275
- const { results: updatedResults } = await (0, methods_1.typeSafeGet)(apiUrl, `/results/${results[0].test_upload_id}`, {
276
- headers: { 'x-app-api-key': apiKey },
277
- });
278
- if (!updatedResults) {
279
- throw new Error('no results');
280
- }
281
- if (!quiet) {
282
- core_1.ux.action.status =
283
- '\nStatus Test\n─────────── ───────────────';
284
- for (const { retry_of: isRetry, status, test_file_name: test, } of updatedResults) {
285
- core_1.ux.action.status += `\n${status.padEnd(10, ' ')} ${test} ${isRetry ? '(retry)' : ''}`;
281
+ await new Promise((resolve, reject) => {
282
+ const intervalId = setInterval(async () => {
283
+ try {
284
+ const { results: updatedResults } = await (0, methods_1.typeSafeGet)(apiUrl, `/results/${results[0].test_upload_id}`, {
285
+ headers: { 'x-app-api-key': apiKey },
286
+ });
287
+ if (!updatedResults) {
288
+ throw new Error('no results');
286
289
  }
287
- }
288
- if (updatedResults.every((result) => !['PENDING', 'RUNNING'].includes(result.status))) {
289
- core_1.ux.action.stop('completed');
290
- (0, cli_ux_1.info)('\n');
291
- (0, cli_ux_1.table)(updatedResults, {
292
- status: { get: (row) => row.status },
293
- test: {
294
- get: (row) => `${row.test_file_name} ${row.retry_of ? '(retry)' : ''}`,
295
- },
296
- }, { printLine: this.log.bind(this) });
297
- (0, cli_ux_1.info)('\n');
298
- (0, cli_ux_1.info)('Run completed, you can access the results at:');
299
- core_1.ux.url(url, url);
300
- (0, cli_ux_1.info)('\n');
301
- clearInterval(intervalId);
302
- if (downloadArtifacts) {
303
- try {
304
- await (0, methods_1.typeSafePostDownload)(apiUrl, `/results/${results[0].test_upload_id}/download`, {
305
- body: JSON.stringify({ results: downloadArtifacts }),
306
- headers: {
307
- 'content-type': 'application/json',
308
- 'x-app-api-key': apiKey,
309
- },
310
- });
311
- (0, cli_ux_1.info)('\n');
312
- (0, cli_ux_1.info)('Test artifacts have been downloaded to ./artifacts.zip');
313
- }
314
- catch {
315
- this.warn('Failed to download artifacts');
290
+ if (!quiet) {
291
+ core_1.ux.action.status =
292
+ '\nStatus Test\n─────────── ───────────────';
293
+ for (const { retry_of: isRetry, status, test_file_name: test, } of updatedResults) {
294
+ core_1.ux.action.status += `\n${status.padEnd(10, ' ')} ${test} ${isRetry ? '(retry)' : ''}`;
316
295
  }
317
296
  }
318
- const resultsWithoutEarlierTries = updatedResults.filter((result) => {
319
- const beenRetried = updatedResults.find((r) => r.retry_of === result.id);
320
- return !beenRetried;
321
- });
322
- if (resultsWithoutEarlierTries.some((result) => result.status === 'FAILED')) {
323
- // eslint-disable-next-line unicorn/no-process-exit
324
- process.exit(2);
297
+ if (updatedResults.every((result) => !['PENDING', 'RUNNING'].includes(result.status))) {
298
+ core_1.ux.action.stop('completed');
299
+ this.log('\n');
300
+ (0, cli_ux_1.table)(updatedResults, {
301
+ status: { get: (row) => row.status },
302
+ test: {
303
+ get: (row) => `${row.test_file_name} ${row.retry_of ? '(retry)' : ''}`,
304
+ },
305
+ }, { printLine: this.log.bind(this) });
306
+ this.log('\n');
307
+ this.log('Run completed, you can access the results at:');
308
+ core_1.ux.url(url, url);
309
+ this.log('\n');
310
+ clearInterval(intervalId);
311
+ if (downloadArtifacts) {
312
+ try {
313
+ await (0, methods_1.typeSafePostDownload)(apiUrl, `/results/${results[0].test_upload_id}/download`, {
314
+ body: JSON.stringify({ results: downloadArtifacts }),
315
+ headers: {
316
+ 'content-type': 'application/json',
317
+ 'x-app-api-key': apiKey,
318
+ },
319
+ });
320
+ this.log('\n');
321
+ this.log('Test artifacts have been downloaded to ./artifacts.zip');
322
+ }
323
+ catch {
324
+ this.warn('Failed to download artifacts');
325
+ }
326
+ }
327
+ const resultsWithoutEarlierTries = updatedResults.filter((result) => {
328
+ const beenRetried = updatedResults.find((r) => r.retry_of === result.id);
329
+ return !beenRetried;
330
+ });
331
+ if (resultsWithoutEarlierTries.some((result) => result.status === 'FAILED')) {
332
+ reject(new Error('RUN_FAILED'));
333
+ }
334
+ sequentialPollFaillures = 0;
335
+ resolve();
325
336
  }
326
- sequentialPollFaillures = 0;
327
337
  }
328
- }
329
- catch {
330
- sequentialPollFaillures++;
331
- if (sequentialPollFaillures > 5) {
332
- // dropped poll requests shouldn't err user CI
333
- clearInterval(intervalId);
334
- throw new Error('unable to fetch results');
338
+ catch (error) {
339
+ sequentialPollFaillures++;
340
+ if (sequentialPollFaillures > 5) {
341
+ // dropped poll requests shouldn't err user CI
342
+ clearInterval(intervalId);
343
+ throw new Error('unable to fetch results after 5 attempts');
344
+ }
345
+ this.log('unable to fetch results, trying again...');
335
346
  }
336
- (0, cli_ux_1.info)('unable to fetch results, trying again...');
337
- }
338
- }, 5000);
347
+ }, 5000);
348
+ });
339
349
  }
340
350
  catch (error) {
341
- console.error(error);
342
- (0, cli_ux_1.exit)(1);
351
+ if (error instanceof Error && error.message === 'RUN_FAILED') {
352
+ this.exit(2);
353
+ }
354
+ this.error(error, { exit: 1 });
343
355
  }
344
356
  }
345
357
  }
@@ -0,0 +1,14 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Status extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
7
+ name: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ 'upload-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ apiKey: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ apiUrl: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ };
12
+ private getStatusSymbol;
13
+ run(): Promise<void>;
14
+ }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const constants_1 = require("../constants");
5
+ const methods_1 = require("../methods");
6
+ class Status extends core_1.Command {
7
+ static description = 'Get the status of an upload by name or upload ID';
8
+ static examples = [
9
+ '<%= config.bin %> <%= command.id %> --name my-upload-name',
10
+ '<%= config.bin %> <%= command.id %> --upload-id 123e4567-e89b-12d3-a456-426614174000 --json',
11
+ ];
12
+ static flags = {
13
+ json: core_1.Flags.boolean({
14
+ description: 'output in json format',
15
+ }),
16
+ name: core_1.Flags.string({
17
+ description: 'Name of the upload to check status for',
18
+ exclusive: ['upload-id'],
19
+ }),
20
+ 'upload-id': core_1.Flags.string({
21
+ description: 'UUID of the upload to check status for',
22
+ exclusive: ['name'],
23
+ }),
24
+ apiKey: constants_1.flags.apiKey,
25
+ apiUrl: constants_1.flags.apiUrl,
26
+ };
27
+ getStatusSymbol(status) {
28
+ switch (status) {
29
+ case 'SUCCESS':
30
+ return '✓';
31
+ case 'FAILED':
32
+ return '✗';
33
+ case 'CANCELED':
34
+ return '⊘';
35
+ case 'PENDING':
36
+ return '⋯';
37
+ default:
38
+ return '?';
39
+ }
40
+ }
41
+ async run() {
42
+ const { flags } = await this.parse(Status);
43
+ const { apiUrl, apiKey, name, 'upload-id': uploadId } = flags;
44
+ if (!apiKey) {
45
+ this.error('API Key is required. Please provide it via --api-key flag or DEVICE_CLOUD_API_KEY environment variable.');
46
+ return;
47
+ }
48
+ if (!name && !uploadId) {
49
+ this.error('Either --name or --upload-id must be provided');
50
+ return;
51
+ }
52
+ try {
53
+ const status = await (0, methods_1.getUploadStatus)(apiUrl, apiKey, {
54
+ name,
55
+ uploadId,
56
+ });
57
+ if (flags.json) {
58
+ this.log(JSON.stringify(status, null, 2));
59
+ }
60
+ else {
61
+ this.log('\nUpload Status:');
62
+ this.log('─'.repeat(50));
63
+ status.forEach((item) => {
64
+ const symbol = this.getStatusSymbol(item.status);
65
+ this.log(`\n${symbol} Flow: ${item.name}`);
66
+ this.log(` Status: ${item.status}`);
67
+ this.log('─'.repeat(50));
68
+ });
69
+ this.log(''); // Add empty line at the end
70
+ }
71
+ }
72
+ catch (error) {
73
+ this.error(`Failed to get status: ${error.message}`);
74
+ }
75
+ }
76
+ }
77
+ exports.default = Status;
@@ -20,6 +20,7 @@ export declare const flags: {
20
20
  'ignore-sha-check': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
21
21
  'ios-device': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
22
22
  'ios-version': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
23
+ 'x86-arch': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
23
24
  'maestro-version': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
24
25
  name: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
25
26
  orientation: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
package/dist/constants.js CHANGED
@@ -122,17 +122,16 @@ exports.flags = {
122
122
  description: '[iOS only] iOS version to run your flow against',
123
123
  options: ['16', '17', '18'],
124
124
  }),
125
+ 'x86-arch': core_1.Flags.boolean({
126
+ description: '[iOS only, experimental] Run your flow against x86 architecture simulator instead of arm64',
127
+ default: false,
128
+ }),
125
129
  'maestro-version': core_1.Flags.string({
126
130
  aliases: ['maestroVersion'],
127
131
  default: '1.39.5',
128
132
  description: 'Maestro version to run your flow against',
129
133
  options: [
130
134
  '1.36.0',
131
- '1.37.0',
132
- '1.37.1',
133
- '1.37.2',
134
- '1.37.3',
135
- '1.37.4',
136
135
  '1.37.5',
137
136
  '1.37.6',
138
137
  '1.37.7',
package/dist/methods.d.ts CHANGED
@@ -14,10 +14,10 @@ export declare const typeSafeGet: <T extends keyof paths>(baseUrl: string, path:
14
14
  body?: FormData;
15
15
  headers?: HeadersInit;
16
16
  }) => Promise<paths[T]["get"]["responses"]["200"]["content"]["application/json"]>;
17
- export declare const toBuffer: (archive: archiver.Archiver) => Promise<Buffer>;
18
- export declare const compressDir: (sourceDir: string) => Promise<Buffer>;
17
+ export declare const toBuffer: (archive: archiver.Archiver) => Promise<Buffer<ArrayBuffer>>;
18
+ export declare const compressDir: (sourceDir: string) => Promise<Buffer<ArrayBuffer>>;
19
19
  export declare const compressFolderToBlob: (sourceDir: string) => Promise<Blob>;
20
- export declare const compressFilesFromRelativePath: (path: string, files: string[], commonRoot: string) => Promise<Buffer>;
20
+ export declare const compressFilesFromRelativePath: (path: string, files: string[], commonRoot: string) => Promise<Buffer<ArrayBuffer>>;
21
21
  export declare const verifyAppZip: (zipPath: string) => Promise<void>;
22
22
  export declare const extractAppMetadataAndroid: (appFilePath: string) => Promise<TAppMetadata>;
23
23
  export declare const extractAppMetadataIosZip: (appFilePath: string) => Promise<TAppMetadata>;
@@ -25,3 +25,10 @@ export declare const extractAppMetadataIos: (appFolderPath: string) => Promise<T
25
25
  export declare const uploadBinary: (filePath: string, apiUrl: string, apiKey: string, ignoreShaCheck?: boolean) => Promise<string>;
26
26
  export declare const uploadBinaries: (finalAppFiles: string[], apiUrl: string, apiKey: string, ignoreShaCheck?: boolean) => Promise<string[]>;
27
27
  export declare const verifyAdditionalAppFiles: (appFiles: string[] | undefined) => Promise<void>;
28
+ export declare const getUploadStatus: (apiUrl: string, apiKey: string, options: {
29
+ uploadId?: string;
30
+ name?: string;
31
+ }) => Promise<{
32
+ name: string;
33
+ status: "SUCCESS" | "FAILED" | "CANCELED" | "PENDING";
34
+ }[]>;
package/dist/methods.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.verifyAdditionalAppFiles = exports.uploadBinaries = exports.uploadBinary = exports.extractAppMetadataIos = exports.extractAppMetadataIosZip = exports.extractAppMetadataAndroid = exports.verifyAppZip = exports.compressFilesFromRelativePath = exports.compressFolderToBlob = exports.compressDir = exports.toBuffer = exports.typeSafeGet = exports.typeSafePostDownload = exports.typeSafePost = exports.versionCheck = void 0;
3
+ exports.getUploadStatus = exports.verifyAdditionalAppFiles = exports.uploadBinaries = exports.uploadBinary = exports.extractAppMetadataIos = exports.extractAppMetadataIosZip = exports.extractAppMetadataAndroid = exports.verifyAppZip = exports.compressFilesFromRelativePath = exports.compressFolderToBlob = exports.compressDir = exports.toBuffer = exports.typeSafeGet = exports.typeSafePostDownload = exports.typeSafePost = exports.versionCheck = void 0;
4
4
  const core_1 = require("@oclif/core");
5
5
  const supabase_js_1 = require("@supabase/supabase-js");
6
6
  // required polyfill for node 18
@@ -33,7 +33,7 @@ const versionCheck = async (currentVersion) => {
33
33
  const versionResponseJson = await versionResponse.json();
34
34
  const latestVersion = versionResponseJson.version;
35
35
  if (latestVersion !== currentVersion) {
36
- core_1.ux.warn(`
36
+ console.log(`
37
37
  -------------------
38
38
  A new version of the devicecloud.dev CLI is available: ${latestVersion}
39
39
  Run 'npm install -g @devicecloud.dev/dcd@latest' to update to the latest version
@@ -272,16 +272,16 @@ const uploadBinary = async (filePath, apiUrl, apiKey, ignoreShaCheck = false) =>
272
272
  // this needs to made nicer by using envs or maybe fetching the keys from the getSignedURL call
273
273
  const SB = {
274
274
  dev: {
275
- SUPABASE_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImxibXNvd2VodGp3bnFsdXJwZW1iIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDkyMTg0ODcsImV4cCI6MjAyNDc5NDQ4N30.zeLTMAuZ_WwYvGdeP0kdvL_Zrs-RQee5APPyxmWq7qQ',
275
+ SUPABASE_PUBLIC_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImxibXNvd2VodGp3bnFsdXJwZW1iIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDkyMTg0ODcsImV4cCI6MjAyNDc5NDQ4N30.zeLTMAuZ_WwYvGdeP0kdvL_Zrs-RQee5APPyxmWq7qQ',
276
276
  SUPABASE_URL: 'https://lbmsowehtjwnqlurpemb.supabase.co',
277
277
  },
278
278
  prod: {
279
- SUPABASE_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBneWRucGhiaW1ldGluc2dma2JvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDc1OTQzNDYsImV4cCI6MjAyMzE3MDM0Nn0.hAYOMFxxwX1exkQkY9xyQJGC_GhGnyogkj2N-kBkMI8',
279
+ SUPABASE_PUBLIC_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBneWRucGhiaW1ldGluc2dma2JvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDc1OTQzNDYsImV4cCI6MjAyMzE3MDM0Nn0.hAYOMFxxwX1exkQkY9xyQJGC_GhGnyogkj2N-kBkMI8',
280
280
  SUPABASE_URL: 'https://pgydnphbimetinsgfkbo.supabase.co',
281
281
  },
282
282
  };
283
- const { SUPABASE_KEY, SUPABASE_URL } = SB[apiUrl === 'https://api.devicecloud.dev' ? 'prod' : 'dev'];
284
- const supabase = (0, supabase_js_1.createClient)(SUPABASE_URL, SUPABASE_KEY);
283
+ const { SUPABASE_PUBLIC_KEY, SUPABASE_URL } = SB[apiUrl === 'https://api.devicecloud.dev' ? 'prod' : 'dev'];
284
+ const supabase = (0, supabase_js_1.createClient)(SUPABASE_URL, SUPABASE_PUBLIC_KEY);
285
285
  const uploadToUrl = await supabase.storage
286
286
  .from('organizations')
287
287
  .uploadToSignedUrl(path, token, file);
@@ -337,3 +337,22 @@ async function getFileHashFromFile(file) {
337
337
  processChunks();
338
338
  });
339
339
  }
340
+ const getUploadStatus = async (apiUrl, apiKey, options) => {
341
+ const queryParams = new URLSearchParams();
342
+ if (options.uploadId) {
343
+ queryParams.append('uploadId', options.uploadId);
344
+ }
345
+ if (options.name) {
346
+ queryParams.append('name', options.name);
347
+ }
348
+ const response = await fetch(`${apiUrl}/uploads/status?${queryParams}`, {
349
+ headers: {
350
+ 'x-app-api-key': apiKey,
351
+ },
352
+ });
353
+ if (!response.ok) {
354
+ throw new Error(`Failed to fetch status: ${response.statusText}`);
355
+ }
356
+ return response.json();
357
+ };
358
+ exports.getUploadStatus = getUploadStatus;
@@ -227,6 +227,12 @@
227
227
  ],
228
228
  "type": "option"
229
229
  },
230
+ "x86-arch": {
231
+ "description": "[iOS only, experimental] Run your flow against x86 architecture simulator instead of arm64",
232
+ "name": "x86-arch",
233
+ "allowNo": false,
234
+ "type": "boolean"
235
+ },
230
236
  "maestro-version": {
231
237
  "aliases": [
232
238
  "maestroVersion"
@@ -238,11 +244,6 @@
238
244
  "multiple": false,
239
245
  "options": [
240
246
  "1.36.0",
241
- "1.37.0",
242
- "1.37.1",
243
- "1.37.2",
244
- "1.37.3",
245
- "1.37.4",
246
247
  "1.37.5",
247
248
  "1.37.6",
248
249
  "1.37.7",
@@ -321,7 +322,81 @@
321
322
  "commands",
322
323
  "cloud.js"
323
324
  ]
325
+ },
326
+ "status": {
327
+ "aliases": [],
328
+ "args": {},
329
+ "description": "Get the status of an upload by name or upload ID",
330
+ "examples": [
331
+ "<%= config.bin %> <%= command.id %> --name my-upload-name",
332
+ "<%= config.bin %> <%= command.id %> --upload-id 123e4567-e89b-12d3-a456-426614174000 --json"
333
+ ],
334
+ "flags": {
335
+ "json": {
336
+ "description": "output in json format",
337
+ "name": "json",
338
+ "allowNo": false,
339
+ "type": "boolean"
340
+ },
341
+ "name": {
342
+ "description": "Name of the upload to check status for",
343
+ "exclusive": [
344
+ "upload-id"
345
+ ],
346
+ "name": "name",
347
+ "hasDynamicHelp": false,
348
+ "multiple": false,
349
+ "type": "option"
350
+ },
351
+ "upload-id": {
352
+ "description": "UUID of the upload to check status for",
353
+ "exclusive": [
354
+ "name"
355
+ ],
356
+ "name": "upload-id",
357
+ "hasDynamicHelp": false,
358
+ "multiple": false,
359
+ "type": "option"
360
+ },
361
+ "apiKey": {
362
+ "aliases": [
363
+ "api-key"
364
+ ],
365
+ "description": "API key for devicecloud.dev (find this in the console UI). You can also set the DEVICE_CLOUD_API_KEY environment variable.",
366
+ "name": "apiKey",
367
+ "hasDynamicHelp": false,
368
+ "multiple": false,
369
+ "type": "option"
370
+ },
371
+ "apiUrl": {
372
+ "aliases": [
373
+ "api-url",
374
+ "apiURL"
375
+ ],
376
+ "description": "API base URL",
377
+ "hidden": true,
378
+ "name": "apiUrl",
379
+ "default": "https://api.devicecloud.dev",
380
+ "hasDynamicHelp": false,
381
+ "multiple": false,
382
+ "type": "option"
383
+ }
384
+ },
385
+ "hasDynamicHelp": false,
386
+ "hiddenAliases": [],
387
+ "id": "status",
388
+ "pluginAlias": "@devicecloud.dev/dcd",
389
+ "pluginName": "@devicecloud.dev/dcd",
390
+ "pluginType": "core",
391
+ "strict": true,
392
+ "enableJsonFlag": false,
393
+ "isESM": false,
394
+ "relativePath": [
395
+ "dist",
396
+ "commands",
397
+ "status.js"
398
+ ]
324
399
  }
325
400
  },
326
- "version": "3.2.2"
401
+ "version": "3.3.0"
327
402
  }
package/package.json CHANGED
@@ -80,7 +80,7 @@
80
80
  "test": "mocha --forbid-only \"test/**/*.test.ts\"",
81
81
  "version": "oclif readme && git add README.md"
82
82
  },
83
- "version": "3.2.2",
83
+ "version": "3.3.0",
84
84
  "bugs": {
85
85
  "url": "https://discord.gg/gm3mJwcNw8"
86
86
  },