eas-cli 18.7.0 → 18.8.1

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.
Files changed (49) hide show
  1. package/README.md +147 -90
  2. package/build/build/utils/url.d.ts +6 -0
  3. package/build/build/utils/url.js +9 -0
  4. package/build/channel/insights/formatInsights.d.ts +47 -0
  5. package/build/channel/insights/formatInsights.js +108 -0
  6. package/build/commands/channel/insights.d.ts +18 -0
  7. package/build/commands/channel/insights.js +71 -0
  8. package/build/commands/observe/events.d.ts +1 -0
  9. package/build/commands/observe/events.js +17 -4
  10. package/build/commands/observe/metrics.d.ts +1 -0
  11. package/build/commands/observe/metrics.js +18 -6
  12. package/build/commands/observe/versions.d.ts +1 -0
  13. package/build/commands/observe/versions.js +17 -4
  14. package/build/commands/simulator/start.d.ts +16 -0
  15. package/build/commands/simulator/start.js +203 -0
  16. package/build/commands/update/insights.d.ts +19 -0
  17. package/build/commands/update/insights.js +75 -0
  18. package/build/commands/update/view.d.ts +4 -0
  19. package/build/commands/update/view.js +47 -2
  20. package/build/credentials/ios/appstore/capabilityIdentifiers.js +28 -3
  21. package/build/graphql/client.d.ts +13 -0
  22. package/build/graphql/client.js +36 -1
  23. package/build/graphql/generated.d.ts +318 -0
  24. package/build/graphql/generated.js +21 -3
  25. package/build/graphql/mutations/DeviceRunSessionMutation.d.ts +5 -0
  26. package/build/graphql/mutations/DeviceRunSessionMutation.js +34 -0
  27. package/build/graphql/queries/ChannelInsightsQuery.d.ts +12 -0
  28. package/build/graphql/queries/ChannelInsightsQuery.js +81 -0
  29. package/build/graphql/queries/DeviceRunSessionQuery.d.ts +5 -0
  30. package/build/graphql/queries/DeviceRunSessionQuery.js +28 -0
  31. package/build/graphql/queries/UpdateInsightsQuery.d.ts +10 -0
  32. package/build/graphql/queries/UpdateInsightsQuery.js +53 -0
  33. package/build/graphql/types/Observe.js +1 -0
  34. package/build/insights/formatTimespan.d.ts +7 -0
  35. package/build/insights/formatTimespan.js +15 -0
  36. package/build/insights/timeRange.d.ts +10 -0
  37. package/build/insights/timeRange.js +10 -0
  38. package/build/metadata/apple/tasks/previews.js +41 -15
  39. package/build/observe/formatEvents.d.ts +3 -0
  40. package/build/observe/formatEvents.js +4 -0
  41. package/build/observe/formatMetrics.d.ts +3 -2
  42. package/build/observe/formatMetrics.js +16 -27
  43. package/build/observe/formatVersions.js +2 -8
  44. package/build/update/insights/formatInsights.d.ts +34 -0
  45. package/build/update/insights/formatInsights.js +128 -0
  46. package/build/utils/renderTextTable.d.ts +6 -0
  47. package/build/utils/renderTextTable.js +23 -0
  48. package/oclif.manifest.json +995 -593
  49. package/package.json +5 -5
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const core_1 = require("@oclif/core");
5
+ const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
6
+ const flags_1 = require("../../commandUtils/flags");
7
+ const UpdateInsightsQuery_1 = require("../../graphql/queries/UpdateInsightsQuery");
8
+ const timeRange_1 = require("../../insights/timeRange");
9
+ const log_1 = tslib_1.__importDefault(require("../../log"));
10
+ const formatInsights_1 = require("../../update/insights/formatInsights");
11
+ const json_1 = require("../../utils/json");
12
+ class UpdateInsights extends EasCommand_1.default {
13
+ static description = 'display launch, crash, unique-user, and size insights for an update group';
14
+ static args = {
15
+ groupId: core_1.Args.string({
16
+ required: true,
17
+ description: 'The ID of an update group.',
18
+ }),
19
+ };
20
+ static flags = {
21
+ platform: core_1.Flags.option({
22
+ description: 'Filter to a single platform.',
23
+ options: ['ios', 'android'],
24
+ })(),
25
+ days: core_1.Flags.integer({
26
+ description: `Show insights from the last N days (default ${timeRange_1.INSIGHTS_DEFAULT_DAYS_BACK}, mutually exclusive with --start/--end).`,
27
+ min: 1,
28
+ exclusive: ['start', 'end'],
29
+ }),
30
+ start: core_1.Flags.string({
31
+ description: 'Start of insights time range (ISO date).',
32
+ exclusive: ['days'],
33
+ }),
34
+ end: core_1.Flags.string({
35
+ description: 'End of insights time range (ISO date).',
36
+ exclusive: ['days'],
37
+ }),
38
+ ...flags_1.EasNonInteractiveAndJsonFlags,
39
+ };
40
+ static contextDefinition = {
41
+ ...this.ContextOptions.LoggedIn,
42
+ };
43
+ async runAsync() {
44
+ const { args: { groupId }, flags, } = await this.parse(UpdateInsights);
45
+ const { json, nonInteractive } = (0, flags_1.resolveNonInteractiveAndJsonFlags)(flags);
46
+ const { loggedIn: { graphqlClient }, } = await this.getContextAsync(UpdateInsights, { nonInteractive });
47
+ if (json) {
48
+ (0, json_1.enableJsonOutput)();
49
+ }
50
+ const { daysBack, startTime, endTime } = (0, timeRange_1.resolveInsightsTimeRange)(flags);
51
+ const allUpdates = await UpdateInsightsQuery_1.UpdateInsightsQuery.viewUpdateGroupInsightsAsync(graphqlClient, {
52
+ groupId,
53
+ startTime,
54
+ endTime,
55
+ });
56
+ const updates = flags.platform
57
+ ? allUpdates.filter(u => u.platform === flags.platform)
58
+ : allUpdates;
59
+ if (updates.length === 0) {
60
+ throw new Error(`Update group "${groupId}" has no ${flags.platform} update (available platforms: ${allUpdates
61
+ .map(u => u.platform)
62
+ .sort()
63
+ .join(', ')}).`);
64
+ }
65
+ const summary = (0, formatInsights_1.toUpdateInsightsSummary)(groupId, updates, { startTime, endTime, daysBack });
66
+ if (json) {
67
+ (0, json_1.printJsonOnlyOutput)((0, formatInsights_1.buildUpdateInsightsJson)(summary));
68
+ }
69
+ else {
70
+ log_1.default.addNewLineIfNone();
71
+ log_1.default.log((0, formatInsights_1.buildUpdateInsightsTable)(summary));
72
+ }
73
+ }
74
+ }
75
+ exports.default = UpdateInsights;
@@ -6,6 +6,10 @@ export default class UpdateView extends EasCommand {
6
6
  };
