diff --git a/CHANGELOG.md b/CHANGELOG.md index 563d33bd8f..ce61d17598 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This is the log of notable changes to EAS CLI and related packages. ### 🎉 New features - [eas-cli] Add Supabase integration foundation: GraphQL client, shared integration helpers, and provisioning utilities. ([#4130](https://github.com/expo/eas-cli/pull/4130) by [@gwdp](https://github.com/gwdp)) +- [eas-cli] Add an opt-in `--max-idle-time-minutes` flag to `eas simulator`; the session stops automatically after that many minutes without activity. ([#4156](https://github.com/expo/eas-cli/pull/4156) by [@szdziedzic](https://github.com/szdziedzic)) ### 🐛 Bug fixes diff --git a/packages/eas-cli/graphql.schema.json b/packages/eas-cli/graphql.schema.json index fb7139ef99..a0509464ea 100644 --- a/packages/eas-cli/graphql.schema.json +++ b/packages/eas-cli/graphql.schema.json @@ -14561,6 +14561,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "latestExpoSdkVersion", + "description": "Highest Expo SDK version seen in telemetry over the trailing 30 days; null when none was reported.", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "navigationRoutes", "description": null, @@ -14804,7 +14816,7 @@ }, { "name": "uniqueActiveUserCount", - "description": "Approximate count of unique users (`eas_client_id`) with at least one\nsupported-metric event in `[startTime, endTime)`. Uses ClickHouse's\nHyperLogLog `uniq()`, so the value can drift by a small percent on apps\nwith very large user bases. `metricNames` on the input is currently\nignored: the count is always over all supported metrics, matching the\nuniverse used by `appVersions` headline counts.", + "description": "Approximate count of unique users (`eas_client_id`) with at least one\nsupported-metric event in `[startTime, endTime)`. Uses a ClickHouse\nHyperLogLog sketch, so the value can drift by a small percent on apps\nwith very large user bases. `metricNames` on the input is currently\nignored: the count is always over all supported metrics, matching the\nuniverse used by `appVersions` headline counts.", "args": [ { "name": "input", @@ -25838,7 +25850,7 @@ "fields": [ { "name": "createAppleDeviceRegistrationRequest", - "description": "Create an Apple Device registration request", + "description": "Create an Apple Device registration request.\nPass singleUse to create a fresh request that closes after the first device is registered.", "args": [ { "name": "accountId", @@ -25871,6 +25883,18 @@ "defaultValue": null, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "singleUse", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null } ], "type": { @@ -30898,6 +30922,18 @@ "isDeprecated": true, "deprecationReason": "Use 'resolvedImage' for the concrete image the build runs on." }, + { + "name": "sshSession", + "description": "The active ssh session for this build, if any.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "TurtleSshSession", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "status", "description": null, @@ -33048,6 +33084,51 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "generateLogsCentrifugoSubscriptionToken", + "description": "Generate a token for subscribing to an EAS Build log channel", + "args": [ + { + "name": "buildId", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "thread", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "RealtimeLogsCentrifugoSubscriptionToken", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "retryAndroidBuild", "description": "Retry an Android EAS Build", @@ -33543,6 +33624,12 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "SSH_SESSION", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "START_BUILD", "description": null, @@ -36380,6 +36467,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "maxIdleTimeMinutes", + "description": "Stop the session automatically after this many minutes without observed\nsession activity. Must be positive and smaller than the session's maximum\nduration (2 hours, or maxRunTimeMinutes when set). Only supported for\nagent-device and argent sessions. If omitted, the session has no idle\ntimeout.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "maxRunTimeMinutes", "description": "Override for the underlying turtle job run's max run time, in minutes. Must\nbe non-negative and smaller than 120 (2 hours). Only customizable on paid\nplans. If omitted, the default is derived based on the job run's priority.", @@ -41992,6 +42091,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "maxIdleTimeMinutes", + "description": "Number of minutes without observed session activity after which the session\nis stopped automatically. Null when the session has no idle timeout.", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "name", "description": "Human-readable label chosen by whoever started the session. Null when the\nsession was started without one.", @@ -58647,6 +58758,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "sshSession", + "description": "The active ssh session for this job run, if any.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "TurtleSshSession", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "startedAt", "description": null, @@ -58792,49 +58915,6 @@ "enumValues": null, "possibleTypes": null }, - { - "kind": "OBJECT", - "name": "JobRunLogsCentrifugoSubscriptionToken", - "description": null, - "fields": [ - { - "name": "channel", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "token", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, { "kind": "OBJECT", "name": "JobRunMutation", @@ -58911,7 +58991,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "JobRunLogsCentrifugoSubscriptionToken", + "name": "RealtimeLogsCentrifugoSubscriptionToken", "ofType": null } }, @@ -63965,6 +64045,49 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "RealtimeLogsCentrifugoSubscriptionToken", + "description": null, + "fields": [ + { + "name": "channel", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "token", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "RealtimeLogsMutation", @@ -66335,6 +66458,22 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "turtleSshSession", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "TurtleSshSessionMutation", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "update", "description": null, @@ -73613,38 +73752,27 @@ }, { "kind": "OBJECT", - "name": "UniqueUsersOverTimeData", - "description": null, + "name": "TurtleSshConnectionConfig", + "description": "Everything a client needs to open the ssh connection, reported by the worker once it has dialed\nthe relay. Reading this decrypts the connection secret, so it is gated at account PUBLISH.", "fields": [ { - "name": "data", + "name": "host", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "LineChartData", + "kind": "SCALAR", + "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Update", - "description": null, - "fields": [ + }, { - "name": "activityTimestamp", + "name": "reconnecting", "description": null, "args": [], "type": { @@ -73652,7 +73780,7 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "DateTime", + "name": "Boolean", "ofType": null } }, @@ -73660,113 +73788,552 @@ "deprecationReason": null }, { - "name": "actor", + "name": "secret", "description": null, "args": [], "type": { - "kind": "INTERFACE", - "name": "Actor", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "app", + "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "App", + "kind": "ENUM", + "name": "TurtleSshTransportType", "ofType": null } }, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "TurtleSshConnectionConfigInput", + "description": null, + "fields": null, + "inputFields": [ { - "name": "assetHostOverride", + "name": "host", "description": null, - "args": [], "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } }, + "defaultValue": null, "isDeprecated": false, "deprecationReason": null }, { - "name": "assetMapUrl", + "name": "reconnecting", "description": null, - "args": [], "type": { "kind": "SCALAR", - "name": "String", + "name": "Boolean", "ofType": null }, + "defaultValue": null, "isDeprecated": false, "deprecationReason": null }, { - "name": "awaitingCodeSigningInfo", + "name": "secret", "description": null, - "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", - "name": "Boolean", + "name": "String", "ofType": null } }, + "defaultValue": null, "isDeprecated": false, "deprecationReason": null }, { - "name": "branch", + "name": "type", "description": null, - "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "UpdateBranch", + "kind": "ENUM", + "name": "TurtleSshTransportType", "ofType": null } }, + "defaultValue": null, "isDeprecated": false, "deprecationReason": null - }, + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "TurtleSshSession", + "description": null, + "fields": [ { - "name": "branchId", + "name": "build", "description": null, "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } + "kind": "OBJECT", + "name": "Build", + "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "codeSigningInfo", + "name": "connectionConfig", "description": null, "args": [], "type": { - "kind": "OBJECT", - "name": "CodeSigningInfo", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "TurtleSshConnectionConfig", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdAt", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "initiatingActor", + "description": null, + "args": [], + "type": { + "kind": "INTERFACE", + "name": "Actor", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "jobRun", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "JobRun", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "sessionSettings", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "TurtleSshSessionSettings", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "updatedAt", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "TurtleSshSessionMutation", + "description": null, + "fields": [ + { + "name": "createOrUpdateTurtleSshSession", + "description": null, + "args": [ + { + "name": "connectionConfig", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "TurtleSshConnectionConfigInput", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "sessionSettings", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "TurtleSshSessionSettingsInput", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "turtleBuildId", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "turtleJobRunId", + "description": null, + "type": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "TurtleSshSession", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "TurtleSshSessionSettings", + "description": null, + "fields": [ + { + "name": "idleTimeoutSeconds", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "TurtleSshSessionSettingsInput", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "idleTimeoutSeconds", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "TurtleSshTransportType", + "description": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "UPTERM_V1", + "description": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "UniqueUsersOverTimeData", + "description": null, + "fields": [ + { + "name": "data", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "LineChartData", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Update", + "description": null, + "fields": [ + { + "name": "activityTimestamp", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "actor", + "description": null, + "args": [], + "type": { + "kind": "INTERFACE", + "name": "Actor", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "app", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "App", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "assetHostOverride", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "assetMapUrl", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "awaitingCodeSigningInfo", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "branch", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "UpdateBranch", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "branchId", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "codeSigningInfo", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "CodeSigningInfo", + "ofType": null }, "isDeprecated": false, "deprecationReason": null @@ -91470,6 +92037,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "skipReason", + "description": "Why the server skipped this job without running it. Null for jobs that\nwere not skipped and for jobs created before the reason was recorded.", + "args": [], + "type": { + "kind": "UNION", + "name": "WorkflowJobSkipReason", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "status", "description": null, @@ -91555,7 +92134,219 @@ "deprecationReason": null }, { - "name": "workflowRun", + "name": "workflowRun", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "WorkflowRun", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "WorkflowJobAppleDeviceRegistrationRequestMutation", + "description": null, + "fields": [ + { + "name": "approveAppleDeviceRegistration", + "description": "Mark the workflow apple-device-registration-request job successful after reviewing the registered device.", + "args": [ + { + "name": "appleDeviceId", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "workflowJobId", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "WorkflowJob", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "rejectAppleDeviceRegistration", + "description": "Fail the workflow apple-device-registration-request job after reviewing the registered device.", + "args": [ + { + "name": "appleDeviceId", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "workflowJobId", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "WorkflowJob", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "WorkflowJobApproval", + "description": null, + "fields": [ + { + "name": "createdAt", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "decision", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "WorkflowJobReviewDecision", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "reviewingActor", + "description": null, + "args": [], + "type": { + "kind": "INTERFACE", + "name": "Actor", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "updatedAt", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "DateTime", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "workflowJob", "description": null, "args": [], "type": { @@ -91563,7 +92354,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "WorkflowRun", + "name": "WorkflowJob", "ofType": null } }, @@ -91578,71 +92369,22 @@ }, { "kind": "OBJECT", - "name": "WorkflowJobAppleDeviceRegistrationRequestMutation", + "name": "WorkflowJobApprovalMutation", "description": null, "fields": [ { - "name": "approveAppleDeviceRegistration", - "description": "Mark the workflow apple-device-registration-request job successful after reviewing the registered device.", - "args": [ - { - "name": "appleDeviceId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "workflowJobId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "WorkflowJob", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "rejectAppleDeviceRegistration", - "description": "Fail the workflow apple-device-registration-request job after reviewing the registered device.", + "name": "setWorkflowJobApprovalDecision", + "description": null, "args": [ { - "name": "appleDeviceId", + "name": "decision", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "ID", + "kind": "ENUM", + "name": "WorkflowJobReviewDecision", "ofType": null } }, @@ -91672,7 +92414,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "WorkflowJob", + "name": "WorkflowJobApproval", "ofType": null } }, @@ -91687,43 +92429,11 @@ }, { "kind": "OBJECT", - "name": "WorkflowJobApproval", + "name": "WorkflowJobError", "description": null, "fields": [ { - "name": "createdAt", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "decision", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "WorkflowJobReviewDecision", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", + "name": "message", "description": null, "args": [], "type": { @@ -91731,7 +92441,7 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "ID", + "name": "String", "ofType": null } }, @@ -91739,19 +92449,7 @@ "deprecationReason": null }, { - "name": "reviewingActor", - "description": null, - "args": [], - "type": { - "kind": "INTERFACE", - "name": "Actor", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", + "name": "title", "description": null, "args": [], "type": { @@ -91759,23 +92457,7 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "workflowJob", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "WorkflowJob", + "name": "String", "ofType": null } }, @@ -91790,29 +92472,13 @@ }, { "kind": "OBJECT", - "name": "WorkflowJobApprovalMutation", + "name": "WorkflowJobQuery", "description": null, "fields": [ { - "name": "setWorkflowJobApprovalDecision", + "name": "byId", "description": null, "args": [ - { - "name": "decision", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "WorkflowJobReviewDecision", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "workflowJobId", "description": null, @@ -91835,7 +92501,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "WorkflowJobApproval", + "name": "WorkflowJob", "ofType": null } }, @@ -91848,13 +92514,57 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "ENUM", + "name": "WorkflowJobReviewDecision", + "description": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "APPROVED", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "REJECTED", + "description": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "UNION", + "name": "WorkflowJobSkipReason", + "description": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "WorkflowJobSkipReasonIfConditionNotMet", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "WorkflowJobSkipReasonUnsuccessfulDependencies", + "ofType": null + } + ] + }, { "kind": "OBJECT", - "name": "WorkflowJobError", + "name": "WorkflowJobSkipReasonDependency", "description": null, "fields": [ { - "name": "message", + "name": "key", "description": null, "args": [], "type": { @@ -91870,7 +92580,7 @@ "deprecationReason": null }, { - "name": "title", + "name": "name", "description": null, "args": [], "type": { @@ -91884,6 +92594,22 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "status", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "WorkflowJobStatus", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -91893,36 +92619,19 @@ }, { "kind": "OBJECT", - "name": "WorkflowJobQuery", + "name": "WorkflowJobSkipReasonIfConditionNotMet", "description": null, "fields": [ { - "name": "byId", - "description": null, - "args": [ - { - "name": "workflowJobId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - } - ], + "name": "condition", + "description": "The job's if expression as written in the workflow YAML.", + "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "OBJECT", - "name": "WorkflowJob", + "kind": "SCALAR", + "name": "String", "ofType": null } }, @@ -91936,26 +92645,38 @@ "possibleTypes": null }, { - "kind": "ENUM", - "name": "WorkflowJobReviewDecision", + "kind": "OBJECT", + "name": "WorkflowJobSkipReasonUnsuccessfulDependencies", "description": null, - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "APPROVED", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, + "fields": [ { - "name": "REJECTED", + "name": "dependencies", "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "WorkflowJobSkipReasonDependency", + "ofType": null + } + } + } + }, "isDeprecated": false, "deprecationReason": null } ], + "inputFields": null, + "interfaces": [], + "enumValues": null, "possibleTypes": null }, { @@ -93088,6 +93809,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "sshSettings", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "WorkflowRunSshSettings", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "status", "description": null, @@ -93711,6 +94444,33 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "WorkflowRunSshSettings", + "description": null, + "fields": [ + { + "name": "idleTimeoutSeconds", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "ENUM", "name": "WorkflowRunStatus", diff --git a/packages/eas-cli/src/commands/simulator/__tests__/index.test.ts b/packages/eas-cli/src/commands/simulator/__tests__/index.test.ts index 3edf61a967..3ca928a850 100644 --- a/packages/eas-cli/src/commands/simulator/__tests__/index.test.ts +++ b/packages/eas-cli/src/commands/simulator/__tests__/index.test.ts @@ -347,6 +347,26 @@ describe(Simulator, () => { }); }); + it('passes --max-idle-time-minutes to the createDeviceRunSession mutation', async () => { + const { command } = createCommand([ + '--platform', + 'ios', + '--non-interactive', + '--max-idle-time-minutes', + '30', + ]); + await command.runAsync(); + + expect(mockCreateDeviceRunSessionAsync).toHaveBeenCalledWith(graphqlClient, { + appId: 'project-123', + name: undefined, + packageVersion: undefined, + platform: AppPlatform.Ios, + type: DeviceRunSessionType.AgentDevice, + maxIdleTimeMinutes: 30, + }); + }); + it(`throws when ${EAS_SIMULATOR_SESSION_ID} is already present with --no-force`, async () => { process.env[EAS_SIMULATOR_SESSION_ID] = 'existing-session'; diff --git a/packages/eas-cli/src/commands/simulator/index.ts b/packages/eas-cli/src/commands/simulator/index.ts index 07842900d8..8075273e89 100644 --- a/packages/eas-cli/src/commands/simulator/index.ts +++ b/packages/eas-cli/src/commands/simulator/index.ts @@ -82,6 +82,11 @@ export default class Simulator extends EasCommand { 'Maximum duration of the simulator session in minutes before it is automatically stopped. Only customizable on paid plans. Defaults to a value derived from the job run priority when omitted.', min: 0, }), + 'max-idle-time-minutes': Flags.integer({ + description: + 'Stop the simulator session automatically after this many minutes without session activity. When omitted, the session has no idle timeout and runs until its maximum duration.', + min: 0, + }), force: Flags.boolean({ description: '[default: true] Create a new simulator session even when an existing simulator session is present in the environment.', @@ -166,6 +171,7 @@ export default class Simulator extends EasCommand { type: DEVICE_RUN_SESSION_TYPE_BY_FLAG_VALUE[flags.type], packageVersion: flags['package-version'], maxRunTimeMinutes: flags['max-duration-minutes'], + maxIdleTimeMinutes: flags['max-idle-time-minutes'], }); deviceRunSessionId = session.id; nullthrows(session.turtleJobRun?.id, 'Expected simulator session to start'); diff --git a/packages/eas-cli/src/graphql/generated.ts b/packages/eas-cli/src/graphql/generated.ts index 91fed12a8e..78384f15b5 100644 --- a/packages/eas-cli/src/graphql/generated.ts +++ b/packages/eas-cli/src/graphql/generated.ts @@ -2151,6 +2151,8 @@ export type AppObserve = { /** Time-bucketed exception counts split into fatal vs non-fatal, for the stacked-bar chart. */ errorTimeSeries: AppObserveErrorTimeSeries; events: AppObserveEventsConnection; + /** Highest Expo SDK version seen in telemetry over the trailing 30 days; null when none was reported. */ + latestExpoSdkVersion?: Maybe; navigationRoutes: AppObserveNavigationRoutesConnection; /** Active users and sessions for the Overview engagement band, across all versions. */ overviewEngagement: AppObserveOverviewEngagement; @@ -2162,8 +2164,8 @@ export type AppObserve = { totalEventCount: Scalars['Int']['output']; /** * Approximate count of unique users (`eas_client_id`) with at least one - * supported-metric event in `[startTime, endTime)`. Uses ClickHouse's - * HyperLogLog `uniq()`, so the value can drift by a small percent on apps + * supported-metric event in `[startTime, endTime)`. Uses a ClickHouse + * HyperLogLog sketch, so the value can drift by a small percent on apps * with very large user bases. `metricNames` on the input is currently * ignored: the count is always over all supported metrics, matching the * universe used by `appVersions` headline counts. @@ -3665,7 +3667,10 @@ export type AppleDeviceRegistrationRequest = { export type AppleDeviceRegistrationRequestMutation = { __typename?: 'AppleDeviceRegistrationRequestMutation'; - /** Create an Apple Device registration request */ + /** + * Create an Apple Device registration request. + * Pass singleUse to create a fresh request that closes after the first device is registered. + */ createAppleDeviceRegistrationRequest: AppleDeviceRegistrationRequest; }; @@ -3673,6 +3678,7 @@ export type AppleDeviceRegistrationRequestMutation = { export type AppleDeviceRegistrationRequestMutationCreateAppleDeviceRegistrationRequestArgs = { accountId: Scalars['ID']['input']; appleTeamId: Scalars['ID']['input']; + singleUse?: InputMaybe; }; /** Publicly visible data for an AppleDeviceRegistrationRequest. */ @@ -4334,6 +4340,8 @@ export type Build = ActivityTimelineProjectActivity & BuildOrBuildJob & { sdkVersion?: Maybe; /** @deprecated Use 'resolvedImage' for the concrete image the build runs on. */ selectedImage?: Maybe; + /** The active ssh session for this build, if any. */ + sshSession?: Maybe; status: BuildStatus; submissions: Array; updateChannel?: Maybe; @@ -4578,6 +4586,8 @@ export type BuildMutation = { createLocalBuild: CreateBuildResult; /** Delete an EAS Build build */ deleteBuild: Build; + /** Generate a token for subscribing to an EAS Build log channel */ + generateLogsCentrifugoSubscriptionToken: RealtimeLogsCentrifugoSubscriptionToken; /** Retry an Android EAS Build */ retryAndroidBuild: Build; /** Retry an iOS EAS Build */ @@ -4621,6 +4631,12 @@ export type BuildMutationDeleteBuildArgs = { }; +export type BuildMutationGenerateLogsCentrifugoSubscriptionTokenArgs = { + buildId: Scalars['ID']['input']; + thread?: InputMaybe; +}; + + export type BuildMutationRetryAndroidBuildArgs = { buildId: Scalars['ID']['input']; jobOverrides?: InputMaybe; @@ -4692,6 +4708,7 @@ export enum BuildPhase { SaveCache = 'SAVE_CACHE', SetUpBuildEnvironment = 'SET_UP_BUILD_ENVIRONMENT', SpinUpBuilder = 'SPIN_UP_BUILDER', + SshSession = 'SSH_SESSION', StartBuild = 'START_BUILD', Unknown = 'UNKNOWN', UploadApplicationArchive = 'UPLOAD_APPLICATION_ARCHIVE', @@ -5095,6 +5112,14 @@ export type CreateDeviceRunSessionEventLogUploadSessionResult = { export type CreateDeviceRunSessionInput = { appId: Scalars['ID']['input']; + /** + * Stop the session automatically after this many minutes without observed + * session activity. Must be positive and smaller than the session's maximum + * duration (2 hours, or maxRunTimeMinutes when set). Only supported for + * agent-device and argent sessions. If omitted, the session has no idle + * timeout. + */ + maxIdleTimeMinutes?: InputMaybe; /** * Override for the underlying turtle job run's max run time, in minutes. Must * be non-negative and smaller than 120 (2 hours). Only customizable on paid @@ -5862,6 +5887,11 @@ export type DeviceRunSession = { finishedAt?: Maybe; id: Scalars['ID']['output']; initiatingActor?: Maybe; + /** + * Number of minutes without observed session activity after which the session + * is stopped automatically. Null when the session has no idle timeout. + */ + maxIdleTimeMinutes?: Maybe; /** * Human-readable label chosen by whoever started the session. Null when the * session was started without one. @@ -8266,6 +8296,8 @@ export type JobRun = { priority: JobRunPriority; /** String describing the worker profile used to run this job run. */ resourceClassDisplayName: Scalars['String']['output']; + /** The active ssh session for this job run, if any. */ + sshSession?: Maybe; startedAt?: Maybe; status: JobRunStatus; updateGroups: Array>; @@ -8280,18 +8312,12 @@ export type JobRunError = { message: Scalars['String']['output']; }; -export type JobRunLogsCentrifugoSubscriptionToken = { - __typename?: 'JobRunLogsCentrifugoSubscriptionToken'; - channel: Scalars['String']['output']; - token: Scalars['String']['output']; -}; - export type JobRunMutation = { __typename?: 'JobRunMutation'; /** Cancel an EAS Job Run */ cancelJobRun: JobRun; /** Generate a token for subscribing to an EAS Job Run log channel */ - generateLogsCentrifugoSubscriptionToken: JobRunLogsCentrifugoSubscriptionToken; + generateLogsCentrifugoSubscriptionToken: RealtimeLogsCentrifugoSubscriptionToken; }; @@ -9041,6 +9067,12 @@ export type RealtimeLogsCentrifugoConnectionToken = { token: Scalars['String']['output']; }; +export type RealtimeLogsCentrifugoSubscriptionToken = { + __typename?: 'RealtimeLogsCentrifugoSubscriptionToken'; + channel: Scalars['String']['output']; + token: Scalars['String']['output']; +}; + export type RealtimeLogsMutation = { __typename?: 'RealtimeLogsMutation'; /** Generate a token for connecting to EAS Logs Centrifugo */ @@ -9340,6 +9372,7 @@ export type RootMutation = { supabaseProject: SupabaseProjectMutation; tunnels: TunnelsMutation; turtleBrownfieldArtifacts: TurtleBrownfieldArtifactMutation; + turtleSshSession: TurtleSshSessionMutation; update: UpdateMutation; updateBranch: UpdateBranchMutation; updateChannel: UpdateChannelMutation; @@ -10388,6 +10421,63 @@ export type TurtleBrownfieldArtifactQueryLatestForAppArgs = { platform: AppPlatform; }; +/** + * Everything a client needs to open the ssh connection, reported by the worker once it has dialed + * the relay. Reading this decrypts the connection secret, so it is gated at account PUBLISH. + */ +export type TurtleSshConnectionConfig = { + __typename?: 'TurtleSshConnectionConfig'; + host: Scalars['String']['output']; + reconnecting: Scalars['Boolean']['output']; + secret: Scalars['String']['output']; + type: TurtleSshTransportType; +}; + +export type TurtleSshConnectionConfigInput = { + host: Scalars['String']['input']; + reconnecting?: InputMaybe; + secret: Scalars['String']['input']; + type: TurtleSshTransportType; +}; + +export type TurtleSshSession = { + __typename?: 'TurtleSshSession'; + build?: Maybe; + connectionConfig: TurtleSshConnectionConfig; + createdAt: Scalars['DateTime']['output']; + id: Scalars['ID']['output']; + initiatingActor?: Maybe; + jobRun?: Maybe; + sessionSettings: TurtleSshSessionSettings; + updatedAt: Scalars['DateTime']['output']; +}; + +export type TurtleSshSessionMutation = { + __typename?: 'TurtleSshSessionMutation'; + createOrUpdateTurtleSshSession: TurtleSshSession; +}; + + +export type TurtleSshSessionMutationCreateOrUpdateTurtleSshSessionArgs = { + connectionConfig: TurtleSshConnectionConfigInput; + sessionSettings: TurtleSshSessionSettingsInput; + turtleBuildId?: InputMaybe; + turtleJobRunId?: InputMaybe; +}; + +export type TurtleSshSessionSettings = { + __typename?: 'TurtleSshSessionSettings'; + idleTimeoutSeconds: Scalars['Int']['output']; +}; + +export type TurtleSshSessionSettingsInput = { + idleTimeoutSeconds: Scalars['Int']['input']; +}; + +export enum TurtleSshTransportType { + UptermV1 = 'UPTERM_V1' +} + export type UniqueUsersOverTimeData = { __typename?: 'UniqueUsersOverTimeData'; data: LineChartData; @@ -12752,6 +12842,11 @@ export type WorkflowJob = { * update_group_id output. Empty for other job types or when the group has no updates. */ rolloutUpdateGroup: Array; + /** + * Why the server skipped this job without running it. Null for jobs that + * were not skipped and for jobs created before the reason was recorded. + */ + skipReason?: Maybe; status: WorkflowJobStatus; turtleBuild?: Maybe; turtleJobRun?: Maybe; @@ -12823,6 +12918,26 @@ export enum WorkflowJobReviewDecision { Rejected = 'REJECTED' } +export type WorkflowJobSkipReason = WorkflowJobSkipReasonIfConditionNotMet | WorkflowJobSkipReasonUnsuccessfulDependencies; + +export type WorkflowJobSkipReasonDependency = { + __typename?: 'WorkflowJobSkipReasonDependency'; + key: Scalars['String']['output']; + name: Scalars['String']['output']; + status: WorkflowJobStatus; +}; + +export type WorkflowJobSkipReasonIfConditionNotMet = { + __typename?: 'WorkflowJobSkipReasonIfConditionNotMet'; + /** The job's if expression as written in the workflow YAML. */ + condition: Scalars['String']['output']; +}; + +export type WorkflowJobSkipReasonUnsuccessfulDependencies = { + __typename?: 'WorkflowJobSkipReasonUnsuccessfulDependencies'; + dependencies: Array; +}; + export enum WorkflowJobStatus { ActionRequired = 'ACTION_REQUIRED', Canceled = 'CANCELED', @@ -12970,6 +13085,7 @@ export type WorkflowRun = ActivityTimelineProjectActivity & { retriedWorkflowRun?: Maybe; retries: Array; sourceExpiresAt?: Maybe; + sshSettings?: Maybe; status: WorkflowRunStatus; triggerEventType: WorkflowRunTriggerEventType; triggeringLabelName?: Maybe; @@ -13057,6 +13173,11 @@ export type WorkflowRunQueryByIdArgs = { workflowRunId: Scalars['ID']['input']; }; +export type WorkflowRunSshSettings = { + __typename?: 'WorkflowRunSshSettings'; + idleTimeoutSeconds: Scalars['Int']['output']; +}; + export enum WorkflowRunStatus { ActionRequired = 'ACTION_REQUIRED', Canceled = 'CANCELED',