mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-15 03:38:08 -10:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcc7201ca8 | ||
|
|
bf3f259bc4 | ||
|
|
1a573679e5 | ||
|
|
bb589f1d36 |
No files matched your search
@@ -8,10 +8,13 @@ This is the log of notable changes to EAS CLI and related packages.
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- [eas-cli] Add experimental `eas simulator:events` command. ([#4001](https://github.com/expo/eas-cli/pull/4001) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- [build-tools] Collect and upload Argent tool-server session events during remote simulator sessions, mirroring agent-device event collection. ([#4067](https://github.com/expo/eas-cli/pull/4067) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- [eas-cli] Add `--name` to `eas simulator:start` and show simulator session names in `eas simulator:get` and `eas simulator:list`. ([#4099](https://github.com/expo/eas-cli/pull/4099) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- [eas-cli] Apply --session-id in observe:events summary mode. ([#4100](https://github.com/expo/eas-cli/pull/4100) by [@douglowder](https://github.com/douglowder))
|
||||
- [eas-cli] Suggest running `agent-device` via `npx` in EAS Simulator session instructions. ([#4070](https://github.com/expo/eas-cli/pull/4070) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"npmClient": "yarn",
|
||||
"version": "21.3.0",
|
||||
"version": "21.4.0",
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/build-tools",
|
||||
"version": "21.3.0",
|
||||
"version": "21.4.0",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "BUSL-1.1",
|
||||
"author": "Expo <[email protected]>",
|
||||
@@ -39,14 +39,14 @@
|
||||
"@expo/config": "55.0.10",
|
||||
"@expo/config-plugins": "55.0.7",
|
||||
"@expo/downloader": "21.0.0",
|
||||
"@expo/eas-build-job": "21.3.0",
|
||||
"@expo/eas-build-job": "21.4.0",
|
||||
"@expo/env": "^0.4.0",
|
||||
"@expo/logger": "21.0.0",
|
||||
"@expo/package-manager": "1.9.10",
|
||||
"@expo/plist": "^0.3.5",
|
||||
"@expo/results": "^1.0.0",
|
||||
"@expo/spawn-async": "1.7.2",
|
||||
"@expo/steps": "21.3.0",
|
||||
"@expo/steps": "21.4.0",
|
||||
"@expo/template-file": "21.0.2",
|
||||
"@expo/turtle-spawn": "21.0.0",
|
||||
"@expo/xcpretty": "^4.3.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-eas-build-function",
|
||||
"version": "21.3.0",
|
||||
"version": "21.4.0",
|
||||
"description": "Create functions for use in EAS Build custom builds.",
|
||||
"keywords": [
|
||||
"expo",
|
||||
@@ -35,7 +35,7 @@
|
||||
"clean": "rimraf ./build/ \"*.tsbuildinfo\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/steps": "21.3.0"
|
||||
"@expo/steps": "21.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@expo/package-manager": "1.9.10",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/eas-build-job",
|
||||
"version": "21.3.0",
|
||||
"version": "21.4.0",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "MIT",
|
||||
"author": "Expo <[email protected]>",
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { DeviceRunSessionEvent, parseDeviceRunSessionEvents } from '../deviceRunSession';
|
||||
|
||||
describe('parseDeviceRunSessionEvents', () => {
|
||||
it('parses, deduplicates, and sorts events from the dedicated event log', () => {
|
||||
const first = createEvent({
|
||||
eventId: 'first',
|
||||
ts: '2026-07-10T12:00:00.000Z',
|
||||
});
|
||||
const second = createEvent({
|
||||
eventId: 'second',
|
||||
ts: '2026-07-10T12:00:01.000Z',
|
||||
});
|
||||
|
||||
expect(
|
||||
parseDeviceRunSessionEvents(`${second}\nplain text\n${first}\n${second}`).map(
|
||||
({ eventId }) => eventId
|
||||
)
|
||||
).toEqual(['first', 'second']);
|
||||
});
|
||||
|
||||
it('ignores malformed events', () => {
|
||||
expect(parseDeviceRunSessionEvents(`plain text\n${JSON.stringify({ v: 1 })}`)).toEqual([]);
|
||||
});
|
||||
|
||||
it('ignores events with invalid timestamps', () => {
|
||||
expect(
|
||||
parseDeviceRunSessionEvents(
|
||||
`${createEvent({ eventId: 'invalid', ts: 'not-a-date' })}\n${createEvent({
|
||||
eventId: 'valid',
|
||||
})}`
|
||||
).map(({ eventId }) => eventId)
|
||||
).toEqual(['valid']);
|
||||
});
|
||||
});
|
||||
|
||||
function createEvent(overrides: Partial<DeviceRunSessionEvent> = {}): string {
|
||||
return JSON.stringify(createEventValue(overrides));
|
||||
}
|
||||
|
||||
function createEventValue(overrides: Partial<DeviceRunSessionEvent> = {}): DeviceRunSessionEvent {
|
||||
return {
|
||||
v: 1,
|
||||
eventId: 'event-id',
|
||||
ts: '2026-07-10T12:00:00.000Z',
|
||||
producer: 'agent-device',
|
||||
type: 'operation.started',
|
||||
summary: 'Started tap',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* Canonical record format for the activity events emitted during a remote device run (simulator)
|
||||
* session. Producers (e.g. the worker and agent-device) write these as NDJSON to the
|
||||
* session-events artifact and consumers (e.g. EAS CLI and the website) read them back. Keep this
|
||||
* schema in sync across every producer and consumer.
|
||||
*/
|
||||
export const DeviceRunSessionEventZ = z
|
||||
.object({
|
||||
v: z.literal(1),
|
||||
eventId: z.string(),
|
||||
ts: z.string().refine(ts => !Number.isNaN(new Date(ts).getTime())),
|
||||
producer: z.string(),
|
||||
type: z.string(),
|
||||
operationId: z.string().optional(),
|
||||
outcome: z.enum(['success', 'failure']).optional(),
|
||||
durationMs: z.number().optional(),
|
||||
summary: z.string(),
|
||||
data: z.record(z.string(), z.unknown()).optional(),
|
||||
})
|
||||
.passthrough();
|
||||
|
||||
export type DeviceRunSessionEvent = z.infer<typeof DeviceRunSessionEventZ>;
|
||||
|
||||
/**
|
||||
* Parse the NDJSON session-events log into canonical event records, de-duplicating by `eventId`
|
||||
* and sorting chronologically by `ts`. Malformed or incomplete lines (including records with
|
||||
* invalid timestamps) are ignored so that a partially-flushed log is still readable.
|
||||
*/
|
||||
export function parseDeviceRunSessionEvents(eventLog: string): DeviceRunSessionEvent[] {
|
||||
const events = new Map<string, DeviceRunSessionEvent>();
|
||||
|
||||
for (const line of eventLog.split('\n')) {
|
||||
try {
|
||||
const result = DeviceRunSessionEventZ.safeParse(JSON.parse(line));
|
||||
if (result.success) {
|
||||
events.set(result.data.eventId, result.data);
|
||||
}
|
||||
} catch {
|
||||
// Ignore malformed or incomplete records.
|
||||
}
|
||||
}
|
||||
|
||||
return [...events.values()].sort(
|
||||
(left, right) => new Date(left.ts).getTime() - new Date(right.ts).getTime()
|
||||
);
|
||||
}
|
||||
@@ -29,6 +29,7 @@ export * from './step';
|
||||
export * from './compositeFunction';
|
||||
export * from './submission-config';
|
||||
export * from './projectPackage';
|
||||
export * from './deviceRunSession';
|
||||
|
||||
const version = require('../package.json').version;
|
||||
export { version };
|
||||
+124
-121
@@ -272,7 +272,7 @@ DESCRIPTION
|
||||
view the audit logs for an account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/audit.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/account/audit.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/account/audit.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/account/audit.ts)_
|
||||
|
||||
## `eas account:login`
|
||||
|
||||
@@ -293,7 +293,7 @@ ALIASES
|
||||
$ eas login
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/account/login.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/account/login.ts)_
|
||||
|
||||
## `eas account:logout`
|
||||
|
||||
@@ -310,7 +310,7 @@ ALIASES
|
||||
$ eas logout
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/account/logout.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/account/logout.ts)_
|
||||
|
||||
## `eas account:usage [ACCOUNT_NAME]`
|
||||
|
||||
@@ -332,7 +332,7 @@ DESCRIPTION
|
||||
view account usage and billing for the current cycle
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/usage.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/account/usage.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/account/usage.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/account/usage.ts)_
|
||||
|
||||
## `eas account:view`
|
||||
|
||||
@@ -349,7 +349,7 @@ ALIASES
|
||||
$ eas whoami
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/account/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/account/view.ts)_
|
||||
|
||||
## `eas analytics [STATUS]`
|
||||
|
||||
@@ -363,7 +363,7 @@ DESCRIPTION
|
||||
display or change analytics settings
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/analytics.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/analytics.ts)_
|
||||
|
||||
## `eas autocomplete [SHELL]`
|
||||
|
||||
@@ -394,7 +394,7 @@ EXAMPLES
|
||||
$ eas autocomplete --refresh-cache
|
||||
```
|
||||
|
||||
_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.2.40/packages/eas-cli/src/commands/autocomplete/index.ts)_
|
||||
_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.2.40/src/commands/autocomplete/index.ts)_
|
||||
|
||||
## `eas branch:create [NAME]`
|
||||
|
||||
@@ -415,7 +415,7 @@ DESCRIPTION
|
||||
create a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/branch/create.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/branch/create.ts)_
|
||||
|
||||
## `eas branch:delete [NAME]`
|
||||
|
||||
@@ -436,7 +436,7 @@ DESCRIPTION
|
||||
delete a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/branch/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/branch/delete.ts)_
|
||||
|
||||
## `eas branch:list`
|
||||
|
||||
@@ -456,7 +456,7 @@ DESCRIPTION
|
||||
list all branches
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/branch/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/branch/list.ts)_
|
||||
|
||||
## `eas branch:rename`
|
||||
|
||||
@@ -476,7 +476,7 @@ DESCRIPTION
|
||||
rename a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/branch/rename.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/branch/rename.ts)_
|
||||
|
||||
## `eas branch:view [NAME]`
|
||||
|
||||
@@ -499,7 +499,7 @@ DESCRIPTION
|
||||
view a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/branch/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/branch/view.ts)_
|
||||
|
||||
## `eas browse [PAGE]`
|
||||
|
||||
@@ -522,7 +522,7 @@ DESCRIPTION
|
||||
Transition from the terminal to the web browser to view and interact with your project on https://expo.dev
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/browse.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/browse.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/browse.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/browse.ts)_
|
||||
|
||||
## `eas build`
|
||||
|
||||
@@ -563,7 +563,7 @@ DESCRIPTION
|
||||
start a build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/index.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/index.ts)_
|
||||
|
||||
## `eas build:cancel [BUILD_ID]`
|
||||
|
||||
@@ -583,7 +583,7 @@ DESCRIPTION
|
||||
cancel a build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/cancel.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/cancel.ts)_
|
||||
|
||||
## `eas build:configure`
|
||||
|
||||
@@ -601,7 +601,7 @@ DESCRIPTION
|
||||
configure the project to support EAS Build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/configure.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/configure.ts)_
|
||||
|
||||
## `eas build:delete [BUILD_ID]`
|
||||
|
||||
@@ -621,7 +621,7 @@ DESCRIPTION
|
||||
delete a build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/delete.ts)_
|
||||
|
||||
## `eas build:dev`
|
||||
|
||||
@@ -646,7 +646,7 @@ DESCRIPTION
|
||||
run dev client simulator/emulator build with matching fingerprint or create a new one
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/dev.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/dev.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/dev.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/dev.ts)_
|
||||
|
||||
## `eas build:download`
|
||||
|
||||
@@ -673,7 +673,7 @@ DESCRIPTION
|
||||
download a simulator/emulator build by build ID or fingerprint hash
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/download.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/download.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/download.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/download.ts)_
|
||||
|
||||
## `eas build:inspect`
|
||||
|
||||
@@ -711,7 +711,7 @@ DESCRIPTION
|
||||
inspect the state of the project at specific build stages, useful for troubleshooting
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/inspect.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/inspect.ts)_
|
||||
|
||||
## `eas build:list`
|
||||
|
||||
@@ -751,7 +751,7 @@ DESCRIPTION
|
||||
list all builds for your project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/list.ts)_
|
||||
|
||||
## `eas build:resign`
|
||||
|
||||
@@ -781,7 +781,7 @@ DESCRIPTION
|
||||
re-sign a build archive
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/resign.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/resign.ts)_
|
||||
|
||||
## `eas build:run`
|
||||
|
||||
@@ -809,7 +809,7 @@ DESCRIPTION
|
||||
run simulator/emulator builds from eas-cli
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/run.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/run.ts)_
|
||||
|
||||
## `eas build:submit`
|
||||
|
||||
@@ -861,7 +861,7 @@ DESCRIPTION
|
||||
get the latest version from EAS servers
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/version/get.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/version/get.ts)_
|
||||
|
||||
## `eas build:version:set`
|
||||
|
||||
@@ -879,7 +879,7 @@ DESCRIPTION
|
||||
update version of an app
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/version/set.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/version/set.ts)_
|
||||
|
||||
## `eas build:version:sync`
|
||||
|
||||
@@ -897,7 +897,7 @@ DESCRIPTION
|
||||
update a version in native code with a value stored on EAS servers
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/version/sync.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/version/sync.ts)_
|
||||
|
||||
## `eas build:view [BUILD_ID]`
|
||||
|
||||
@@ -914,7 +914,7 @@ DESCRIPTION
|
||||
view a build for your project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/build/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/build/view.ts)_
|
||||
|
||||
## `eas channel:create [NAME]`
|
||||
|
||||
@@ -935,7 +935,7 @@ DESCRIPTION
|
||||
create a channel
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/channel/create.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/channel/create.ts)_
|
||||
|
||||
## `eas channel:delete [NAME]`
|
||||
|
||||
@@ -956,7 +956,7 @@ DESCRIPTION
|
||||
Delete a channel
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/channel/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/channel/delete.ts)_
|
||||
|
||||
## `eas channel:edit [NAME]`
|
||||
|
||||
@@ -978,7 +978,7 @@ DESCRIPTION
|
||||
point a channel at a new branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/channel/edit.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/channel/edit.ts)_
|
||||
|
||||
## `eas channel:insights`
|
||||
|
||||
@@ -1002,7 +1002,7 @@ DESCRIPTION
|
||||
display adoption, crash, and unique-user insights for a channel + runtime version
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/insights.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/channel/insights.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/insights.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/channel/insights.ts)_
|
||||
|
||||
## `eas channel:list`
|
||||
|
||||
@@ -1022,7 +1022,7 @@ DESCRIPTION
|
||||
list all channels
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/channel/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/channel/list.ts)_
|
||||
|
||||
## `eas channel:pause [NAME]`
|
||||
|
||||
@@ -1044,7 +1044,7 @@ DESCRIPTION
|
||||
pause a channel to stop it from sending updates
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/pause.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/channel/pause.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/pause.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/channel/pause.ts)_
|
||||
|
||||
## `eas channel:resume [NAME]`
|
||||
|
||||
@@ -1066,7 +1066,7 @@ DESCRIPTION
|
||||
resume a channel to start sending updates
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/resume.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/channel/resume.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/resume.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/channel/resume.ts)_
|
||||
|
||||
## `eas channel:rollout [CHANNEL]`
|
||||
|
||||
@@ -1101,7 +1101,7 @@ DESCRIPTION
|
||||
Roll a new branch out on a channel incrementally.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/channel/rollout.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/channel/rollout.ts)_
|
||||
|
||||
## `eas channel:view [NAME]`
|
||||
|
||||
@@ -1124,7 +1124,7 @@ DESCRIPTION
|
||||
view a channel
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/channel/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/channel/view.ts)_
|
||||
|
||||
## `eas config`
|
||||
|
||||
@@ -1145,7 +1145,7 @@ DESCRIPTION
|
||||
display project configuration (app.json + eas.json)
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/config.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/config.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/config.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/config.ts)_
|
||||
|
||||
## `eas credentials`
|
||||
|
||||
@@ -1162,7 +1162,7 @@ DESCRIPTION
|
||||
manage credentials
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/credentials/index.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/credentials/index.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/credentials/index.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/credentials/index.ts)_
|
||||
|
||||
## `eas credentials:configure-build`
|
||||
|
||||
@@ -1180,7 +1180,7 @@ DESCRIPTION
|
||||
Set up credentials for building your project.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/credentials/configure-build.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/credentials/configure-build.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/credentials/configure-build.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/credentials/configure-build.ts)_
|
||||
|
||||
## `eas deploy [options]`
|
||||
|
||||
@@ -1212,7 +1212,7 @@ ALIASES
|
||||
$ eas worker:deploy
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/deploy/index.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/deploy/index.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/deploy/index.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/deploy/index.ts)_
|
||||
|
||||
## `eas deploy:alias`
|
||||
|
||||
@@ -1237,7 +1237,7 @@ ALIASES
|
||||
$ eas deploy:promote
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/deploy/alias/index.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/deploy/alias/index.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/deploy/alias/index.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/deploy/alias/index.ts)_
|
||||
|
||||
## `eas deploy:alias:delete [ALIAS_NAME]`
|
||||
|
||||
@@ -1258,7 +1258,7 @@ ALIASES
|
||||
$ eas worker:alias:delete
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/deploy/alias/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/deploy/alias/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/deploy/alias/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/deploy/alias/delete.ts)_
|
||||
|
||||
## `eas deploy:delete [DEPLOYMENT_ID]`
|
||||
|
||||
@@ -1279,7 +1279,7 @@ ALIASES
|
||||
$ eas worker:delete
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/deploy/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/deploy/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/deploy/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/deploy/delete.ts)_
|
||||
|
||||
## `eas deploy:promote`
|
||||
|
||||
@@ -1316,7 +1316,7 @@ DESCRIPTION
|
||||
register new Apple Devices to use for internal distribution
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/device/create.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/device/create.ts)_
|
||||
|
||||
## `eas device:delete`
|
||||
|
||||
@@ -1336,7 +1336,7 @@ DESCRIPTION
|
||||
remove a registered device from your account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/device/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/device/delete.ts)_
|
||||
|
||||
## `eas device:list`
|
||||
|
||||
@@ -1357,7 +1357,7 @@ DESCRIPTION
|
||||
list all registered devices for your account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/device/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/device/list.ts)_
|
||||
|
||||
## `eas device:rename`
|
||||
|
||||
@@ -1378,7 +1378,7 @@ DESCRIPTION
|
||||
rename a registered device
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/device/rename.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/device/rename.ts)_
|
||||
|
||||
## `eas device:view [UDID]`
|
||||
|
||||
@@ -1392,7 +1392,7 @@ DESCRIPTION
|
||||
view a device for your project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/device/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/device/view.ts)_
|
||||
|
||||
## `eas diagnostics`
|
||||
|
||||
@@ -1406,7 +1406,7 @@ DESCRIPTION
|
||||
display environment info
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/diagnostics.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/diagnostics.ts)_
|
||||
|
||||
## `eas env:delete [ENVIRONMENT]`
|
||||
|
||||
@@ -1432,7 +1432,7 @@ DESCRIPTION
|
||||
delete an environment variable for the current project or account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/env/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/env/delete.ts)_
|
||||
|
||||
## `eas env:exec ENVIRONMENT BASH_COMMAND`
|
||||
|
||||
@@ -1454,7 +1454,7 @@ DESCRIPTION
|
||||
execute a command with environment variables from the selected environment
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/exec.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/env/exec.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/exec.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/env/exec.ts)_
|
||||
|
||||
## `eas env:get [ENVIRONMENT]`
|
||||
|
||||
@@ -1482,7 +1482,7 @@ DESCRIPTION
|
||||
view an environment variable for the current project or account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/get.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/env/get.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/get.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/env/get.ts)_
|
||||
|
||||
## `eas env:list [ENVIRONMENT]`
|
||||
|
||||
@@ -1510,7 +1510,7 @@ DESCRIPTION
|
||||
list environment variables for the current project or account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/list.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/env/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/list.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/env/list.ts)_
|
||||
|
||||
## `eas env:pull [ENVIRONMENT]`
|
||||
|
||||
@@ -1533,7 +1533,7 @@ DESCRIPTION
|
||||
pull environment variables for the selected environment to .env file
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/pull.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/env/pull.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/pull.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/env/pull.ts)_
|
||||
|
||||
## `eas env:push [ENVIRONMENT]`
|
||||
|
||||
@@ -1555,7 +1555,7 @@ DESCRIPTION
|
||||
push environment variables from .env file to the selected environment
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/push.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/env/push.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/push.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/env/push.ts)_
|
||||
|
||||
## `eas env:set [ENVIRONMENT]`
|
||||
|
||||
@@ -1587,7 +1587,7 @@ DESCRIPTION
|
||||
set (create or update) an environment variable on the current project or account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/set.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/env/set.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/set.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/env/set.ts)_
|
||||
|
||||
## `eas fingerprint:compare [HASH1] [HASH2]`
|
||||
|
||||
@@ -1631,7 +1631,7 @@ EXAMPLES
|
||||
$ eas fingerprint:compare <FINGERPRINT-HASH> --update-id <UPDATE-ID> # Compare fingerprint from update against provided fingerprint
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/fingerprint/compare.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/fingerprint/compare.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/fingerprint/compare.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/fingerprint/compare.ts)_
|
||||
|
||||
## `eas fingerprint:generate`
|
||||
|
||||
@@ -1662,7 +1662,7 @@ EXAMPLES
|
||||
$ eas fingerprint:generate --json --non-interactive --platform android # Output fingerprint json to stdout
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/fingerprint/generate.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/fingerprint/generate.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/fingerprint/generate.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/fingerprint/generate.ts)_
|
||||
|
||||
## `eas help [COMMAND]`
|
||||
|
||||
@@ -1682,7 +1682,7 @@ DESCRIPTION
|
||||
Display help for eas.
|
||||
```
|
||||
|
||||
_See code: [@expo/plugin-help](https://github.com/expo/oclif-plugin-help/blob/v5.1.23/packages/eas-cli/src/commands/help.ts)_
|
||||
_See code: [@expo/plugin-help](https://github.com/expo/oclif-plugin-help/blob/v5.1.23/src/commands/help.ts)_
|
||||
|
||||
## `eas init`
|
||||
|
||||
@@ -1736,7 +1736,7 @@ DESCRIPTION
|
||||
connect a project to an App Store Connect app
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/asc/connect.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/asc/connect.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/asc/connect.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/asc/connect.ts)_
|
||||
|
||||
## `eas integrations:asc:disconnect`
|
||||
|
||||
@@ -1755,7 +1755,7 @@ DESCRIPTION
|
||||
disconnect the current project from its App Store Connect app
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/asc/disconnect.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/asc/disconnect.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/asc/disconnect.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/asc/disconnect.ts)_
|
||||
|
||||
## `eas integrations:asc:status`
|
||||
|
||||
@@ -1773,7 +1773,7 @@ DESCRIPTION
|
||||
show the App Store Connect app link status for the current project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/asc/status.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/asc/status.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/asc/status.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/asc/status.ts)_
|
||||
|
||||
## `eas integrations:convex:connect`
|
||||
|
||||
@@ -1795,7 +1795,7 @@ DESCRIPTION
|
||||
connect Convex to your Expo project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/connect.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/convex/connect.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/connect.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/convex/connect.ts)_
|
||||
|
||||
## `eas integrations:convex:dashboard`
|
||||
|
||||
@@ -1809,7 +1809,7 @@ DESCRIPTION
|
||||
open the Convex dashboard for the linked Convex project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/dashboard.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/convex/dashboard.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/dashboard.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/convex/dashboard.ts)_
|
||||
|
||||
## `eas integrations:convex:project`
|
||||
|
||||
@@ -1823,7 +1823,7 @@ DESCRIPTION
|
||||
display the Convex project linked to the current Expo app
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/project.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/convex/project.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/project.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/convex/project.ts)_
|
||||
|
||||
## `eas integrations:convex:project:delete`
|
||||
|
||||
@@ -1841,7 +1841,7 @@ DESCRIPTION
|
||||
remove the Convex project link for the current Expo app from EAS servers
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/project/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/convex/project/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/project/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/convex/project/delete.ts)_
|
||||
|
||||
## `eas integrations:convex:team`
|
||||
|
||||
@@ -1855,7 +1855,7 @@ DESCRIPTION
|
||||
display Convex teams linked to the current Expo app's owner account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/team.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/convex/team.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/team.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/convex/team.ts)_
|
||||
|
||||
## `eas integrations:convex:team:delete [CONVEX_TEAM]`
|
||||
|
||||
@@ -1876,7 +1876,7 @@ DESCRIPTION
|
||||
remove a Convex team link from the current Expo app owner account's EAS servers
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/team/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/convex/team/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/team/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/convex/team/delete.ts)_
|
||||
|
||||
## `eas integrations:convex:team:invite [CONVEX_TEAM]`
|
||||
|
||||
@@ -1896,7 +1896,7 @@ DESCRIPTION
|
||||
send a Convex team invitation to your verified email address
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/team/invite.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/convex/team/invite.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/convex/team/invite.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/convex/team/invite.ts)_
|
||||
|
||||
## `eas integrations:posthog:connect`
|
||||
|
||||
@@ -1923,7 +1923,7 @@ DESCRIPTION
|
||||
connect PostHog to your Expo project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/posthog/connect.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/posthog/connect.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/posthog/connect.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/posthog/connect.ts)_
|
||||
|
||||
## `eas integrations:posthog:dashboard`
|
||||
|
||||
@@ -1943,7 +1943,7 @@ DESCRIPTION
|
||||
open the PostHog dashboard for the linked PostHog project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/posthog/dashboard.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/posthog/dashboard.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/posthog/dashboard.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/posthog/dashboard.ts)_
|
||||
|
||||
## `eas integrations:posthog:disconnect`
|
||||
|
||||
@@ -1962,7 +1962,7 @@ DESCRIPTION
|
||||
remove the PostHog project link for the current Expo app from EAS servers
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/integrations/posthog/disconnect.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/integrations/posthog/disconnect.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/integrations/posthog/disconnect.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/integrations/posthog/disconnect.ts)_
|
||||
|
||||
## `eas login`
|
||||
|
||||
@@ -2014,7 +2014,7 @@ DESCRIPTION
|
||||
validate the local store configuration
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/metadata/lint.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/metadata/lint.ts)_
|
||||
|
||||
## `eas metadata:pull`
|
||||
|
||||
@@ -2032,7 +2032,7 @@ DESCRIPTION
|
||||
generate the local store configuration from the app stores
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/metadata/pull.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/metadata/pull.ts)_
|
||||
|
||||
## `eas metadata:push`
|
||||
|
||||
@@ -2050,7 +2050,7 @@ DESCRIPTION
|
||||
sync the local store configuration to the app stores
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/metadata/push.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/metadata/push.ts)_
|
||||
|
||||
## `eas new [PATH]`
|
||||
|
||||
@@ -2100,7 +2100,8 @@ FLAGS
|
||||
--platform=<option> Filter by platform
|
||||
<options: android|ios>
|
||||
--project-id=<value> EAS project ID (defaults to the project ID of the current directory)
|
||||
--session-id=<value> Filter by session ID
|
||||
--session-id=<value> Filter by session ID. When no event name is given, lists the events in the session instead of
|
||||
the event-name summary.
|
||||
--start=<value> Start of time range (ISO date)
|
||||
--update-id=<value> Filter by EAS update ID
|
||||
|
||||
@@ -2109,7 +2110,7 @@ DESCRIPTION
|
||||
arguments, a list of the available event names and associated event counts is returned.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/observe/events.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/observe/events.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/observe/events.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/observe/events.ts)_
|
||||
|
||||
## `eas observe:metrics [METRIC]`
|
||||
|
||||
@@ -2145,7 +2146,7 @@ DESCRIPTION
|
||||
display individual performance metric samples ordered by value
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/observe/metrics.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/observe/metrics.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/observe/metrics.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/observe/metrics.ts)_
|
||||
|
||||
## `eas observe:metrics-summary`
|
||||
|
||||
@@ -2177,7 +2178,7 @@ DESCRIPTION
|
||||
display aggregated performance metric statistics grouped by app version
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/observe/metrics-summary.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/observe/metrics-summary.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/observe/metrics-summary.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/observe/metrics-summary.ts)_
|
||||
|
||||
## `eas observe:routes`
|
||||
|
||||
@@ -2214,7 +2215,7 @@ DESCRIPTION
|
||||
display app navigation route metrics (Cold TTR, Warm TTR, TTI) grouped by route name
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/observe/routes.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/observe/routes.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/observe/routes.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/observe/routes.ts)_
|
||||
|
||||
## `eas observe:session [SESSIONID]`
|
||||
|
||||
@@ -2245,7 +2246,7 @@ DESCRIPTION
|
||||
display the timeline of metric and log events for a specific session
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/observe/session.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/observe/session.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/observe/session.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/observe/session.ts)_
|
||||
|
||||
## `eas observe:versions`
|
||||
|
||||
@@ -2270,7 +2271,7 @@ DESCRIPTION
|
||||
display app versions with build and update details
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/observe/versions.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/observe/versions.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/observe/versions.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/observe/versions.ts)_
|
||||
|
||||
## `eas project:delete [NAME]`
|
||||
|
||||
@@ -2294,7 +2295,7 @@ DESCRIPTION
|
||||
delete a project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/project/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/project/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/project/delete.ts)_
|
||||
|
||||
## `eas project:icon:set PATH`
|
||||
|
||||
@@ -2314,7 +2315,7 @@ DESCRIPTION
|
||||
set the project icon displayed on the EAS dashboard
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/icon/set.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/project/icon/set.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/project/icon/set.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/project/icon/set.ts)_
|
||||
|
||||
## `eas project:info`
|
||||
|
||||
@@ -2328,7 +2329,7 @@ DESCRIPTION
|
||||
information about the current project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/project/info.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/project/info.ts)_
|
||||
|
||||
## `eas project:init`
|
||||
|
||||
@@ -2362,7 +2363,7 @@ EXAMPLES
|
||||
$ eas init --account my-account --json --non-interactive # Same, and print the result as JSON to stdout
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/project/init.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/project/init.ts)_
|
||||
|
||||
## `eas project:new [PATH]`
|
||||
|
||||
@@ -2386,7 +2387,7 @@ ALIASES
|
||||
$ eas new
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/new.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/project/new.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/project/new.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/project/new.ts)_
|
||||
|
||||
## `eas simulator`
|
||||
|
||||
@@ -2394,8 +2395,8 @@ _See code: [packages/eas-cli/src/commands/project/new.ts](https://github.com/exp
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas simulator [-p android|ios] [--type agent-device|argent|serve-sim] [--package-version <value>]
|
||||
[--max-duration-minutes <value>] [--force] [--out-config-type env|dotenv] [--json] [--non-interactive]
|
||||
$ eas simulator [-p android|ios] [--name <value>] [--type agent-device|argent|serve-sim] [--package-version
|
||||
<value>] [--max-duration-minutes <value>] [--force] [--out-config-type env|dotenv] [--json] [--non-interactive]
|
||||
|
||||
FLAGS
|
||||
-p, --platform=<option> Device platform
|
||||
@@ -2407,6 +2408,8 @@ FLAGS
|
||||
--max-duration-minutes=<value> 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.
|
||||
--name=<value> Human-readable name for the simulator session, shown in eas simulator:list and on
|
||||
expo.dev. Defaults to unnamed.
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--out-config-type=<option> [default: dotenv] How to output simulator connection configuration. Use "env" to
|
||||
print shell exports, or "dotenv" to write .env.eas-simulator.
|
||||
@@ -2454,7 +2457,7 @@ ALIASES
|
||||
$ eas build:submit
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/submit.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/submit.ts)_
|
||||
|
||||
## `eas testflight:crashes [ID]`
|
||||
|
||||
@@ -2495,7 +2498,7 @@ EXAMPLES
|
||||
$ eas testflight:crashes ${{ app_store_connect.beta_feedback.url }} --json # Look up whatever an EAS workflow trigger reported
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/testflight/crashes.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/testflight/crashes.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/testflight/crashes.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/testflight/crashes.ts)_
|
||||
|
||||
## `eas testflight:feedback [ID]`
|
||||
|
||||
@@ -2537,7 +2540,7 @@ EXAMPLES
|
||||
$ eas testflight:feedback ${{ app_store_connect.beta_feedback.url }} --json # Look up whatever an EAS workflow trigger reported
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/testflight/feedback.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/testflight/feedback.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/testflight/feedback.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/testflight/feedback.ts)_
|
||||
|
||||
## `eas update`
|
||||
|
||||
@@ -2580,7 +2583,7 @@ DESCRIPTION
|
||||
publish an update group
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/index.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/index.ts)_
|
||||
|
||||
## `eas update:configure`
|
||||
|
||||
@@ -2601,7 +2604,7 @@ DESCRIPTION
|
||||
configure the project to support EAS Update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/configure.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/configure.ts)_
|
||||
|
||||
## `eas update:delete GROUPID`
|
||||
|
||||
@@ -2622,7 +2625,7 @@ DESCRIPTION
|
||||
delete all the updates in an update group
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/delete.ts)_
|
||||
|
||||
## `eas update:edit [GROUPID]`
|
||||
|
||||
@@ -2647,7 +2650,7 @@ DESCRIPTION
|
||||
edit all the updates in an update group
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/edit.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/edit.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/edit.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/edit.ts)_
|
||||
|
||||
## `eas update:embedded:delete ID`
|
||||
|
||||
@@ -2668,7 +2671,7 @@ DESCRIPTION
|
||||
delete an embedded update registered with EAS Update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/embedded/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/embedded/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/embedded/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/embedded/delete.ts)_
|
||||
|
||||
## `eas update:embedded:list`
|
||||
|
||||
@@ -2694,7 +2697,7 @@ DESCRIPTION
|
||||
list embedded updates registered with EAS Update for this project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/embedded/list.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/embedded/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/embedded/list.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/embedded/list.ts)_
|
||||
|
||||
## `eas update:embedded:upload`
|
||||
|
||||
@@ -2724,7 +2727,7 @@ EXAMPLES
|
||||
$ eas update:embedded:upload --platform android --bundle android/app/src/main/assets/index.android.bundle --manifest android/app/src/main/assets/app.manifest --channel production --build-id <BUILD-ID>
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/embedded/upload.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/embedded/upload.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/embedded/upload.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/embedded/upload.ts)_
|
||||
|
||||
## `eas update:embedded:view ID`
|
||||
|
||||
@@ -2744,7 +2747,7 @@ DESCRIPTION
|
||||
view details of an embedded update registered with EAS Update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/embedded/view.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/embedded/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/embedded/view.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/embedded/view.ts)_
|
||||
|
||||
## `eas update:insights GROUPID`
|
||||
|
||||
@@ -2771,7 +2774,7 @@ DESCRIPTION
|
||||
display launch, crash, unique-user, and size insights for an update group
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/insights.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/insights.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/insights.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/insights.ts)_
|
||||
|
||||
## `eas update:list`
|
||||
|
||||
@@ -2798,7 +2801,7 @@ DESCRIPTION
|
||||
view the recent updates
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/list.ts)_
|
||||
|
||||
## `eas update:republish`
|
||||
|
||||
@@ -2836,7 +2839,7 @@ DESCRIPTION
|
||||
roll back to an existing update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/republish.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/republish.ts)_
|
||||
|
||||
## `eas update:revert-update-rollout`
|
||||
|
||||
@@ -2864,7 +2867,7 @@ DESCRIPTION
|
||||
revert a rollout update for a project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/revert-update-rollout.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/revert-update-rollout.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/revert-update-rollout.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/revert-update-rollout.ts)_
|
||||
|
||||
## `eas update:roll-back-to-embedded`
|
||||
|
||||
@@ -2894,7 +2897,7 @@ DESCRIPTION
|
||||
roll back to the embedded update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/roll-back-to-embedded.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/roll-back-to-embedded.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts)_
|
||||
|
||||
## `eas update:rollback [GROUPID]`
|
||||
|
||||
@@ -2926,7 +2929,7 @@ DESCRIPTION
|
||||
roll back to an embedded update or an existing update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/rollback.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/rollback.ts)_
|
||||
|
||||
## `eas update:view GROUPID`
|
||||
|
||||
@@ -2950,7 +2953,7 @@ DESCRIPTION
|
||||
update group details
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/update/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/update/view.ts)_
|
||||
|
||||
## `eas upload`
|
||||
|
||||
@@ -2971,7 +2974,7 @@ DESCRIPTION
|
||||
upload a local build and generate a sharable link
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/upload.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/upload.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/upload.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/upload.ts)_
|
||||
|
||||
## `eas webhook:create`
|
||||
|
||||
@@ -2993,7 +2996,7 @@ DESCRIPTION
|
||||
create a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/webhook/create.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/webhook/create.ts)_
|
||||
|
||||
## `eas webhook:delete [ID]`
|
||||
|
||||
@@ -3013,7 +3016,7 @@ DESCRIPTION
|
||||
delete a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/webhook/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/webhook/delete.ts)_
|
||||
|
||||
## `eas webhook:list`
|
||||
|
||||
@@ -3032,7 +3035,7 @@ DESCRIPTION
|
||||
list webhooks
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/webhook/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/webhook/list.ts)_
|
||||
|
||||
## `eas webhook:update`
|
||||
|
||||
@@ -3055,7 +3058,7 @@ DESCRIPTION
|
||||
update a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/webhook/update.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/webhook/update.ts)_
|
||||
|
||||
## `eas webhook:view ID`
|
||||
|
||||
@@ -3072,7 +3075,7 @@ DESCRIPTION
|
||||
view a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/webhook/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/webhook/view.ts)_
|
||||
|
||||
## `eas whoami`
|
||||
|
||||
@@ -3196,7 +3199,7 @@ DESCRIPTION
|
||||
to cancel.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/cancel.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/workflow/cancel.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/cancel.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/workflow/cancel.ts)_
|
||||
|
||||
## `eas workflow:create [NAME]`
|
||||
|
||||
@@ -3218,7 +3221,7 @@ DESCRIPTION
|
||||
create a new workflow configuration YAML file
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/create.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/workflow/create.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/create.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/workflow/create.ts)_
|
||||
|
||||
## `eas workflow:logs [ID]`
|
||||
|
||||
@@ -3242,7 +3245,7 @@ DESCRIPTION
|
||||
If no ID is passed in, you will be prompted to select from recent workflow runs for the current project.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/logs.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/workflow/logs.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/logs.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/workflow/logs.ts)_
|
||||
|
||||
## `eas workflow:run FILE`
|
||||
|
||||
@@ -3282,7 +3285,7 @@ FLAG DESCRIPTIONS
|
||||
Exit codes: 0 = success, 11 = failure, 12 = canceled, 13 = wait aborted.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/run.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/workflow/run.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/run.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/workflow/run.ts)_
|
||||
|
||||
## `eas workflow:runs`
|
||||
|
||||
@@ -3304,7 +3307,7 @@ DESCRIPTION
|
||||
list recent workflow runs for this project, with their IDs, statuses, and timestamps
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/runs.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/workflow/runs.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/runs.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/workflow/runs.ts)_
|
||||
|
||||
## `eas workflow:status [WORKFLOW_RUN_ID]`
|
||||
|
||||
@@ -3332,7 +3335,7 @@ FLAG DESCRIPTIONS
|
||||
Exit codes: 0 = success, 11 = failure, 12 = canceled, 13 = wait aborted.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/status.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/workflow/status.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/status.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/workflow/status.ts)_
|
||||
|
||||
## `eas workflow:validate PATH`
|
||||
|
||||
@@ -3352,7 +3355,7 @@ DESCRIPTION
|
||||
validate a workflow configuration yaml file
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/validate.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/workflow/validate.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/validate.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/workflow/validate.ts)_
|
||||
|
||||
## `eas workflow:view [ID]`
|
||||
|
||||
@@ -3374,5 +3377,5 @@ DESCRIPTION
|
||||
workflow runs for the current project.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/view.ts](https://github.com/expo/eas-cli/blob/v21.3.0/packages/eas-cli/src/commands/workflow/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/view.ts](https://github.com/expo/eas-cli/blob/v21.4.0/packages/eas-cli/src/commands/workflow/view.ts)_
|
||||
<!-- commandsstop -->
|
||||
Generated
+1189
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eas-cli",
|
||||
"version": "21.3.0",
|
||||
"version": "21.4.0",
|
||||
"description": "EAS command line tool",
|
||||
"keywords": [
|
||||
"cli",
|
||||
@@ -48,8 +48,8 @@
|
||||
"@expo/code-signing-certificates": "0.0.5",
|
||||
"@expo/config": "55.0.10",
|
||||
"@expo/config-plugins": "55.0.7",
|
||||
"@expo/eas-build-job": "21.3.0",
|
||||
"@expo/eas-json": "21.3.0",
|
||||
"@expo/eas-build-job": "21.4.0",
|
||||
"@expo/eas-json": "21.4.0",
|
||||
"@expo/env": "^1.0.0",
|
||||
"@expo/json-file": "8.3.3",
|
||||
"@expo/logger": "21.0.0",
|
||||
@@ -64,7 +64,7 @@
|
||||
"@expo/results": "1.0.0",
|
||||
"@expo/rudder-sdk-node": "1.1.1",
|
||||
"@expo/spawn-async": "1.7.2",
|
||||
"@expo/steps": "21.3.0",
|
||||
"@expo/steps": "21.4.0",
|
||||
"@expo/timeago.js": "1.0.0",
|
||||
"@oclif/core": "^4.8.3",
|
||||
"@oclif/plugin-autocomplete": "^3.2.40",
|
||||
|
||||
@@ -133,6 +133,17 @@ describe(ObserveEvents, () => {
|
||||
expect(options.eventName).toBeUndefined();
|
||||
});
|
||||
|
||||
it('routes to fetchObserveCustomEventsAsync with the session filter when --session-id is set with no positional arg', async () => {
|
||||
const command = createCommand(['--session-id', 'session-xyz']);
|
||||
await command.runAsync();
|
||||
|
||||
expect(mockFetchObserveCustomEventsAsync).toHaveBeenCalledTimes(1);
|
||||
expect(mockCustomEventNamesAsync).not.toHaveBeenCalled();
|
||||
const options = mockFetchObserveCustomEventsAsync.mock.calls[0][2];
|
||||
expect(options.eventName).toBeUndefined();
|
||||
expect(options.sessionId).toBe('session-xyz');
|
||||
});
|
||||
|
||||
it('throws when both an event name argument and --all-events are provided', async () => {
|
||||
const command = createCommand(['my_event', '--all-events']);
|
||||
await expect(command.runAsync()).rejects.toThrow(
|
||||
|
||||
@@ -55,7 +55,8 @@ export default class ObserveEvents extends EasCommand {
|
||||
...ObserveAppVersionFlag,
|
||||
...ObserveUpdateIdFlag,
|
||||
'session-id': Flags.string({
|
||||
description: 'Filter by session ID',
|
||||
description:
|
||||
'Filter by session ID. When no event name is given, lists the events in the session instead of the event-name summary.',
|
||||
}),
|
||||
'all-events': Flags.boolean({
|
||||
description:
|
||||
@@ -101,7 +102,10 @@ export default class ObserveEvents extends EasCommand {
|
||||
|
||||
const platform = appObservePlatformFromFlag(flags.platform);
|
||||
|
||||
if (!args.eventName && !flags['all-events']) {
|
||||
// A session ID narrows to a single session, so show that session's events
|
||||
// (like --all-events) instead of the account-wide name+count summary, which
|
||||
// has no session filter.
|
||||
if (!args.eventName && !flags['all-events'] && !flags['session-id']) {
|
||||
const { names, isTruncated } = await withObservePlanGateHandlingAsync(() =>
|
||||
ObserveQuery.customEventNamesAsync(graphqlClient, {
|
||||
appId: projectId,
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
import { Config } from '@oclif/core';
|
||||
|
||||
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import {
|
||||
DeviceRunSessionEventsByIdQuery,
|
||||
DeviceRunSessionStatus,
|
||||
} from '../../../graphql/generated';
|
||||
import { DeviceRunSessionQuery } from '../../../graphql/queries/DeviceRunSessionQuery';
|
||||
import Log from '../../../log';
|
||||
import { loadSimulatorEnvAsync } from '../../../simulator/env';
|
||||
import {
|
||||
type DeviceRunSessionEvent,
|
||||
downloadDeviceRunSessionEventsAsync,
|
||||
formatDeviceRunSessionEvent,
|
||||
projectDeviceRunSessionEventsForDisplay,
|
||||
} from '../../../simulator/events';
|
||||
import { enableJsonOutput, printJsonOnlyOutput } from '../../../utils/json';
|
||||
import { sleepAsync } from '../../../utils/promise';
|
||||
import SimulatorEvents from '../events';
|
||||
|
||||
jest.mock('../../../graphql/queries/DeviceRunSessionQuery');
|
||||
jest.mock('../../../log');
|
||||
jest.mock('../../../simulator/env', () => ({
|
||||
...jest.requireActual('../../../simulator/env'),
|
||||
loadSimulatorEnvAsync: jest.fn(),
|
||||
}));
|
||||
jest.mock('../../../simulator/events');
|
||||
jest.mock('../../../utils/json');
|
||||
jest.mock('../../../utils/promise');
|
||||
|
||||
const mockEventsByIdAsync = jest.mocked(DeviceRunSessionQuery.eventsByIdAsync);
|
||||
const mockDownloadEventsAsync = jest.mocked(downloadDeviceRunSessionEventsAsync);
|
||||
const mockFormatEvent = jest.mocked(formatDeviceRunSessionEvent);
|
||||
const mockLoadSimulatorEnvAsync = jest.mocked(loadSimulatorEnvAsync);
|
||||
const mockEnableJsonOutput = jest.mocked(enableJsonOutput);
|
||||
const mockPrintJsonOnlyOutput = jest.mocked(printJsonOnlyOutput);
|
||||
const mockProjectEvents = jest.mocked(projectDeviceRunSessionEventsForDisplay);
|
||||
const mockSleepAsync = jest.mocked(sleepAsync);
|
||||
const mockDebug = jest.mocked(Log.debug);
|
||||
const mockLog = jest.mocked(Log.log);
|
||||
|
||||
function getMockOclifConfig(): Config {
|
||||
const config = new Config({ root: __dirname });
|
||||
config.runHook = async () => ({ failures: [], successes: [] });
|
||||
return config;
|
||||
}
|
||||
|
||||
describe(SimulatorEvents, () => {
|
||||
const graphqlClient = {} as ExpoGraphqlClient;
|
||||
const projectDir = '/test/project';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockLoadSimulatorEnvAsync.mockResolvedValue();
|
||||
mockProjectEvents.mockImplementation(events => events);
|
||||
mockFormatEvent.mockImplementation(event => `formatted:${event.eventId}`);
|
||||
mockSleepAsync.mockResolvedValue();
|
||||
});
|
||||
|
||||
it('prints a JSON snapshot for the requested session', async () => {
|
||||
const session: DeviceRunSessionEventsByIdQuery['deviceRunSessions']['byId'] = {
|
||||
id: 'session-id',
|
||||
status: DeviceRunSessionStatus.InProgress,
|
||||
artifacts: [
|
||||
{
|
||||
id: 'event-artifact-id',
|
||||
downloadUrl: 'https://example.test/events',
|
||||
metadata: { __eas_type: 'session-events' },
|
||||
},
|
||||
],
|
||||
};
|
||||
const events = [
|
||||
{
|
||||
v: 1 as const,
|
||||
eventId: 'event-id',
|
||||
ts: '2026-07-10T12:00:00.000Z',
|
||||
producer: 'agent-device',
|
||||
type: 'operation.started',
|
||||
summary: 'Started tap',
|
||||
},
|
||||
];
|
||||
mockEventsByIdAsync.mockResolvedValue(session);
|
||||
mockDownloadEventsAsync.mockResolvedValue(events);
|
||||
const command = new SimulatorEvents(['--id', 'session-id', '--json'], getMockOclifConfig());
|
||||
// @ts-expect-error getContextAsync is protected
|
||||
jest.spyOn(command, 'getContextAsync').mockResolvedValue({
|
||||
loggedIn: { graphqlClient },
|
||||
projectDir,
|
||||
});
|
||||
|
||||
await command.runAsync();
|
||||
|
||||
expect(mockEnableJsonOutput).toHaveBeenCalled();
|
||||
expect(mockLoadSimulatorEnvAsync).toHaveBeenCalledWith(projectDir);
|
||||
expect(mockEventsByIdAsync).toHaveBeenCalledWith(graphqlClient, 'session-id');
|
||||
expect(mockDownloadEventsAsync).toHaveBeenCalledWith('https://example.test/events');
|
||||
expect(mockPrintJsonOnlyOutput).toHaveBeenCalledWith({
|
||||
deviceRunSessionId: 'session-id',
|
||||
events,
|
||||
});
|
||||
expect(mockProjectEvents).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('prints an empty snapshot when the session has no event artifact', async () => {
|
||||
mockEventsByIdAsync.mockResolvedValue({
|
||||
id: 'session-id',
|
||||
status: DeviceRunSessionStatus.Stopped,
|
||||
artifacts: [],
|
||||
});
|
||||
const command = new SimulatorEvents(['--id', 'session-id', '--json'], getMockOclifConfig());
|
||||
// @ts-expect-error getContextAsync is protected
|
||||
jest.spyOn(command, 'getContextAsync').mockResolvedValue({
|
||||
loggedIn: { graphqlClient },
|
||||
projectDir,
|
||||
});
|
||||
|
||||
await command.runAsync();
|
||||
|
||||
expect(mockDownloadEventsAsync).not.toHaveBeenCalled();
|
||||
expect(mockPrintJsonOnlyOutput).toHaveBeenCalledWith({
|
||||
deviceRunSessionId: 'session-id',
|
||||
events: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('prints a condensed text snapshot', async () => {
|
||||
const session = createSession(DeviceRunSessionStatus.Stopped);
|
||||
const events = [createEvent()];
|
||||
mockEventsByIdAsync.mockResolvedValue(session);
|
||||
mockDownloadEventsAsync.mockResolvedValue(events);
|
||||
const command = createCommand(['--id', 'session-id']);
|
||||
|
||||
await command.runAsync();
|
||||
|
||||
expect(mockProjectEvents).toHaveBeenCalledWith(events, {
|
||||
includeIncompleteOperations: true,
|
||||
});
|
||||
expect(mockFormatEvent).toHaveBeenCalledWith(events[0]);
|
||||
expect(mockLog).toHaveBeenCalledWith('formatted:event-id');
|
||||
});
|
||||
|
||||
it('refreshes twice after a followed running session stops before flushing incomplete events', async () => {
|
||||
const events = [createEvent()];
|
||||
mockEventsByIdAsync
|
||||
.mockResolvedValueOnce(createSession(DeviceRunSessionStatus.InProgress))
|
||||
.mockResolvedValueOnce(createSession(DeviceRunSessionStatus.Stopped))
|
||||
.mockResolvedValueOnce(createSession(DeviceRunSessionStatus.Stopped))
|
||||
.mockResolvedValueOnce(createSession(DeviceRunSessionStatus.Stopped));
|
||||
mockDownloadEventsAsync.mockResolvedValue(events);
|
||||
mockProjectEvents.mockImplementation((projectedEvents, options) =>
|
||||
options?.includeIncompleteOperations ? projectedEvents : []
|
||||
);
|
||||
const command = createCommand(['--id', 'session-id', '--follow']);
|
||||
|
||||
await command.runAsync();
|
||||
|
||||
expect(mockEventsByIdAsync).toHaveBeenCalledTimes(4);
|
||||
expect(mockDownloadEventsAsync).toHaveBeenCalledTimes(4);
|
||||
expect(mockSleepAsync).toHaveBeenCalledTimes(3);
|
||||
expect(
|
||||
mockProjectEvents.mock.calls.map(([, options]) => options?.includeIncompleteOperations)
|
||||
).toEqual([false, false, false, true]);
|
||||
expect(mockLog).toHaveBeenCalledTimes(1);
|
||||
expect(mockLog).toHaveBeenCalledWith('formatted:event-id');
|
||||
});
|
||||
|
||||
it('wakes from polling and flushes incomplete events when follow mode is interrupted', async () => {
|
||||
const existingInterruptListeners = new Set(process.listeners('SIGINT'));
|
||||
mockEventsByIdAsync.mockResolvedValue(createSession(DeviceRunSessionStatus.InProgress));
|
||||
const events = [createEvent()];
|
||||
mockDownloadEventsAsync.mockResolvedValue(events);
|
||||
mockProjectEvents.mockImplementation((projectedEvents, options) =>
|
||||
options?.includeIncompleteOperations ? projectedEvents : []
|
||||
);
|
||||
let notifySleepStarted: () => void;
|
||||
const sleepStarted = new Promise<void>(resolve => {
|
||||
notifySleepStarted = resolve;
|
||||
});
|
||||
mockSleepAsync.mockImplementationOnce(() => {
|
||||
notifySleepStarted();
|
||||
return new Promise<void>(() => {});
|
||||
});
|
||||
const command = createCommand(['--id', 'session-id', '--follow']);
|
||||
|
||||
const commandPromise = command.runAsync();
|
||||
await sleepStarted;
|
||||
const interruptHandler = process
|
||||
.listeners('SIGINT')
|
||||
.find(listener => !existingInterruptListeners.has(listener));
|
||||
expect(interruptHandler).toBeDefined();
|
||||
interruptHandler?.('SIGINT');
|
||||
await commandPromise;
|
||||
|
||||
expect(mockEventsByIdAsync).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
mockProjectEvents.mock.calls.map(([, options]) => options?.includeIncompleteOperations)
|
||||
).toEqual([false, true]);
|
||||
expect(mockLog).toHaveBeenCalledWith('formatted:event-id');
|
||||
expect(process.listeners('SIGINT')).toEqual([...existingInterruptListeners]);
|
||||
});
|
||||
|
||||
it('force exits on a second interrupt', async () => {
|
||||
const existingInterruptListeners = new Set(process.listeners('SIGINT'));
|
||||
mockEventsByIdAsync.mockResolvedValue(createSession(DeviceRunSessionStatus.InProgress));
|
||||
mockDownloadEventsAsync.mockResolvedValue([]);
|
||||
let notifySleepStarted: () => void;
|
||||
const sleepStarted = new Promise<void>(resolve => {
|
||||
notifySleepStarted = resolve;
|
||||
});
|
||||
mockSleepAsync.mockImplementationOnce(() => {
|
||||
notifySleepStarted();
|
||||
return new Promise<void>(() => {});
|
||||
});
|
||||
const exitSpy = jest
|
||||
.spyOn(process, 'exit')
|
||||
.mockImplementation((code?: string | number | null): never => {
|
||||
throw new Error(`process.exit(${code})`);
|
||||
});
|
||||
const command = createCommand(['--id', 'session-id', '--follow']);
|
||||
|
||||
try {
|
||||
const commandPromise = command.runAsync();
|
||||
await sleepStarted;
|
||||
const interruptHandler = process
|
||||
.listeners('SIGINT')
|
||||
.find(listener => !existingInterruptListeners.has(listener));
|
||||
expect(interruptHandler).toBeDefined();
|
||||
interruptHandler?.('SIGINT');
|
||||
expect(() => interruptHandler?.('SIGINT')).toThrow('process.exit(130)');
|
||||
await commandPromise;
|
||||
|
||||
expect(exitSpy).toHaveBeenCalledWith(130);
|
||||
expect(process.listeners('SIGINT')).toEqual([...existingInterruptListeners]);
|
||||
} finally {
|
||||
exitSpy.mockRestore();
|
||||
}
|
||||
});
|
||||
|
||||
it('retries transient query and artifact download errors in follow mode', async () => {
|
||||
const events = [createEvent()];
|
||||
mockEventsByIdAsync
|
||||
.mockRejectedValueOnce(new Error('query unavailable'))
|
||||
.mockResolvedValueOnce(createSession(DeviceRunSessionStatus.InProgress))
|
||||
.mockResolvedValueOnce(createSession(DeviceRunSessionStatus.Stopped));
|
||||
mockDownloadEventsAsync
|
||||
.mockRejectedValueOnce(new Error('artifact unavailable'))
|
||||
.mockResolvedValueOnce(events);
|
||||
const command = createCommand(['--id', 'session-id', '--follow']);
|
||||
|
||||
await command.runAsync();
|
||||
|
||||
expect(mockEventsByIdAsync).toHaveBeenCalledTimes(3);
|
||||
expect(mockDownloadEventsAsync).toHaveBeenCalledTimes(2);
|
||||
expect(mockSleepAsync).toHaveBeenCalledTimes(2);
|
||||
expect(mockDebug).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'Failed to poll simulator session events: query unavailable'
|
||||
);
|
||||
expect(mockDebug).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'Failed to poll simulator session events: artifact unavailable'
|
||||
);
|
||||
expect(mockLog).toHaveBeenCalledWith('formatted:event-id');
|
||||
});
|
||||
|
||||
it('does not retry query errors outside follow mode', async () => {
|
||||
const existingInterruptListeners = process.listeners('SIGINT');
|
||||
mockEventsByIdAsync.mockRejectedValue(new Error('query unavailable'));
|
||||
const command = createCommand(['--id', 'session-id']);
|
||||
|
||||
await expect(command.runAsync()).rejects.toThrow('query unavailable');
|
||||
|
||||
expect(mockSleepAsync).not.toHaveBeenCalled();
|
||||
expect(mockDebug).not.toHaveBeenCalled();
|
||||
expect(process.listeners('SIGINT')).toEqual(existingInterruptListeners);
|
||||
});
|
||||
|
||||
it('does not register an interrupt handler outside follow mode', async () => {
|
||||
const existingInterruptListeners = process.listeners('SIGINT');
|
||||
let notifyQueryStarted: () => void;
|
||||
const queryStarted = new Promise<void>(resolve => {
|
||||
notifyQueryStarted = resolve;
|
||||
});
|
||||
let resolveSession: (
|
||||
session: DeviceRunSessionEventsByIdQuery['deviceRunSessions']['byId']
|
||||
) => void = () => {
|
||||
throw new Error('Session promise was not initialized.');
|
||||
};
|
||||
const pendingSession = new Promise<
|
||||
DeviceRunSessionEventsByIdQuery['deviceRunSessions']['byId']
|
||||
>(resolve => {
|
||||
resolveSession = resolve;
|
||||
});
|
||||
mockEventsByIdAsync.mockImplementationOnce(() => {
|
||||
notifyQueryStarted();
|
||||
return pendingSession;
|
||||
});
|
||||
mockDownloadEventsAsync.mockResolvedValue([]);
|
||||
const command = createCommand(['--id', 'session-id']);
|
||||
|
||||
const commandPromise = command.runAsync();
|
||||
await queryStarted;
|
||||
expect(process.listeners('SIGINT')).toEqual(existingInterruptListeners);
|
||||
resolveSession(createSession(DeviceRunSessionStatus.Stopped));
|
||||
await commandPromise;
|
||||
});
|
||||
|
||||
it('rejects combining JSON and follow output', async () => {
|
||||
const command = new SimulatorEvents(
|
||||
['--id', 'session-id', '--json', '--follow'],
|
||||
getMockOclifConfig()
|
||||
);
|
||||
|
||||
await expect(command.runAsync()).rejects.toThrow('Use either --json or --follow, not both.');
|
||||
});
|
||||
});
|
||||
|
||||
function createCommand(args: string[]): SimulatorEvents {
|
||||
const command = new SimulatorEvents(args, getMockOclifConfig());
|
||||
// @ts-expect-error getContextAsync is protected
|
||||
jest.spyOn(command, 'getContextAsync').mockResolvedValue({
|
||||
loggedIn: { graphqlClient: {} as ExpoGraphqlClient },
|
||||
projectDir: '/test/project',
|
||||
});
|
||||
return command;
|
||||
}
|
||||
|
||||
function createSession(
|
||||
status: DeviceRunSessionStatus
|
||||
): DeviceRunSessionEventsByIdQuery['deviceRunSessions']['byId'] {
|
||||
return {
|
||||
id: 'session-id',
|
||||
status,
|
||||
artifacts: [
|
||||
{
|
||||
id: 'event-artifact-id',
|
||||
downloadUrl: 'https://example.test/events',
|
||||
metadata: { __eas_type: 'session-events' },
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function createEvent(): DeviceRunSessionEvent {
|
||||
return {
|
||||
v: 1 as const,
|
||||
eventId: 'event-id',
|
||||
ts: '2026-07-10T12:00:00.000Z',
|
||||
producer: 'agent-device',
|
||||
type: 'operation.started',
|
||||
summary: 'Started tap',
|
||||
};
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
JobRunStatus,
|
||||
} from '../../../graphql/generated';
|
||||
import { DeviceRunSessionQuery } from '../../../graphql/queries/DeviceRunSessionQuery';
|
||||
import Log from '../../../log';
|
||||
import {
|
||||
EAS_SIMULATOR_SESSION_ID,
|
||||
SIMULATOR_DOTENV_FILE_NAME,
|
||||
@@ -46,6 +47,7 @@ const mockPrintJsonOnlyOutput = jest.mocked(printJsonOnlyOutput);
|
||||
function makeDeviceRunSession(overrides: Partial<DeviceRunSessionById> = {}): DeviceRunSessionById {
|
||||
return {
|
||||
id: 'session-123',
|
||||
name: null,
|
||||
status: DeviceRunSessionStatus.InProgress,
|
||||
type: DeviceRunSessionType.AgentDevice,
|
||||
platform: AppPlatform.Ios,
|
||||
@@ -134,6 +136,7 @@ describe(SimulatorGet, () => {
|
||||
expect(mockByIdAsync).toHaveBeenCalledWith(graphqlClient, 'session-123');
|
||||
expect(mockPrintJsonOnlyOutput).toHaveBeenCalledWith({
|
||||
id: 'session-123',
|
||||
name: undefined,
|
||||
type: 'agent-device',
|
||||
status: DeviceRunSessionStatus.InProgress,
|
||||
platform: AppPlatform.Ios,
|
||||
@@ -148,6 +151,26 @@ describe(SimulatorGet, () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('includes the session name in JSON and human output when the session is named', async () => {
|
||||
mockByIdAsync.mockResolvedValue(makeDeviceRunSession({ name: 'Checkout regression' }));
|
||||
|
||||
const { command } = createCommand(['--id', 'session-123', '--json']);
|
||||
await command.runAsync();
|
||||
|
||||
expect(mockPrintJsonOnlyOutput).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ name: 'Checkout regression' })
|
||||
);
|
||||
|
||||
jest.clearAllMocks();
|
||||
mockLoadSimulatorEnvironmentVariablesAsync.mockResolvedValue();
|
||||
mockByIdAsync.mockResolvedValue(makeDeviceRunSession({ name: 'Checkout regression' }));
|
||||
|
||||
const { command: humanCommand } = createCommand(['--id', 'session-123']);
|
||||
await humanCommand.runAsync();
|
||||
|
||||
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('Checkout regression'));
|
||||
});
|
||||
|
||||
it(`uses ${EAS_SIMULATOR_SESSION_ID} from simulator env when --id is not passed`, async () => {
|
||||
const previousDeviceRunSessionId = process.env[EAS_SIMULATOR_SESSION_ID];
|
||||
const session = makeDeviceRunSession({ id: 'session-from-env' });
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
JobRunStatus,
|
||||
} from '../../../graphql/generated';
|
||||
import { DeviceRunSessionQuery } from '../../../graphql/queries/DeviceRunSessionQuery';
|
||||
import Log from '../../../log';
|
||||
import { enableJsonOutput, printJsonOnlyOutput } from '../../../utils/json';
|
||||
import SimulatorList from '../list';
|
||||
|
||||
@@ -40,6 +41,7 @@ const mockPrintJsonOnlyOutput = jest.mocked(printJsonOnlyOutput);
|
||||
function makeSession(overrides: Partial<DeviceRunSessionNode> = {}): DeviceRunSessionNode {
|
||||
return {
|
||||
id: 'session-123',
|
||||
name: null,
|
||||
status: DeviceRunSessionStatus.InProgress,
|
||||
type: DeviceRunSessionType.AgentDevice,
|
||||
platform: AppPlatform.Ios,
|
||||
@@ -129,6 +131,7 @@ describe(SimulatorList, () => {
|
||||
sessions: [
|
||||
{
|
||||
id: 'session-123',
|
||||
name: undefined,
|
||||
type: 'agent-device',
|
||||
status: DeviceRunSessionStatus.InProgress,
|
||||
platform: AppPlatform.Ios,
|
||||
@@ -180,6 +183,26 @@ describe(SimulatorList, () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('prints a name row for every session, named or not', async () => {
|
||||
mockListByAppIdAsync.mockResolvedValue(
|
||||
makeConnection([
|
||||
makeSession({ id: 'session-1', name: 'Checkout regression' }),
|
||||
makeSession({ id: 'session-2' }),
|
||||
])
|
||||
);
|
||||
|
||||
const { command } = createCommand([]);
|
||||
await command.runAsync();
|
||||
|
||||
const printed = jest
|
||||
.mocked(Log.log)
|
||||
.mock.calls.map(([entry]) => String(entry))
|
||||
.join('\n');
|
||||
expect(printed).toContain('Name: Checkout regression');
|
||||
expect(printed).toContain('Name: null');
|
||||
expect(printed.match(/Name:/g)).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('runs non-interactively without --json', async () => {
|
||||
const session = makeSession({ id: 'session-1', turtleJobRun: null });
|
||||
mockListByAppIdAsync.mockResolvedValue(makeConnection([session]));
|
||||
|
||||
@@ -99,6 +99,7 @@ function makeCreatedDeviceRunSession(
|
||||
function makeDeviceRunSession(overrides: Partial<DeviceRunSessionById> = {}): DeviceRunSessionById {
|
||||
return {
|
||||
id: 'session-123',
|
||||
name: null,
|
||||
status: DeviceRunSessionStatus.InProgress,
|
||||
type: DeviceRunSessionType.AgentDevice,
|
||||
platform: AppPlatform.Ios,
|
||||
@@ -189,6 +190,7 @@ describe(SimulatorStart, () => {
|
||||
});
|
||||
expect(mockCreateDeviceRunSessionAsync).toHaveBeenCalledWith(graphqlClient, {
|
||||
appId: 'project-123',
|
||||
name: undefined,
|
||||
packageVersion: undefined,
|
||||
platform: AppPlatform.Ios,
|
||||
type: DeviceRunSessionType.AgentDevice,
|
||||
@@ -278,6 +280,7 @@ describe(SimulatorStart, () => {
|
||||
);
|
||||
expect(mockCreateDeviceRunSessionAsync).toHaveBeenCalledWith(graphqlClient, {
|
||||
appId: 'project-123',
|
||||
name: undefined,
|
||||
packageVersion: undefined,
|
||||
platform: AppPlatform.Ios,
|
||||
type: DeviceRunSessionType.AgentDevice,
|
||||
@@ -297,6 +300,7 @@ describe(SimulatorStart, () => {
|
||||
);
|
||||
expect(mockCreateDeviceRunSessionAsync).toHaveBeenCalledWith(graphqlClient, {
|
||||
appId: 'project-123',
|
||||
name: undefined,
|
||||
packageVersion: undefined,
|
||||
platform: AppPlatform.Ios,
|
||||
type: DeviceRunSessionType.AgentDevice,
|
||||
@@ -325,6 +329,48 @@ describe(SimulatorStart, () => {
|
||||
expect(mockResetSimulatorEnvAsync).toHaveBeenCalledWith(projectDir);
|
||||
});
|
||||
|
||||
it('forwards --name to the create mutation', async () => {
|
||||
const { command } = createCommand([
|
||||
'--platform',
|
||||
'ios',
|
||||
'--non-interactive',
|
||||
'--name',
|
||||
'Checkout regression',
|
||||
]);
|
||||
await command.runAsync();
|
||||
|
||||
expect(mockCreateDeviceRunSessionAsync).toHaveBeenCalledWith(
|
||||
graphqlClient,
|
||||
expect.objectContaining({ name: 'Checkout regression' })
|
||||
);
|
||||
});
|
||||
|
||||
it('trims --name before sending it', async () => {
|
||||
const { command } = createCommand([
|
||||
'--platform',
|
||||
'ios',
|
||||
'--non-interactive',
|
||||
'--name',
|
||||
' Checkout regression ',
|
||||
]);
|
||||
await command.runAsync();
|
||||
|
||||
expect(mockCreateDeviceRunSessionAsync).toHaveBeenCalledWith(
|
||||
graphqlClient,
|
||||
expect.objectContaining({ name: 'Checkout regression' })
|
||||
);
|
||||
});
|
||||
|
||||
it('omits a blank --name instead of letting the server reject it', async () => {
|
||||
const { command } = createCommand(['--platform', 'ios', '--non-interactive', '--name', ' ']);
|
||||
await command.runAsync();
|
||||
|
||||
expect(mockCreateDeviceRunSessionAsync).toHaveBeenCalledWith(
|
||||
graphqlClient,
|
||||
expect.objectContaining({ name: undefined })
|
||||
);
|
||||
});
|
||||
|
||||
it('prompts to select the platform when --platform is omitted', async () => {
|
||||
mockPromptAsync.mockResolvedValueOnce({ selectedPlatform: AppPlatform.Android });
|
||||
mockByIdAsync
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
import { Flags } from '@oclif/core';
|
||||
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import {
|
||||
EasNonInteractiveAndJsonFlags,
|
||||
resolveNonInteractiveAndJsonFlags,
|
||||
} from '../../commandUtils/flags';
|
||||
import {
|
||||
type DeviceRunSessionEventsByIdQuery,
|
||||
DeviceRunSessionStatus,
|
||||
} from '../../graphql/generated';
|
||||
import { DeviceRunSessionQuery } from '../../graphql/queries/DeviceRunSessionQuery';
|
||||
import Log from '../../log';
|
||||
import {
|
||||
EAS_SIMULATOR_SESSION_ID,
|
||||
SIMULATOR_DOTENV_FILE_NAME,
|
||||
loadSimulatorEnvAsync,
|
||||
} from '../../simulator/env';
|
||||
import {
|
||||
type DeviceRunSessionEvent,
|
||||
downloadDeviceRunSessionEventsAsync,
|
||||
formatDeviceRunSessionEvent,
|
||||
projectDeviceRunSessionEventsForDisplay,
|
||||
} from '../../simulator/events';
|
||||
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
|
||||
import { sleepAsync } from '../../utils/promise';
|
||||
|
||||
const POLL_INTERVAL_MS = 5_000;
|
||||
const POST_STOP_REFRESH_COUNT = 2;
|
||||
|
||||
export default class SimulatorEvents extends EasCommand {
|
||||
static override hidden = true;
|
||||
static override description =
|
||||
'[EXPERIMENTAL] show activity events from a remote simulator session';
|
||||
|
||||
static override flags = {
|
||||
id: Flags.string({
|
||||
description: `Simulator session ID. Defaults to ${SIMULATOR_DOTENV_FILE_NAME}.`,
|
||||
}),
|
||||
follow: Flags.boolean({
|
||||
char: 'f',
|
||||
description: 'Keep watching for new events until the session ends.',
|
||||
}),
|
||||
...EasNonInteractiveAndJsonFlags,
|
||||
};
|
||||
|
||||
static override contextDefinition = {
|
||||
...this.ContextOptions.LoggedIn,
|
||||
...this.ContextOptions.ProjectDir,
|
||||
};
|
||||
|
||||
async runAsync(): Promise<void> {
|
||||
const { flags } = await this.parse(SimulatorEvents);
|
||||
const { json: jsonFlag, nonInteractive } = resolveNonInteractiveAndJsonFlags(flags);
|
||||
if (jsonFlag && flags.follow) {
|
||||
throw new Error('Use either --json or --follow, not both.');
|
||||
}
|
||||
if (jsonFlag) {
|
||||
enableJsonOutput();
|
||||
}
|
||||
|
||||
const {
|
||||
projectDir,
|
||||
loggedIn: { graphqlClient },
|
||||
} = await this.getContextAsync(SimulatorEvents, { nonInteractive });
|
||||
await loadSimulatorEnvAsync(projectDir);
|
||||
const deviceRunSessionId = flags.id ?? process.env[EAS_SIMULATOR_SESSION_ID];
|
||||
if (!deviceRunSessionId) {
|
||||
throw new Error(
|
||||
`No simulator session ID provided. Pass --id, or run \`eas simulator:start\` first to write ${SIMULATOR_DOTENV_FILE_NAME}.`
|
||||
);
|
||||
}
|
||||
|
||||
const printedEventIds = new Set<string>();
|
||||
let observedRunningSession = false;
|
||||
let remainingPostStopRefreshes = 0;
|
||||
let latestEvents: DeviceRunSessionEvent[] = [];
|
||||
const abortController = new AbortController();
|
||||
const { signal } = abortController;
|
||||
const abortPromise = new Promise<void>(resolve => {
|
||||
signal.addEventListener(
|
||||
'abort',
|
||||
() => {
|
||||
resolve();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
const interruptHandler = (): void => {
|
||||
if (signal.aborted) {
|
||||
process.exit(130);
|
||||
}
|
||||
abortController.abort();
|
||||
};
|
||||
if (flags.follow) {
|
||||
process.on('SIGINT', interruptHandler);
|
||||
}
|
||||
|
||||
try {
|
||||
while (!signal.aborted) {
|
||||
let session: DeviceRunSessionEventsByIdQuery['deviceRunSessions']['byId'];
|
||||
let events: DeviceRunSessionEvent[];
|
||||
try {
|
||||
session = await DeviceRunSessionQuery.eventsByIdAsync(graphqlClient, deviceRunSessionId);
|
||||
const eventArtifact = session.artifacts.find(
|
||||
artifact => artifact.metadata?.__eas_type === 'session-events'
|
||||
);
|
||||
events = eventArtifact
|
||||
? await downloadDeviceRunSessionEventsAsync(eventArtifact.downloadUrl)
|
||||
: [];
|
||||
} catch (err) {
|
||||
if (!flags.follow) {
|
||||
throw err;
|
||||
}
|
||||
Log.debug(
|
||||
`Failed to poll simulator session events: ${
|
||||
err instanceof Error ? err.message : String(err)
|
||||
}`
|
||||
);
|
||||
await Promise.race([sleepAsync(POLL_INTERVAL_MS), abortPromise]);
|
||||
continue;
|
||||
}
|
||||
latestEvents = events;
|
||||
|
||||
if (jsonFlag) {
|
||||
printJsonOnlyOutput({ deviceRunSessionId, events });
|
||||
return;
|
||||
}
|
||||
|
||||
const isRunning =
|
||||
session.status === DeviceRunSessionStatus.New ||
|
||||
session.status === DeviceRunSessionStatus.InProgress;
|
||||
if (isRunning) {
|
||||
observedRunningSession = true;
|
||||
remainingPostStopRefreshes = 0;
|
||||
} else if (observedRunningSession) {
|
||||
observedRunningSession = false;
|
||||
remainingPostStopRefreshes = POST_STOP_REFRESH_COUNT;
|
||||
}
|
||||
|
||||
const shouldRefreshAgain =
|
||||
flags.follow && !signal.aborted && (isRunning || remainingPostStopRefreshes > 0);
|
||||
printNewEvents(events, printedEventIds, !shouldRefreshAgain);
|
||||
|
||||
if (!shouldRefreshAgain) {
|
||||
if (events.length === 0) {
|
||||
Log.log('No simulator session activity has been recorded.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!isRunning) {
|
||||
remainingPostStopRefreshes -= 1;
|
||||
}
|
||||
await Promise.race([sleepAsync(POLL_INTERVAL_MS), abortPromise]);
|
||||
}
|
||||
printNewEvents(latestEvents, printedEventIds, true);
|
||||
} finally {
|
||||
if (flags.follow) {
|
||||
process.removeListener('SIGINT', interruptHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function printNewEvents(
|
||||
events: DeviceRunSessionEvent[],
|
||||
printedEventIds: Set<string>,
|
||||
includeIncompleteOperations: boolean
|
||||
): void {
|
||||
const displayEvents = projectDeviceRunSessionEventsForDisplay(events, {
|
||||
includeIncompleteOperations,
|
||||
});
|
||||
for (const event of displayEvents) {
|
||||
if (printedEventIds.has(event.eventId)) {
|
||||
continue;
|
||||
}
|
||||
Log.log(formatDeviceRunSessionEvent(event));
|
||||
printedEventIds.add(event.eventId);
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,7 @@ export default class SimulatorGet extends EasCommand {
|
||||
if (jsonFlag) {
|
||||
printJsonOnlyOutput({
|
||||
id: session.id,
|
||||
name: session.name ?? undefined,
|
||||
type: deviceRunSessionTypeToFlagValue(session.type),
|
||||
status: session.status,
|
||||
platform: session.platform,
|
||||
@@ -120,6 +121,7 @@ export default class SimulatorGet extends EasCommand {
|
||||
function formatSessionFields(session: DeviceRunSessionById, deviceRunSessionUrl: string): string {
|
||||
return formatFields([
|
||||
{ label: 'ID', value: session.id },
|
||||
{ label: 'Name', value: formatNullable(session.name) },
|
||||
{ label: 'Type', value: session.type },
|
||||
{ label: 'Status', value: session.status },
|
||||
{ label: 'Platform', value: session.platform },
|
||||
|
||||
@@ -131,6 +131,7 @@ export default class SimulatorList extends EasCommand {
|
||||
printJsonOnlyOutput({
|
||||
sessions: sessions.map(session => ({
|
||||
id: session.id,
|
||||
name: session.name ?? undefined,
|
||||
type: deviceRunSessionTypeToFlagValue(session.type),
|
||||
status: session.status,
|
||||
platform: session.platform,
|
||||
@@ -163,6 +164,7 @@ export default class SimulatorList extends EasCommand {
|
||||
);
|
||||
const lines = [
|
||||
`ID: ${session.id}`,
|
||||
`Name: ${session.name ?? 'null'}`,
|
||||
`Type: ${session.type}`,
|
||||
`Status: ${session.status}`,
|
||||
`Platform: ${session.platform}`,
|
||||
|
||||
@@ -61,6 +61,10 @@ export default class SimulatorStart extends EasCommand {
|
||||
description: 'Device platform',
|
||||
options: PLATFORM_FLAG_VALUES,
|
||||
})(),
|
||||
name: Flags.string({
|
||||
description:
|
||||
'Human-readable name for the simulator session, shown in eas simulator:list and on expo.dev. Defaults to unnamed.',
|
||||
}),
|
||||
type: Flags.option({
|
||||
description: 'Type of simulator session to create',
|
||||
options: Object.values(DEVICE_RUN_SESSION_TYPE_FLAG_VALUES),
|
||||
@@ -111,6 +115,10 @@ export default class SimulatorStart extends EasCommand {
|
||||
nonInteractive,
|
||||
});
|
||||
|
||||
// The server rejects blank names, so trim here and treat a whitespace-only
|
||||
// --name as if it had been omitted rather than surfacing a validation error.
|
||||
const name = flags.name?.trim() || undefined;
|
||||
|
||||
await loadSimulatorEnvAsync(projectDir);
|
||||
const existingDeviceRunSessionId = process.env[EAS_SIMULATOR_SESSION_ID];
|
||||
if (existingDeviceRunSessionId && !flags.force) {
|
||||
@@ -136,6 +144,7 @@ export default class SimulatorStart extends EasCommand {
|
||||
try {
|
||||
const session = await DeviceRunSessionMutation.createDeviceRunSessionAsync(graphqlClient, {
|
||||
appId: projectId,
|
||||
name,
|
||||
platform,
|
||||
type: DEVICE_RUN_SESSION_TYPE_BY_FLAG_VALUE[flags.type],
|
||||
packageVersion: flags['package-version'],
|
||||
@@ -224,6 +233,7 @@ export default class SimulatorStart extends EasCommand {
|
||||
if (jsonFlag) {
|
||||
printJsonOnlyOutput({
|
||||
id: deviceRunSessionId,
|
||||
name,
|
||||
type: flags.type,
|
||||
deviceRunSessionUrl,
|
||||
remoteConfig,
|
||||
|
||||
+171
-2
@@ -2149,6 +2149,12 @@ export type AppObserve = {
|
||||
errorTimeSeries: AppObserveErrorTimeSeries;
|
||||
events: AppObserveEventsConnection;
|
||||
navigationRoutes: AppObserveNavigationRoutesConnection;
|
||||
/** Active users and sessions for the Overview engagement band, across all versions. */
|
||||
overviewEngagement: AppObserveOverviewEngagement;
|
||||
/** Per-update comparison within one app version: the embedded bundle plus each OTA update. */
|
||||
overviewUpdateComparison: AppObserveOverviewUpdateComparison;
|
||||
/** Per-version, per-platform metric summaries for the Overview version-comparison matrix. */
|
||||
overviewVersionComparison: AppObserveOverviewVersionComparison;
|
||||
timeSeries: AppObserveTimeSeries;
|
||||
totalEventCount: Scalars['Int']['output'];
|
||||
/**
|
||||
@@ -2245,6 +2251,21 @@ export type AppObserveNavigationRoutesArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type AppObserveOverviewEngagementArgs = {
|
||||
input: AppObserveOverviewEngagementInput;
|
||||
};
|
||||
|
||||
|
||||
export type AppObserveOverviewUpdateComparisonArgs = {
|
||||
input: AppObserveOverviewUpdateComparisonInput;
|
||||
};
|
||||
|
||||
|
||||
export type AppObserveOverviewVersionComparisonArgs = {
|
||||
input: AppObserveOverviewVersionComparisonInput;
|
||||
};
|
||||
|
||||
|
||||
export type AppObserveTimeSeriesArgs = {
|
||||
input: AppObserveTimeSeriesInput;
|
||||
};
|
||||
@@ -2810,6 +2831,132 @@ export type AppObserveNavigationStat = {
|
||||
p90?: Maybe<Scalars['Float']['output']>;
|
||||
};
|
||||
|
||||
export type AppObserveOverviewEngagement = {
|
||||
__typename?: 'AppObserveOverviewEngagement';
|
||||
activeUsers: AppObserveOverviewEngagementStat;
|
||||
sessions: AppObserveOverviewEngagementStat;
|
||||
};
|
||||
|
||||
export type AppObserveOverviewEngagementBucket = {
|
||||
__typename?: 'AppObserveOverviewEngagementBucket';
|
||||
bucketStart: Scalars['DateTime']['output'];
|
||||
count: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
/** Engagement-band filters. No release filters: the band always spans all versions. */
|
||||
export type AppObserveOverviewEngagementInput = {
|
||||
/** Series bucket size. Defaults to one day. */
|
||||
bucketIntervalMinutes?: InputMaybe<Scalars['Int']['input']>;
|
||||
endTime: Scalars['DateTime']['input'];
|
||||
environment?: InputMaybe<Scalars['String']['input']>;
|
||||
platform?: InputMaybe<AppObservePlatform>;
|
||||
startTime: Scalars['DateTime']['input'];
|
||||
};
|
||||
|
||||
export type AppObserveOverviewEngagementStat = {
|
||||
__typename?: 'AppObserveOverviewEngagementStat';
|
||||
previousPeriodTotal: Scalars['Int']['output'];
|
||||
/** Per-bucket approximate uniques; buckets do not sum to `total`. */
|
||||
series: Array<AppObserveOverviewEngagementBucket>;
|
||||
total: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type AppObserveOverviewStability = {
|
||||
__typename?: 'AppObserveOverviewStability';
|
||||
affectedUsers: Scalars['Int']['output'];
|
||||
/** Fraction (0..1) of active sessions without a fatal error. */
|
||||
crashFreeSessions: Scalars['Float']['output'];
|
||||
/** Fraction (0..1) of active users without a fatal error. */
|
||||
crashFreeUsers: Scalars['Float']['output'];
|
||||
totalErrors: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type AppObserveOverviewUpdate = {
|
||||
__typename?: 'AppObserveOverviewUpdate';
|
||||
/** Null for the embedded bundle. */
|
||||
appUpdateId?: Maybe<Scalars['ID']['output']>;
|
||||
/** Downloads recorded in range; null when none were recorded (and always for the embedded bundle). */
|
||||
downloadCount?: Maybe<Scalars['Int']['output']>;
|
||||
eventCount: Scalars['Int']['output'];
|
||||
firstSeenAt: Scalars['DateTime']['output'];
|
||||
isEmbedded: Scalars['Boolean']['output'];
|
||||
medianDownloadTime?: Maybe<Scalars['Float']['output']>;
|
||||
/** EAS update message; null for the embedded bundle or when the update row no longer exists. */
|
||||
message?: Maybe<Scalars['String']['output']>;
|
||||
/** One entry per metric with data in range, all platforms combined. */
|
||||
metrics: Array<AppObserveOverviewUpdateMetric>;
|
||||
/** When the update was published; null for the embedded bundle. */
|
||||
publishedAt?: Maybe<Scalars['DateTime']['output']>;
|
||||
stability: AppObserveOverviewStability;
|
||||
uniqueUserCount: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type AppObserveOverviewUpdateComparison = {
|
||||
__typename?: 'AppObserveOverviewUpdateComparison';
|
||||
/** Embedded bundle first, then OTA updates oldest first. Only updates with runtime data appear. */
|
||||
updates: Array<AppObserveOverviewUpdate>;
|
||||
};
|
||||
|
||||
export type AppObserveOverviewUpdateComparisonInput = {
|
||||
appVersion: Scalars['String']['input'];
|
||||
endTime: Scalars['DateTime']['input'];
|
||||
environment?: InputMaybe<Scalars['String']['input']>;
|
||||
/** Metric names to aggregate. Defaults to all metrics available on the account's plan. */
|
||||
metricNames?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
startTime: Scalars['DateTime']['input'];
|
||||
};
|
||||
|
||||
export type AppObserveOverviewUpdateMetric = {
|
||||
__typename?: 'AppObserveOverviewUpdateMetric';
|
||||
eventCount: Scalars['Int']['output'];
|
||||
metricName: Scalars['String']['output'];
|
||||
statistics: AppObserveVersionMarkerStatistics;
|
||||
};
|
||||
|
||||
export type AppObserveOverviewVersion = {
|
||||
__typename?: 'AppObserveOverviewVersion';
|
||||
appVersion: Scalars['String']['output'];
|
||||
firstSeenAt: Scalars['DateTime']['output'];
|
||||
/** One entry per (metric, platform) with data in range; iOS includes tvOS and iPadOS. */
|
||||
metrics: Array<AppObserveOverviewVersionMetric>;
|
||||
/** Error stats for this version, all platforms combined. */
|
||||
stability: AppObserveOverviewStability;
|
||||
uniqueUserCount: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type AppObserveOverviewVersionComparison = {
|
||||
__typename?: 'AppObserveOverviewVersionComparison';
|
||||
/** Every version with data in range, highest version first, for the version picker. */
|
||||
allVersions: Array<AppObserveOverviewVersionSummary>;
|
||||
/** Compared versions, lowest version first. Requested versions with no data are omitted. */
|
||||
versions: Array<AppObserveOverviewVersion>;
|
||||
};
|
||||
|
||||
export type AppObserveOverviewVersionComparisonInput = {
|
||||
/** Versions to compare (max 10, any order). Defaults to the three highest versions. */
|
||||
appVersions?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
endTime: Scalars['DateTime']['input'];
|
||||
environment?: InputMaybe<Scalars['String']['input']>;
|
||||
/** Metric names to aggregate. Defaults to all metrics available on the account's plan. */
|
||||
metricNames?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
startTime: Scalars['DateTime']['input'];
|
||||
};
|
||||
|
||||
export type AppObserveOverviewVersionMetric = {
|
||||
__typename?: 'AppObserveOverviewVersionMetric';
|
||||
eventCount: Scalars['Int']['output'];
|
||||
metricName: Scalars['String']['output'];
|
||||
platform: AppObservePlatform;
|
||||
statistics: AppObserveVersionMarkerStatistics;
|
||||
};
|
||||
|
||||
export type AppObserveOverviewVersionSummary = {
|
||||
__typename?: 'AppObserveOverviewVersionSummary';
|
||||
appVersion: Scalars['String']['output'];
|
||||
firstSeenAt: Scalars['DateTime']['output'];
|
||||
uniqueUserCount: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export enum AppObservePlatform {
|
||||
Android = 'ANDROID',
|
||||
Ios = 'IOS'
|
||||
@@ -4933,6 +5080,11 @@ export type CreateDeviceRunSessionInput = {
|
||||
* plans. If omitted, the default is derived based on the job run's priority.
|
||||
*/
|
||||
maxRunTimeMinutes?: InputMaybe<Scalars['Int']['input']>;
|
||||
/**
|
||||
* Human-readable label for the session, at most 255 characters. If omitted, the
|
||||
* session is unnamed and clients fall back to identifying it by id.
|
||||
*/
|
||||
name?: InputMaybe<Scalars['String']['input']>;
|
||||
/**
|
||||
* The version of the package backing the device run session (e.g. "0.1.3-alpha.3").
|
||||
* If omitted, consumers treat the session as pinned to "latest".
|
||||
@@ -5689,6 +5841,11 @@ export type DeviceRunSession = {
|
||||
finishedAt?: Maybe<Scalars['DateTime']['output']>;
|
||||
id: Scalars['ID']['output'];
|
||||
initiatingActor?: Maybe<Actor>;
|
||||
/**
|
||||
* Human-readable label chosen by whoever started the session. Null when the
|
||||
* session was started without one.
|
||||
*/
|
||||
name?: Maybe<Scalars['String']['output']>;
|
||||
/**
|
||||
* The version of the package backing the device run session. Null means the session is
|
||||
* pinned to "latest" at the consumer side.
|
||||
@@ -10746,6 +10903,11 @@ export type User = Actor & UserActor & {
|
||||
lastName?: Maybe<Scalars['String']['output']>;
|
||||
newEmailPendingVerification?: Maybe<Scalars['String']['output']>;
|
||||
oAuthIdentities: Array<OAuthIdentity>;
|
||||
/**
|
||||
* The organization created during signup onboarding: the most recently
|
||||
* created organization this user owns. Only resolves for the viewer.
|
||||
*/
|
||||
onboardingOrganization?: Maybe<Account>;
|
||||
/** Registered passkey credentials */
|
||||
passkeyCredentials: Array<UserPasskeyCredential>;
|
||||
/** Pending UserInvitations for this user. Only resolves for the viewer. */
|
||||
@@ -14415,12 +14577,19 @@ export type SimulatorAvailabilityQueryVariables = Exact<{
|
||||
|
||||
export type SimulatorAvailabilityQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, ownerAccount: { __typename?: 'Account', id: string, name: string, accountFeatureGates: any } } } };
|
||||
|
||||
export type DeviceRunSessionEventsByIdQueryVariables = Exact<{
|
||||
deviceRunSessionId: Scalars['ID']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type DeviceRunSessionEventsByIdQuery = { __typename?: 'RootQuery', deviceRunSessions: { __typename?: 'DeviceRunSessionQuery', byId: { __typename?: 'DeviceRunSession', id: string, status: DeviceRunSessionStatus, artifacts: Array<{ __typename?: 'DeviceRunSessionArtifact', id: string, downloadUrl: string, metadata?: any | null }> } } };
|
||||
|
||||
export type DeviceRunSessionByIdQueryVariables = Exact<{
|
||||
deviceRunSessionId: Scalars['ID']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type DeviceRunSessionByIdQuery = { __typename?: 'RootQuery', deviceRunSessions: { __typename?: 'DeviceRunSessionQuery', byId: { __typename?: 'DeviceRunSession', id: string, status: DeviceRunSessionStatus, type: DeviceRunSessionType, platform: AppPlatform, createdAt: any, startedAt?: any | null, finishedAt?: any | null, updatedAt: any, app: { __typename?: 'App', id: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, artifacts: Array<{ __typename?: 'DeviceRunSessionArtifact', id: string, name: string, filename: string, downloadUrl: string, fileSizeBytes?: number | null, metadata?: any | null, createdAt: any, updatedAt: any }>, remoteConfig?:
|
||||
export type DeviceRunSessionByIdQuery = { __typename?: 'RootQuery', deviceRunSessions: { __typename?: 'DeviceRunSessionQuery', byId: { __typename?: 'DeviceRunSession', id: string, name?: string | null, status: DeviceRunSessionStatus, type: DeviceRunSessionType, platform: AppPlatform, createdAt: any, startedAt?: any | null, finishedAt?: any | null, updatedAt: any, app: { __typename?: 'App', id: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, artifacts: Array<{ __typename?: 'DeviceRunSessionArtifact', id: string, name: string, filename: string, downloadUrl: string, fileSizeBytes?: number | null, metadata?: any | null, createdAt: any, updatedAt: any }>, remoteConfig?:
|
||||
| { __typename: 'AgentDeviceRunSessionRemoteConfig', agentDeviceRemoteSessionUrl: string, agentDeviceRemoteSessionToken: string, webPreviewUrl?: string | null }
|
||||
| { __typename: 'ArgentRunSessionRemoteConfig', toolsUrl: string, toolsAuthToken?: string | null, webPreviewUrl?: string | null }
|
||||
| { __typename: 'ServeSimRunSessionRemoteConfig', previewUrl: string }
|
||||
@@ -14434,7 +14603,7 @@ export type DeviceRunSessionsByAppIdQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type DeviceRunSessionsByAppIdQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, deviceRunSessionsPaginated: { __typename?: 'AppDeviceRunSessionsConnection', edges: Array<{ __typename?: 'AppDeviceRunSessionEdge', cursor: string, node: { __typename?: 'DeviceRunSession', id: string, status: DeviceRunSessionStatus, type: DeviceRunSessionType, platform: AppPlatform, createdAt: any, startedAt?: any | null, finishedAt?: any | null, app: { __typename?: 'App', id: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, turtleJobRun?: { __typename?: 'JobRun', id: string, status: JobRunStatus } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null } } } } };
|
||||
export type DeviceRunSessionsByAppIdQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, deviceRunSessionsPaginated: { __typename?: 'AppDeviceRunSessionsConnection', edges: Array<{ __typename?: 'AppDeviceRunSessionEdge', cursor: string, node: { __typename?: 'DeviceRunSession', id: string, name?: string | null, status: DeviceRunSessionStatus, type: DeviceRunSessionType, platform: AppPlatform, createdAt: any, startedAt?: any | null, finishedAt?: any | null, app: { __typename?: 'App', id: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, turtleJobRun?: { __typename?: 'JobRun', id: string, status: JobRunStatus } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null } } } } };
|
||||
|
||||
export type ViewEmbeddedUpdateByIdQueryVariables = Exact<{
|
||||
embeddedUpdateId: Scalars['ID']['input'];
|
||||
|
||||
@@ -5,12 +5,43 @@ import { withErrorHandlingAsync } from '../client';
|
||||
import {
|
||||
DeviceRunSessionByIdQuery,
|
||||
DeviceRunSessionByIdQueryVariables,
|
||||
DeviceRunSessionEventsByIdQuery,
|
||||
DeviceRunSessionEventsByIdQueryVariables,
|
||||
DeviceRunSessionFilterInput,
|
||||
DeviceRunSessionsByAppIdQuery,
|
||||
DeviceRunSessionsByAppIdQueryVariables,
|
||||
} from '../generated';
|
||||
|
||||
export const DeviceRunSessionQuery = {
|
||||
async eventsByIdAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
deviceRunSessionId: string
|
||||
): Promise<DeviceRunSessionEventsByIdQuery['deviceRunSessions']['byId']> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<DeviceRunSessionEventsByIdQuery, DeviceRunSessionEventsByIdQueryVariables>(
|
||||
gql`
|
||||
query DeviceRunSessionEventsByIdQuery($deviceRunSessionId: ID!) {
|
||||
deviceRunSessions {
|
||||
byId(deviceRunSessionId: $deviceRunSessionId) {
|
||||
id
|
||||
status
|
||||
artifacts {
|
||||
id
|
||||
downloadUrl
|
||||
metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
{ deviceRunSessionId },
|
||||
{ requestPolicy: 'network-only' }
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.deviceRunSessions.byId;
|
||||
},
|
||||
async byIdAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
deviceRunSessionId: string
|
||||
@@ -23,6 +54,7 @@ export const DeviceRunSessionQuery = {
|
||||
deviceRunSessions {
|
||||
byId(deviceRunSessionId: $deviceRunSessionId) {
|
||||
id
|
||||
name
|
||||
status
|
||||
type
|
||||
platform
|
||||
@@ -111,6 +143,7 @@ export const DeviceRunSessionQuery = {
|
||||
cursor
|
||||
node {
|
||||
id
|
||||
name
|
||||
status
|
||||
type
|
||||
platform
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
import fetch, { RequestError, Response } from '../../fetch';
|
||||
import {
|
||||
type DeviceRunSessionEvent,
|
||||
downloadDeviceRunSessionEventsAsync,
|
||||
formatDeviceRunSessionEvent,
|
||||
projectDeviceRunSessionEventsForDisplay,
|
||||
} from '../events';
|
||||
|
||||
jest.mock('../../fetch', () => ({
|
||||
__esModule: true,
|
||||
...jest.requireActual('../../fetch'),
|
||||
default: jest.fn(),
|
||||
}));
|
||||
|
||||
describe(projectDeviceRunSessionEventsForDisplay, () => {
|
||||
it('collapses completed operations and carries duration onto the recorded interaction', () => {
|
||||
const events = [
|
||||
createEventValue({
|
||||
eventId: 'started',
|
||||
type: 'operation.started',
|
||||
operationId: 'operation-id',
|
||||
summary: 'Started press',
|
||||
}),
|
||||
createEventValue({
|
||||
eventId: 'interaction',
|
||||
ts: '2026-07-10T12:00:01.000Z',
|
||||
type: 'interaction.recorded',
|
||||
operationId: 'operation-id',
|
||||
summary: 'Tapped @e13',
|
||||
}),
|
||||
createEventValue({
|
||||
eventId: 'completed',
|
||||
ts: '2026-07-10T12:00:02.000Z',
|
||||
type: 'operation.completed',
|
||||
operationId: 'operation-id',
|
||||
outcome: 'success',
|
||||
durationMs: 123,
|
||||
summary: 'Finished press',
|
||||
}),
|
||||
];
|
||||
|
||||
expect(projectDeviceRunSessionEventsForDisplay(events)).toEqual([
|
||||
{
|
||||
...events[1],
|
||||
durationMs: 123,
|
||||
outcome: 'success',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('preserves completed failures and successful operations without interactions', () => {
|
||||
const successful = createEventValue({
|
||||
eventId: 'successful',
|
||||
type: 'operation.completed',
|
||||
operationId: 'successful-operation',
|
||||
outcome: 'success',
|
||||
summary: 'Found 2 devices',
|
||||
});
|
||||
const failed = createEventValue({
|
||||
eventId: 'failed',
|
||||
ts: '2026-07-10T12:00:01.000Z',
|
||||
type: 'operation.completed',
|
||||
operationId: 'failed-operation',
|
||||
outcome: 'failure',
|
||||
summary: 'Failed install: INVALID_ARGS',
|
||||
});
|
||||
|
||||
expect(projectDeviceRunSessionEventsForDisplay([successful, failed])).toEqual([
|
||||
successful,
|
||||
failed,
|
||||
]);
|
||||
});
|
||||
|
||||
it('can withhold incomplete operations while following a running session', () => {
|
||||
const started = createEventValue({
|
||||
eventId: 'started',
|
||||
type: 'operation.started',
|
||||
operationId: 'operation-id',
|
||||
summary: 'Started install',
|
||||
});
|
||||
const interaction = createEventValue({
|
||||
eventId: 'interaction',
|
||||
type: 'interaction.recorded',
|
||||
operationId: 'another-operation-id',
|
||||
summary: 'Captured screenshot screenshot.png',
|
||||
});
|
||||
const standalone = createEventValue({
|
||||
eventId: 'standalone',
|
||||
type: 'control.recorded',
|
||||
summary: 'Stopping session',
|
||||
});
|
||||
|
||||
expect(
|
||||
projectDeviceRunSessionEventsForDisplay([started, interaction, standalone], {
|
||||
includeIncompleteOperations: false,
|
||||
})
|
||||
).toEqual([standalone]);
|
||||
expect(projectDeviceRunSessionEventsForDisplay([started, interaction, standalone])).toEqual([
|
||||
started,
|
||||
interaction,
|
||||
standalone,
|
||||
]);
|
||||
});
|
||||
|
||||
it('keeps matching operation IDs from different producers separate', () => {
|
||||
const agentStarted = createEventValue({
|
||||
eventId: 'agent-started',
|
||||
operationId: 'shared-operation-id',
|
||||
summary: 'Started devices',
|
||||
});
|
||||
const agentCompleted = createEventValue({
|
||||
eventId: 'agent-completed',
|
||||
type: 'operation.completed',
|
||||
operationId: 'shared-operation-id',
|
||||
outcome: 'success',
|
||||
summary: 'Found 2 devices',
|
||||
});
|
||||
const serveSimStarted = createEventValue({
|
||||
eventId: 'serve-sim-started',
|
||||
producer: 'serve-sim',
|
||||
operationId: 'shared-operation-id',
|
||||
summary: 'Started simulator activity',
|
||||
});
|
||||
|
||||
expect(
|
||||
projectDeviceRunSessionEventsForDisplay([agentStarted, agentCompleted, serveSimStarted]).map(
|
||||
({ eventId }) => eventId
|
||||
)
|
||||
).toEqual(['agent-completed', 'serve-sim-started']);
|
||||
});
|
||||
});
|
||||
|
||||
describe(formatDeviceRunSessionEvent, () => {
|
||||
it('formats a compact log line with the producer and duration', () => {
|
||||
expect(
|
||||
formatDeviceRunSessionEvent(
|
||||
createEventValue({
|
||||
ts: '2026-07-10T12:00:01.000Z',
|
||||
summary: 'Found 2 devices',
|
||||
durationMs: 123,
|
||||
})
|
||||
)
|
||||
).toBe('2026-07-10T12:00:01.000Z [agent-device] Found 2 devices (123ms)');
|
||||
});
|
||||
|
||||
it('includes a screenshot filename without exposing its full path', () => {
|
||||
expect(
|
||||
formatDeviceRunSessionEvent(
|
||||
createEventValue({
|
||||
summary: 'Ran screenshot',
|
||||
data: {
|
||||
command: 'screenshot',
|
||||
path: '/tmp/private/screenshot.png',
|
||||
},
|
||||
})
|
||||
)
|
||||
).toBe('2026-07-10T12:00:00.000Z [agent-device] Ran screenshot screenshot.png');
|
||||
});
|
||||
|
||||
it('strips ANSI escape sequences and control characters from terminal output', () => {
|
||||
expect(
|
||||
formatDeviceRunSessionEvent(
|
||||
createEventValue({
|
||||
ts: '\u001B[31m2026-07-10T12:00:00.000Z\u001B[0m\n',
|
||||
producer: 'agent\u0000-device',
|
||||
summary: 'Found\r2\tdevices\u0007',
|
||||
})
|
||||
)
|
||||
).toBe('2026-07-10T12:00:00.000Z [agent-device] Found2devices');
|
||||
});
|
||||
});
|
||||
|
||||
describe(downloadDeviceRunSessionEventsAsync, () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(fetch).mockReset();
|
||||
});
|
||||
|
||||
it('treats a missing event object as an empty log', async () => {
|
||||
const response = new Response('', { status: 404 });
|
||||
jest.mocked(fetch).mockRejectedValue(new RequestError('not found', response));
|
||||
|
||||
await expect(
|
||||
downloadDeviceRunSessionEventsAsync('https://example.test/events')
|
||||
).resolves.toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
function createEventValue(overrides: Partial<DeviceRunSessionEvent> = {}): DeviceRunSessionEvent {
|
||||
return {
|
||||
v: 1,
|
||||
eventId: 'event-id',
|
||||
ts: '2026-07-10T12:00:00.000Z',
|
||||
producer: 'agent-device',
|
||||
type: 'operation.started',
|
||||
summary: 'Started tap',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
import { stripVTControlCharacters } from 'util';
|
||||
|
||||
import { type DeviceRunSessionEvent, parseDeviceRunSessionEvents } from '@expo/eas-build-job';
|
||||
|
||||
import fetch, { RequestError } from '../fetch';
|
||||
import { formatMilliseconds } from '../utils/timer';
|
||||
|
||||
export type { DeviceRunSessionEvent };
|
||||
|
||||
export async function downloadDeviceRunSessionEventsAsync(
|
||||
eventLogUrl: string
|
||||
): Promise<DeviceRunSessionEvent[]> {
|
||||
try {
|
||||
const response = await fetch(eventLogUrl);
|
||||
return parseDeviceRunSessionEvents(await response.text());
|
||||
} catch (error) {
|
||||
if (error instanceof RequestError && error.response.status === 404) {
|
||||
return [];
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export function projectDeviceRunSessionEventsForDisplay(
|
||||
events: DeviceRunSessionEvent[],
|
||||
{ includeIncompleteOperations = true }: { includeIncompleteOperations?: boolean } = {}
|
||||
): DeviceRunSessionEvent[] {
|
||||
const operations = new Map<
|
||||
string,
|
||||
{
|
||||
completed?: DeviceRunSessionEvent;
|
||||
interactions: DeviceRunSessionEvent[];
|
||||
}
|
||||
>();
|
||||
|
||||
for (const event of events) {
|
||||
if (!event.operationId) {
|
||||
continue;
|
||||
}
|
||||
const operationKey = getOperationKey(event);
|
||||
const operation = operations.get(operationKey) ?? { interactions: [] };
|
||||
if (event.type === 'operation.completed') {
|
||||
operation.completed = event;
|
||||
} else if (event.type === 'interaction.recorded') {
|
||||
operation.interactions.push(event);
|
||||
}
|
||||
operations.set(operationKey, operation);
|
||||
}
|
||||
|
||||
return events.flatMap(event => {
|
||||
if (!event.operationId) {
|
||||
return [event];
|
||||
}
|
||||
|
||||
const operation = operations.get(getOperationKey(event));
|
||||
const completed = operation?.completed;
|
||||
const interactions = operation?.interactions ?? [];
|
||||
|
||||
if (
|
||||
!includeIncompleteOperations &&
|
||||
!completed &&
|
||||
(event.type === 'operation.started' || event.type === 'interaction.recorded')
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
if (event.type === 'operation.started' && (completed || interactions.length > 0)) {
|
||||
return [];
|
||||
}
|
||||
if (event.type === 'interaction.recorded' && completed?.outcome === 'failure') {
|
||||
return [];
|
||||
}
|
||||
if (event.type === 'operation.completed' && completed?.outcome !== 'failure') {
|
||||
return interactions.length > 0 ? [] : [event];
|
||||
}
|
||||
if (
|
||||
event.type === 'interaction.recorded' &&
|
||||
completed &&
|
||||
interactions.at(-1)?.eventId === event.eventId
|
||||
) {
|
||||
return [{ ...event, durationMs: completed.durationMs, outcome: completed.outcome }];
|
||||
}
|
||||
|
||||
return [event];
|
||||
});
|
||||
}
|
||||
|
||||
export function formatDeviceRunSessionEvent(event: DeviceRunSessionEvent): string {
|
||||
const screenshotFilename = getScreenshotFilename(event);
|
||||
const summary =
|
||||
screenshotFilename && !event.summary.includes(screenshotFilename)
|
||||
? `${event.summary} ${screenshotFilename}`
|
||||
: event.summary;
|
||||
const duration =
|
||||
event.durationMs === undefined ? '' : ` (${formatEventDuration(event.durationMs)})`;
|
||||
return stripTerminalControlCharacters(`${event.ts} [${event.producer}] ${summary}${duration}`);
|
||||
}
|
||||
|
||||
function getOperationKey(event: DeviceRunSessionEvent): string {
|
||||
return JSON.stringify([event.producer, event.operationId]);
|
||||
}
|
||||
|
||||
function formatEventDuration(durationMs: number): string {
|
||||
return durationMs < 1000 ? `${Math.round(durationMs)}ms` : formatMilliseconds(durationMs);
|
||||
}
|
||||
|
||||
function getScreenshotFilename(event: DeviceRunSessionEvent): string | undefined {
|
||||
if (event.data?.command !== 'screenshot' || typeof event.data.path !== 'string') {
|
||||
return undefined;
|
||||
}
|
||||
return event.data.path.split(/[\\/]/).at(-1);
|
||||
}
|
||||
|
||||
function stripTerminalControlCharacters(value: string): string {
|
||||
return [...stripVTControlCharacters(value)]
|
||||
.filter(character => {
|
||||
const codePoint = character.codePointAt(0) ?? 0;
|
||||
return codePoint >= 0x20 && !(codePoint >= 0x7f && codePoint <= 0x9f);
|
||||
})
|
||||
.join('');
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/eas-json",
|
||||
"version": "21.3.0",
|
||||
"version": "21.4.0",
|
||||
"description": "A library for interacting with eas.json",
|
||||
"homepage": "https://github.com/expo/eas-cli",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
@@ -32,7 +32,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "7.23.5",
|
||||
"@expo/eas-build-job": "21.3.0",
|
||||
"@expo/eas-build-job": "21.4.0",
|
||||
"chalk": "4.1.2",
|
||||
"env-string": "1.0.1",
|
||||
"fs-extra": "11.2.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eas-cli-local-build-plugin",
|
||||
"version": "21.3.0",
|
||||
"version": "21.4.0",
|
||||
"description": "Tool for running EAS compatible builds on a local machine.",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "BUSL-1.1",
|
||||
@@ -26,8 +26,8 @@
|
||||
"clean": "rimraf node_modules dist coverage \"*.tsbuildinfo\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/build-tools": "21.3.0",
|
||||
"@expo/eas-build-job": "21.3.0",
|
||||
"@expo/build-tools": "21.4.0",
|
||||
"@expo/eas-build-job": "21.4.0",
|
||||
"@expo/logger": "21.0.0",
|
||||
"@expo/spawn-async": "^1.7.2",
|
||||
"@expo/turtle-spawn": "21.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/steps",
|
||||
"version": "21.3.0",
|
||||
"version": "21.4.0",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "BUSL-1.1",
|
||||
"author": "Expo <[email protected]>",
|
||||
@@ -27,7 +27,7 @@
|
||||
"clean": "rimraf node_modules dist coverage \"*.tsbuildinfo\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/eas-build-job": "21.3.0",
|
||||
"@expo/eas-build-job": "21.4.0",
|
||||
"@expo/logger": "21.0.0",
|
||||
"@expo/spawn-async": "^1.7.2",
|
||||
"arg": "^5.0.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/worker",
|
||||
"version": "21.3.0",
|
||||
"version": "21.4.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "yarn watch",
|
||||
@@ -19,16 +19,16 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "7.24.7",
|
||||
"@expo/build-tools": "21.3.0",
|
||||
"@expo/build-tools": "21.4.0",
|
||||
"@expo/config-plugins": "55.0.7",
|
||||
"@expo/config-types": "55.0.5",
|
||||
"@expo/downloader": "21.0.0",
|
||||
"@expo/eas-build-job": "21.3.0",
|
||||
"@expo/eas-build-job": "21.4.0",
|
||||
"@expo/logger": "21.0.0",
|
||||
"@expo/results": "1.0.0",
|
||||
"@expo/rudder-sdk-node": "1.1.1",
|
||||
"@expo/spawn-async": "1.7.2",
|
||||
"@expo/steps": "21.3.0",
|
||||
"@expo/steps": "21.4.0",
|
||||
"@expo/template-file": "21.0.2",
|
||||
"@expo/turtle-spawn": "21.0.0",
|
||||
"@hapi/boom": "10.0.1",
|
||||
|
||||
@@ -2291,14 +2291,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@expo/build-tools@npm:21.3.0, @expo/build-tools@workspace:packages/build-tools":
|
||||
"@expo/build-tools@npm:21.4.0, @expo/build-tools@workspace:packages/build-tools":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@expo/build-tools@workspace:packages/build-tools"
|
||||
dependencies:
|
||||
"@expo/config": "npm:55.0.10"
|
||||
"@expo/config-plugins": "npm:55.0.7"
|
||||
"@expo/downloader": "npm:21.0.0"
|
||||
"@expo/eas-build-job": "npm:21.3.0"
|
||||
"@expo/eas-build-job": "npm:21.4.0"
|
||||
"@expo/env": "npm:^0.4.0"
|
||||
"@expo/logger": "npm:21.0.0"
|
||||
"@expo/package-manager": "npm:1.9.10"
|
||||
@@ -2306,7 +2306,7 @@ __metadata:
|
||||
"@expo/repack-app": "npm:~0.6.1"
|
||||
"@expo/results": "npm:^1.0.0"
|
||||
"@expo/spawn-async": "npm:1.7.2"
|
||||
"@expo/steps": "npm:21.3.0"
|
||||
"@expo/steps": "npm:21.4.0"
|
||||
"@expo/template-file": "npm:21.0.2"
|
||||
"@expo/turtle-spawn": "npm:21.0.0"
|
||||
"@expo/xcpretty": "npm:^4.3.1"
|
||||
@@ -2547,7 +2547,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@expo/eas-build-job@npm:21.3.0, @expo/eas-build-job@workspace:packages/eas-build-job":
|
||||
"@expo/eas-build-job@npm:21.4.0, @expo/eas-build-job@workspace:packages/eas-build-job":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@expo/eas-build-job@workspace:packages/eas-build-job"
|
||||
dependencies:
|
||||
@@ -2566,12 +2566,12 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@expo/eas-json@npm:21.3.0, @expo/eas-json@workspace:packages/eas-json":
|
||||
"@expo/eas-json@npm:21.4.0, @expo/eas-json@workspace:packages/eas-json":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@expo/eas-json@workspace:packages/eas-json"
|
||||
dependencies:
|
||||
"@babel/code-frame": "npm:7.23.5"
|
||||
"@expo/eas-build-job": "npm:21.3.0"
|
||||
"@expo/eas-build-job": "npm:21.4.0"
|
||||
"@tsconfig/node20": "npm:20.1.8"
|
||||
"@types/babel__code-frame": "npm:7.0.3"
|
||||
"@types/fs-extra": "npm:11.0.4"
|
||||
@@ -2884,11 +2884,11 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@expo/steps@npm:21.3.0, @expo/steps@workspace:packages/steps":
|
||||
"@expo/steps@npm:21.4.0, @expo/steps@workspace:packages/steps":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@expo/steps@workspace:packages/steps"
|
||||
dependencies:
|
||||
"@expo/eas-build-job": "npm:21.3.0"
|
||||
"@expo/eas-build-job": "npm:21.4.0"
|
||||
"@expo/logger": "npm:21.0.0"
|
||||
"@expo/spawn-async": "npm:^1.7.2"
|
||||
"@jest/globals": "npm:^29.7.0"
|
||||
@@ -2957,16 +2957,16 @@ __metadata:
|
||||
resolution: "@expo/worker@workspace:packages/worker"
|
||||
dependencies:
|
||||
"@babel/core": "npm:7.24.7"
|
||||
"@expo/build-tools": "npm:21.3.0"
|
||||
"@expo/build-tools": "npm:21.4.0"
|
||||
"@expo/config-plugins": "npm:55.0.7"
|
||||
"@expo/config-types": "npm:55.0.5"
|
||||
"@expo/downloader": "npm:21.0.0"
|
||||
"@expo/eas-build-job": "npm:21.3.0"
|
||||
"@expo/eas-build-job": "npm:21.4.0"
|
||||
"@expo/logger": "npm:21.0.0"
|
||||
"@expo/results": "npm:1.0.0"
|
||||
"@expo/rudder-sdk-node": "npm:1.1.1"
|
||||
"@expo/spawn-async": "npm:1.7.2"
|
||||
"@expo/steps": "npm:21.3.0"
|
||||
"@expo/steps": "npm:21.4.0"
|
||||
"@expo/template-file": "npm:21.0.2"
|
||||
"@expo/turtle-spawn": "npm:21.0.0"
|
||||
"@hapi/boom": "npm:10.0.1"
|
||||
@@ -9722,7 +9722,7 @@ __metadata:
|
||||
resolution: "create-eas-build-function@workspace:packages/create-eas-build-function"
|
||||
dependencies:
|
||||
"@expo/package-manager": "npm:1.9.10"
|
||||
"@expo/steps": "npm:21.3.0"
|
||||
"@expo/steps": "npm:21.4.0"
|
||||
"@jest/globals": "npm:^29.7.0"
|
||||
"@types/jest": "npm:^29.5.12"
|
||||
"@types/node": "npm:20.14.2"
|
||||
@@ -10294,8 +10294,8 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "eas-cli-local-build-plugin@workspace:packages/local-build-plugin"
|
||||
dependencies:
|
||||
"@expo/build-tools": "npm:21.3.0"
|
||||
"@expo/eas-build-job": "npm:21.3.0"
|
||||
"@expo/build-tools": "npm:21.4.0"
|
||||
"@expo/eas-build-job": "npm:21.4.0"
|
||||
"@expo/logger": "npm:21.0.0"
|
||||
"@expo/spawn-async": "npm:^1.7.2"
|
||||
"@expo/turtle-spawn": "npm:21.0.0"
|
||||
@@ -10352,8 +10352,8 @@ __metadata:
|
||||
"@expo/code-signing-certificates": "npm:0.0.5"
|
||||
"@expo/config": "npm:55.0.10"
|
||||
"@expo/config-plugins": "npm:55.0.7"
|
||||
"@expo/eas-build-job": "npm:21.3.0"
|
||||
"@expo/eas-json": "npm:21.3.0"
|
||||
"@expo/eas-build-job": "npm:21.4.0"
|
||||
"@expo/eas-json": "npm:21.4.0"
|
||||
"@expo/env": "npm:^1.0.0"
|
||||
"@expo/json-file": "npm:8.3.3"
|
||||
"@expo/logger": "npm:21.0.0"
|
||||
@@ -10368,7 +10368,7 @@ __metadata:
|
||||
"@expo/results": "npm:1.0.0"
|
||||
"@expo/rudder-sdk-node": "npm:1.1.1"
|
||||
"@expo/spawn-async": "npm:1.7.2"
|
||||
"@expo/steps": "npm:21.3.0"
|
||||
"@expo/steps": "npm:21.4.0"
|
||||
"@expo/timeago.js": "npm:1.0.0"
|
||||
"@graphql-codegen/cli": "npm:6.3.1"
|
||||
"@graphql-codegen/introspection": "npm:5.0.2"
|
||||
|
||||
Reference in new issue
Block a user