7
7
  static flags: {
8
8
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ insights: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ days: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ start: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ end: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
13
  };
10
14
  static contextDefinition: {
11
15
  loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
@@ -5,8 +5,11 @@ const core_1 = require("@oclif/core");
5
5
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
6
  const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
7
7
  const flags_1 = require("../../commandUtils/flags");
8
+ const UpdateInsightsQuery_1 = require("../../graphql/queries/UpdateInsightsQuery");
8
9
  const UpdateQuery_1 = require("../../graphql/queries/UpdateQuery");
10
+ const timeRange_1 = require("../../insights/timeRange");
9
11
  const log_1 = tslib_1.__importDefault(require("../../log"));
12
+ const formatInsights_1 = require("../../update/insights/formatInsights");
10
13
  const utils_1 = require("../../update/utils");
11
14
  const json_1 = require("../../utils/json");
12
15
  class UpdateView extends EasCommand_1.default {
@@ -18,25 +21,67 @@ class UpdateView extends EasCommand_1.default {
18
21
  }),
19
22
  };
20
23
  static flags = {
24
+ insights: core_1.Flags.boolean({
25
+ description: 'Also show insights (launches, crash rate, unique users, payload size) for the update group.',
26
+ default: false,
27
+ }),
28
+ days: core_1.Flags.integer({
29
+ description: 'Show insights from the last N days (default 7). Only used with --insights.',
30
+ min: 1,
31
+ exclusive: ['start', 'end'],
32
+ }),
33
+ start: core_1.Flags.string({
34
+ description: 'Start of insights time range (ISO date). Only used with --insights.',
35
+ exclusive: ['days'],
36
+ }),
37
+ end: core_1.Flags.string({
38
+ description: 'End of insights time range (ISO date). Only used with --insights.',
39
+ exclusive: ['days'],
40
+ }),
21
41
  ...flags_1.EasJsonOnlyFlag,
22
42
  };
23
43
  static contextDefinition = {
24
44
  ...this.ContextOptions.LoggedIn,
25
45
  };
26
46
  async runAsync() {
27
- const { args: { groupId }, flags: { json: jsonFlag }, } = await this.parse(UpdateView);
47
+ const { args: { groupId }, flags: { json: jsonFlag, insights: insightsFlag, days, start, end }, } = await this.parse(UpdateView);
48
+ if (!insightsFlag && (days !== undefined || start !== undefined || end !== undefined)) {
49
+ throw new Error('--days, --start, and --end can only be used with --insights.');
50
+ }
28
51
  const { loggedIn: { graphqlClient }, } = await this.getContextAsync(UpdateView, { nonInteractive: true });
29
52
  if (jsonFlag) {
30
53
  (0, json_1.enableJsonOutput)();
31
54
  }
32
55
  const updatesByGroup = await UpdateQuery_1.UpdateQuery.viewUpdateGroupAsync(graphqlClient, { groupId });
56
+ let insightsSummary = null;
57
+ if (insightsFlag) {
58
+ const { daysBack, startTime, endTime } = (0, timeRange_1.resolveInsightsTimeRange)({ days, start, end });
59
+ const updatesWithInsights = await UpdateInsightsQuery_1.UpdateInsightsQuery.viewUpdateGroupInsightsAsync(graphqlClient, { groupId, startTime, endTime });
60
+ insightsSummary = (0, formatInsights_1.toUpdateInsightsSummary)(groupId, updatesWithInsights, {
61
+ startTime,
62
+ endTime,
63
+ daysBack,
64
+ });
65
+ }
33
66
  if (jsonFlag) {
34
- (0, json_1.printJsonOnlyOutput)((0, utils_1.getUpdateJsonInfosForUpdates)(updatesByGroup));
67
+ if (insightsSummary) {
68
+ (0, json_1.printJsonOnlyOutput)({
69
+ updates: (0, utils_1.getUpdateJsonInfosForUpdates)(updatesByGroup),
70
+ insights: (0, formatInsights_1.buildUpdateInsightsJson)(insightsSummary),
71
+ });
72
+ }
73
+ else {
74
+ (0, json_1.printJsonOnlyOutput)((0, utils_1.getUpdateJsonInfosForUpdates)(updatesByGroup));
75
+ }
35
76
  }
36
77
  else {
37
78
  const [updateGroupDescription] = (0, utils_1.getUpdateGroupDescriptions)([updatesByGroup]);
38
79
  log_1.default.log(chalk_1.default.bold('Update group:'));
39
80
  log_1.default.log((0, utils_1.formatUpdateGroup)(updateGroupDescription));
81
+ if (insightsSummary) {
82
+ log_1.default.addNewLineIfNone();
83
+ log_1.default.log((0, formatInsights_1.buildUpdateInsightsTable)(insightsSummary));
84
+ }
40
85
  }
41
86
  }
42
87
  }
@@ -34,6 +34,19 @@ async function syncCapabilityIdentifiersForEntitlementsAsync(bundleId, entitleme
34
34
  // these are only APPLE_PAY, ICLOUD, APP_GROUPS
35
35
  const CapabilityIdMapping = capabilityList_1.CapabilityMapping.filter(capability => capability.capabilityIdModel);
36
36
  const updateRequest = [];
37
+ // Fetch the bundle with its linked capability identifiers to check for already linked identifiers.
38
+ const bundleWithRelationships = await apple_utils_1.BundleId.infoAsync(bundleId.context, {
39
+ id: bundleId.id,
40
+ query: {
41
+ includes: [
42
+ 'bundleIdCapabilities',
43
+ 'bundleIdCapabilities.appGroups',
44
+ 'bundleIdCapabilities.merchantIds',
45
+ 'bundleIdCapabilities.cloudContainers',
46
+ ],
47
+ },
48
+ });
49
+ const linkedBundleCapabilities = bundleWithRelationships.attributes.bundleIdCapabilities ?? [];
37
50
  // Iterate through the supported capabilities to build the request.
38
51
  for (const classifier of CapabilityIdMapping) {
39
52
  const CapabilityModel = classifier.capabilityIdModel;
@@ -57,12 +70,24 @@ async function syncCapabilityIdentifiersForEntitlementsAsync(bundleId, entitleme
57
70
  const capabilityIds = [...new Set(entitlementValue)];
58
71
  // Get a list of all of the capability IDs that are already created on the server.
59
72
  const existingIds = await CapabilityModel.getAsync(bundleId.context);
73
+ // Opaque ids of identifiers already linked to this capability.
74
+ const remoteLinkedIds = linkedBundleCapabilities.find(c => c.isType(classifier.capability))
75
+ ?.attributes;
76
+ const alreadyLinkedOpaqueIds = new Set((remoteLinkedIds?.[CapabilityModel.type] ?? []).map(model => model.id));
60
77
  // A list of server IDs for linking.
61
78
  const capabilityIdOpaqueIds = [];
62
- const capabilitiesWithoutRemoteModels = capabilityIds.filter(localId => existingIds.find(model => model.attributes.identifier === localId) === undefined);
63
79
  // Iterate through all the local IDs and see if they exist on the server.
64
- for (const localId of capabilitiesWithoutRemoteModels) {
65
- let remoteIdModel = undefined;
80
+ for (const localId of capabilityIds) {
81
+ let remoteIdModel = existingIds.find(model => model.attributes.identifier === localId);
82
+ // Identifier already exists.
83
+ if (remoteIdModel) {
84
+ if (!alreadyLinkedOpaqueIds.has(remoteIdModel.id)) {
85
+ // Link the existing identifier to this bundle.
86
+ linkedIds.push(remoteIdModel.attributes.identifier);
87
+ capabilityIdOpaqueIds.push(remoteIdModel.id);
88
+ }
89
+ continue;
90
+ }
66
91
  if (log_1.default.isDebug) {
67
92
  log_1.default.log(`Creating capability ID: ${localId} (${CapabilityModel.type})`);
68
93
  }
@@ -1,3 +1,16 @@
1
1
  import { CombinedError as GraphqlError, OperationResult } from '@urql/core';
2
+ export declare const EAS_CLI_UPGRADE_REQUIRED_ERROR_CODE = "EAS_CLI_UPGRADE_REQUIRED";
2
3
  export declare function withErrorHandlingAsync<T>(promise: Promise<OperationResult<T>>): Promise<T>;
4
+ /**
5
+ * Wraps `withErrorHandlingAsync` for queries that hit endpoints which may evolve in
6
+ * ways that require a newer eas-cli. The server signals this by returning a GraphQL
7
+ * error with `extensions.errorCode === EAS_CLI_UPGRADE_REQUIRED`. As a fallback we
8
+ * also detect schema validation errors of the form `Cannot query field "X" on type "Y"`,
9
+ * which surface when a field has been removed without a coded error.
10
+ *
11
+ * In either case we re-throw an `EasCommandError` instructing the user to upgrade.
12
+ */
13
+ export declare function withUpgradeRequiredErrorHandlingAsync<T>(promise: Promise<OperationResult<T>>, { featureName }: {
14
+ featureName: string;
15
+ }): Promise<T>;
3
16
  export { GraphqlError };
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GraphqlError = void 0;
3
+ exports.GraphqlError = exports.EAS_CLI_UPGRADE_REQUIRED_ERROR_CODE = void 0;
4
4
  exports.withErrorHandlingAsync = withErrorHandlingAsync;
5
+ exports.withUpgradeRequiredErrorHandlingAsync = withUpgradeRequiredErrorHandlingAsync;
5
6
  const tslib_1 = require("tslib");
6
7
  const core_1 = require("@urql/core");
7
8
  Object.defineProperty(exports, "GraphqlError", { enumerable: true, get: function () { return core_1.CombinedError; } });
9
+ const errors_1 = require("../commandUtils/errors");
8
10
  const log_1 = tslib_1.__importDefault(require("../log"));
11
+ exports.EAS_CLI_UPGRADE_REQUIRED_ERROR_CODE = 'EAS_CLI_UPGRADE_REQUIRED';
9
12
  async function withErrorHandlingAsync(promise) {
10
13
  const { data, error } = await promise;
11
14
  if (error) {
@@ -25,3 +28,35 @@ async function withErrorHandlingAsync(promise) {
25
28
  }
26
29
  return data;
27
30
  }
31
+ /**
32
+ * Wraps `withErrorHandlingAsync` for queries that hit endpoints which may evolve in
33
+ * ways that require a newer eas-cli. The server signals this by returning a GraphQL
34
+ * error with `extensions.errorCode === EAS_CLI_UPGRADE_REQUIRED`. As a fallback we
35
+ * also detect schema validation errors of the form `Cannot query field "X" on type "Y"`,
36
+ * which surface when a field has been removed without a coded error.
37
+ *
38
+ * In either case we re-throw an `EasCommandError` instructing the user to upgrade.
39
+ */
40
+ async function withUpgradeRequiredErrorHandlingAsync(promise, { featureName }) {
41
+ try {
42
+ return await withErrorHandlingAsync(promise);
43
+ }
44
+ catch (error) {
45
+ if (isUpgradeRequiredError(error)) {
46
+ throw new errors_1.EasCommandError(`${featureName} is not supported by this version of eas-cli. ` +
47
+ `Upgrade to the latest version: \`npm install -g eas-cli@latest\`.`);
48
+ }
49
+ throw error;
50
+ }
51
+ }
52
+ function isUpgradeRequiredError(error) {
53
+ if (!(error instanceof core_1.CombinedError)) {
54
+ return false;
55
+ }
56
+ return error.graphQLErrors.some(e => {
57
+ if (e?.extensions?.errorCode === exports.EAS_CLI_UPGRADE_REQUIRED_ERROR_CODE) {
58
+ return true;
59
+ }
60
+ return /Cannot query field ".+" on type ".+"/.test(e?.message ?? '');
61
+ });
62
+ }