@expo/build-tools 21.4.0 → 21.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/android/gradleProfile.js +14 -2
- package/dist/builders/custom.js +20 -12
- package/dist/common/git.d.ts +4 -0
- package/dist/common/git.js +35 -2
- package/dist/common/jobHooks.js +10 -0
- package/dist/generic.js +15 -6
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -1
- package/dist/logging/HttpLogStream.d.ts +28 -0
- package/dist/logging/HttpLogStream.js +137 -0
- package/dist/steps/compositeFunctions.d.ts +11 -0
- package/dist/steps/compositeFunctions.js +62 -0
- package/dist/steps/easFunctions.js +4 -0
- package/dist/steps/functions/checkout.js +26 -1
- package/dist/steps/functions/collectServeSimMetrics.d.ts +3 -0
- package/dist/steps/functions/collectServeSimMetrics.js +41 -0
- package/dist/steps/functions/startAgentDeviceRemoteSession.js +48 -40
- package/dist/steps/functions/startArgentRemoteSession.js +17 -2
- package/dist/steps/functions/startServeSimMetrics.d.ts +2 -0
- package/dist/steps/functions/startServeSimMetrics.js +17 -0
- package/dist/steps/functions/startServeSimRemoteSession.js +19 -14
- package/dist/steps/utils/agentDeviceArtifacts.js +1 -1
- package/dist/steps/utils/argentArtifacts.js +1 -1
- package/dist/steps/utils/deviceRunSessionEvents.js +68 -10
- package/dist/steps/utils/remoteDeviceRunSession.d.ts +43 -5
- package/dist/steps/utils/remoteDeviceRunSession.js +249 -37
- package/dist/steps/utils/serveSimMetricsArtifacts.d.ts +9 -0
- package/dist/steps/utils/serveSimMetricsArtifacts.js +49 -0
- package/dist/steps/utils/serveSimMetricsRecorder.d.ts +30 -0
- package/dist/steps/utils/serveSimMetricsRecorder.js +232 -0
- package/package.json +4 -4
|
@@ -59,50 +59,51 @@ function createStartAgentDeviceRemoteSessionBuildFunction(ctx) {
|
|
|
59
59
|
daemonProcess,
|
|
60
60
|
});
|
|
61
61
|
logger.info(`Daemon is listening on port ${daemonPort}; loaded auth token.`);
|
|
62
|
-
const
|
|
62
|
+
const agentDeviceTunnel = await (0, remoteDeviceRunSession_1.startNgrokTunnelAsync)({
|
|
63
63
|
port: daemonPort,
|
|
64
64
|
subdomainPrefix: 'agent-device',
|
|
65
65
|
baseDomain: ngrokTunnelDomain,
|
|
66
66
|
authtoken: ngrokAuthtoken,
|
|
67
67
|
logger,
|
|
68
68
|
});
|
|
69
|
+
const agentDeviceRemoteSessionUrl = agentDeviceTunnel.url;
|
|
69
70
|
logger.info(`Tunnel is ready at ${agentDeviceRemoteSessionUrl}.`);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
let serveSim;
|
|
72
|
+
let eventCollection;
|
|
73
|
+
try {
|
|
74
|
+
// serve-sim is iOS-only — only launch it (and report a webPreviewUrl)
|
|
75
|
+
// on Darwin. Android sessions go without a preview URL.
|
|
76
|
+
if (runtimePlatform === steps_1.BuildRuntimePlatform.DARWIN) {
|
|
77
|
+
serveSim = await (0, remoteDeviceRunSession_1.startServeSimWithTunnelAsync)(ctx, {
|
|
78
|
+
baseDomain: ngrokTunnelDomain,
|
|
79
|
+
env,
|
|
80
|
+
logger,
|
|
81
|
+
timeoutMs: STARTUP_TIMEOUT_MS,
|
|
82
|
+
});
|
|
83
|
+
logger.info(`Web preview URL: ${serveSim.previewUrl}`);
|
|
84
|
+
}
|
|
85
|
+
await (0, remoteDeviceRunSession_1.uploadRemoteSessionConfigAsync)({
|
|
86
|
+
ctx,
|
|
87
|
+
deviceRunSessionId,
|
|
88
|
+
remoteConfig: {
|
|
89
|
+
agentDeviceRemoteSessionUrl,
|
|
90
|
+
agentDeviceRemoteSessionToken: daemonToken,
|
|
91
|
+
...(serveSim ? { webPreviewUrl: serveSim.previewUrl } : {}),
|
|
92
|
+
},
|
|
93
|
+
logger,
|
|
94
|
+
});
|
|
95
|
+
void (0, agentDeviceArtifacts_1.pollAgentDeviceArtifactsForUploadAsync)(ctx, {
|
|
96
|
+
deviceRunSessionId,
|
|
97
|
+
daemonUrl: `http://127.0.0.1:${daemonPort}`,
|
|
98
|
+
daemonToken,
|
|
99
|
+
logger,
|
|
100
|
+
});
|
|
101
|
+
eventCollection = await (0, agentDeviceEvents_1.startAgentDeviceEventCollectionAsync)({
|
|
102
|
+
ctx,
|
|
103
|
+
deviceRunSessionId,
|
|
104
|
+
stateDir: AGENT_DEVICE_STATE_DIR,
|
|
77
105
|
logger,
|
|
78
|
-
timeoutMs: STARTUP_TIMEOUT_MS,
|
|
79
106
|
});
|
|
80
|
-
webPreviewUrl = previewUrl;
|
|
81
|
-
logger.info(`Web preview URL: ${webPreviewUrl}`);
|
|
82
|
-
}
|
|
83
|
-
await (0, remoteDeviceRunSession_1.uploadRemoteSessionConfigAsync)({
|
|
84
|
-
ctx,
|
|
85
|
-
deviceRunSessionId,
|
|
86
|
-
remoteConfig: {
|
|
87
|
-
agentDeviceRemoteSessionUrl,
|
|
88
|
-
agentDeviceRemoteSessionToken: daemonToken,
|
|
89
|
-
...(webPreviewUrl ? { webPreviewUrl } : {}),
|
|
90
|
-
},
|
|
91
|
-
logger,
|
|
92
|
-
});
|
|
93
|
-
void (0, agentDeviceArtifacts_1.pollAgentDeviceArtifactsForUploadAsync)(ctx, {
|
|
94
|
-
deviceRunSessionId,
|
|
95
|
-
daemonUrl: `http://127.0.0.1:${daemonPort}`,
|
|
96
|
-
daemonToken,
|
|
97
|
-
logger,
|
|
98
|
-
});
|
|
99
|
-
const eventCollection = await (0, agentDeviceEvents_1.startAgentDeviceEventCollectionAsync)({
|
|
100
|
-
ctx,
|
|
101
|
-
deviceRunSessionId,
|
|
102
|
-
stateDir: AGENT_DEVICE_STATE_DIR,
|
|
103
|
-
logger,
|
|
104
|
-
});
|
|
105
|
-
try {
|
|
106
107
|
await (0, remoteDeviceRunSession_1.waitForDeviceRunSessionStoppedAsync)({
|
|
107
108
|
ctx,
|
|
108
109
|
deviceRunSessionId,
|
|
@@ -111,11 +112,18 @@ function createStartAgentDeviceRemoteSessionBuildFunction(ctx) {
|
|
|
111
112
|
});
|
|
112
113
|
}
|
|
113
114
|
finally {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
if (serveSim) {
|
|
116
|
+
await serveSim.stopAsync();
|
|
117
|
+
}
|
|
118
|
+
await agentDeviceTunnel.stopAsync();
|
|
119
|
+
if (eventCollection) {
|
|
120
|
+
await stopAgentDeviceEventCollectionSafelyAsync({
|
|
121
|
+
eventCollection,
|
|
122
|
+
deviceRunSessionId,
|
|
123
|
+
logger,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
await daemonProcess.stopAsync();
|
|
119
127
|
}
|
|
120
128
|
},
|
|
121
129
|
});
|
|
@@ -69,6 +69,11 @@ function createStartArgentRemoteSessionBuildFunction(ctx) {
|
|
|
69
69
|
if (runtimePlatform === steps_1.BuildRuntimePlatform.DARWIN) {
|
|
70
70
|
await (0, remoteDeviceRunSession_1.selectXcodeDeveloperDirectoryAsync)({ env, logger });
|
|
71
71
|
}
|
|
72
|
+
// Argent shells out to ffmpeg to record the screen. Installing it pulls a
|
|
73
|
+
// large Homebrew dependency tree, so do not block session readiness on it:
|
|
74
|
+
// the session comes up at its usual speed and only a recording started in
|
|
75
|
+
// the first moments misses ffmpeg. Never rejects, so `void` is safe.
|
|
76
|
+
void (0, remoteDeviceRunSession_1.ensureFfmpegInstalledAsync)({ runtimePlatform, env, logger });
|
|
72
77
|
logger.info('Enabling the Argent artifacts list endpoint flag.');
|
|
73
78
|
await (0, turtle_spawn_1.default)('bunx', [`${ARGENT_PACKAGE_NAME}@${versionSpec}`, 'enable', ARGENT_ARTIFACTS_LIST_ENDPOINT_FLAG], { env, logger });
|
|
74
79
|
logger.info('Enabling the Argent tool-server event log flag.');
|
|
@@ -127,8 +132,10 @@ function createStartArgentRemoteSessionBuildFunction(ctx) {
|
|
|
127
132
|
eventLogPath: ARGENT_EVENT_LOG_PATH,
|
|
128
133
|
logger,
|
|
129
134
|
});
|
|
135
|
+
let toolsTunnel;
|
|
136
|
+
let serveSim;
|
|
130
137
|
try {
|
|
131
|
-
|
|
138
|
+
toolsTunnel = await (0, remoteDeviceRunSession_1.startNgrokTunnelAsync)({
|
|
132
139
|
port: toolServerPort,
|
|
133
140
|
subdomainPrefix: 'argent',
|
|
134
141
|
baseDomain: ngrokTunnelDomain,
|
|
@@ -136,11 +143,12 @@ function createStartArgentRemoteSessionBuildFunction(ctx) {
|
|
|
136
143
|
rewriteHostHeader: true,
|
|
137
144
|
logger,
|
|
138
145
|
});
|
|
146
|
+
const publicToolsUrl = toolsTunnel.url;
|
|
139
147
|
logger.info(`Tunnel is ready at ${publicToolsUrl}.`);
|
|
140
148
|
// serve-sim is iOS-only — Android sessions go without a preview URL.
|
|
141
149
|
let webPreviewUrl;
|
|
142
150
|
if (runtimePlatform === steps_1.BuildRuntimePlatform.DARWIN) {
|
|
143
|
-
|
|
151
|
+
serveSim = await (0, remoteDeviceRunSession_1.startServeSimWithTunnelAsync)(ctx, {
|
|
144
152
|
baseDomain: ngrokTunnelDomain,
|
|
145
153
|
env,
|
|
146
154
|
logger,
|
|
@@ -167,6 +175,12 @@ function createStartArgentRemoteSessionBuildFunction(ctx) {
|
|
|
167
175
|
});
|
|
168
176
|
}
|
|
169
177
|
finally {
|
|
178
|
+
if (serveSim) {
|
|
179
|
+
await serveSim.stopAsync();
|
|
180
|
+
}
|
|
181
|
+
if (toolsTunnel) {
|
|
182
|
+
await toolsTunnel.stopAsync();
|
|
183
|
+
}
|
|
170
184
|
await stopArgentEventCollectionSafelyAsync({ eventCollection, deviceRunSessionId, logger });
|
|
171
185
|
artifactPollAbortController.abort();
|
|
172
186
|
try {
|
|
@@ -177,6 +191,7 @@ function createStartArgentRemoteSessionBuildFunction(ctx) {
|
|
|
177
191
|
sentry_1.Sentry.capture('Could not finish Argent remote session artifact polling', error);
|
|
178
192
|
logger.warn({ err: error }, 'Could not finish Argent remote session artifact polling.');
|
|
179
193
|
}
|
|
194
|
+
await argentServer.stopAsync();
|
|
180
195
|
}
|
|
181
196
|
},
|
|
182
197
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createStartServeSimMetricsBuildFunction = createStartServeSimMetricsBuildFunction;
|
|
4
|
+
const steps_1 = require("@expo/steps");
|
|
5
|
+
const serveSimMetricsRecorder_1 = require("../utils/serveSimMetricsRecorder");
|
|
6
|
+
function createStartServeSimMetricsBuildFunction() {
|
|
7
|
+
return new steps_1.BuildFunction({
|
|
8
|
+
namespace: 'eas',
|
|
9
|
+
id: 'start_serve_sim_metrics',
|
|
10
|
+
name: 'Start serve-sim metrics',
|
|
11
|
+
__metricsId: 'eas/start_serve_sim_metrics',
|
|
12
|
+
supportedRuntimePlatforms: [steps_1.BuildRuntimePlatform.DARWIN],
|
|
13
|
+
fn: async ({ logger }) => {
|
|
14
|
+
await serveSimMetricsRecorder_1.ServeSimMetricsRecorder.startAsync({ logger });
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -16,25 +16,30 @@ function createStartServeSimRemoteSessionBuildFunction(ctx) {
|
|
|
16
16
|
const ngrokTunnelDomain = (0, remoteDeviceRunSession_1.getNgrokTunnelDomainOrThrow)(env);
|
|
17
17
|
logger.info('Starting serve-sim remote session.');
|
|
18
18
|
await (0, remoteDeviceRunSession_1.selectXcodeDeveloperDirectoryAsync)({ env, logger });
|
|
19
|
-
const
|
|
19
|
+
const serveSim = await (0, remoteDeviceRunSession_1.startServeSimWithTunnelAsync)(ctx, {
|
|
20
20
|
baseDomain: ngrokTunnelDomain,
|
|
21
21
|
env,
|
|
22
22
|
logger,
|
|
23
23
|
timeoutMs: STARTUP_TIMEOUT_MS,
|
|
24
24
|
});
|
|
25
|
-
logger.info(`Preview URL: ${previewUrl}`);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
logger.info(`Preview URL: ${serveSim.previewUrl}`);
|
|
26
|
+
try {
|
|
27
|
+
await (0, remoteDeviceRunSession_1.uploadRemoteSessionConfigAsync)({
|
|
28
|
+
ctx,
|
|
29
|
+
deviceRunSessionId,
|
|
30
|
+
remoteConfig: { previewUrl: serveSim.previewUrl },
|
|
31
|
+
logger,
|
|
32
|
+
});
|
|
33
|
+
await (0, remoteDeviceRunSession_1.waitForDeviceRunSessionStoppedAsync)({
|
|
34
|
+
ctx,
|
|
35
|
+
deviceRunSessionId,
|
|
36
|
+
logger,
|
|
37
|
+
signal,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
await serveSim.stopAsync();
|
|
42
|
+
}
|
|
38
43
|
},
|
|
39
44
|
});
|
|
40
45
|
}
|
|
@@ -68,7 +68,7 @@ async function pollAgentDeviceArtifactsForUploadAsync(ctx, { deviceRunSessionId,
|
|
|
68
68
|
}
|
|
69
69
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
70
70
|
listArtifactsErrorCount += 1;
|
|
71
|
-
if (listArtifactsErrorCount
|
|
71
|
+
if (listArtifactsErrorCount % 5 === 0) {
|
|
72
72
|
sentry_1.Sentry.capture('Could not list agent-device remote session artifacts', error);
|
|
73
73
|
logger.warn({ err: error, failedArtifactListCount: listArtifactsErrorCount }, 'Could not list agent-device remote session artifacts.');
|
|
74
74
|
}
|
|
@@ -68,7 +68,7 @@ async function pollArgentArtifactsForUploadAsync(ctx, { deviceRunSessionId, tool
|
|
|
68
68
|
}
|
|
69
69
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
70
70
|
listArtifactsErrorCount += 1;
|
|
71
|
-
if (listArtifactsErrorCount
|
|
71
|
+
if (listArtifactsErrorCount % 5 === 0) {
|
|
72
72
|
sentry_1.Sentry.capture('Could not list Argent remote session artifacts', error);
|
|
73
73
|
logger.warn({ err: error, failedArtifactListCount: listArtifactsErrorCount }, 'Could not list Argent remote session artifacts.');
|
|
74
74
|
}
|
|
@@ -9,10 +9,13 @@ const gql_tada_1 = require("gql.tada");
|
|
|
9
9
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
10
|
const node_string_decoder_1 = require("node:string_decoder");
|
|
11
11
|
const promises_1 = require("node:timers/promises");
|
|
12
|
+
const HttpLogStream_1 = __importDefault(require("../../logging/HttpLogStream"));
|
|
12
13
|
const RemoteLoggerStream_1 = __importDefault(require("../../logging/RemoteLoggerStream"));
|
|
13
14
|
const sentry_1 = require("../../sentry");
|
|
14
15
|
const POLL_INTERVAL_MS = 1_000;
|
|
15
16
|
const UPLOAD_INTERVAL_MS = 5_000;
|
|
17
|
+
const EAS_LOGS_THREAD = 'session-events';
|
|
18
|
+
const EAS_LOGS_BUFFER_RETENTION_MS = 30_000;
|
|
16
19
|
const CREATE_DEVICE_RUN_SESSION_EVENT_LOG_UPLOAD_SESSION_MUTATION = (0, gql_tada_1.graphql)(`
|
|
17
20
|
mutation CreateDeviceRunSessionEventLogUploadSession($deviceRunSessionId: ID!) {
|
|
18
21
|
deviceRunSession {
|
|
@@ -53,10 +56,31 @@ async function startDeviceRunSessionEventCollectionAsync({ ctx, deviceRunSession
|
|
|
53
56
|
}
|
|
54
57
|
catch (err) {
|
|
55
58
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
56
|
-
logger.warn({ err: error }, 'Could not
|
|
59
|
+
logger.warn({ err: error }, 'Could not persist device run session events to the artifact.');
|
|
57
60
|
reportEventLogFailure(error, 'setup');
|
|
58
61
|
return { stopAsync: async () => { } };
|
|
59
62
|
}
|
|
63
|
+
let didReportRealtimeLogFailure = false;
|
|
64
|
+
const reportRealtimeLogFailure = (error, operation) => {
|
|
65
|
+
if (didReportRealtimeLogFailure) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
didReportRealtimeLogFailure = true;
|
|
69
|
+
sentry_1.Sentry.capture('Could not publish device run session events in real time', error, {
|
|
70
|
+
level: 'warning',
|
|
71
|
+
tags: { phase: 'device-run-session-event-collection', operation, producer },
|
|
72
|
+
extras: { deviceRunSessionId },
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
let realtimeLogStream;
|
|
76
|
+
try {
|
|
77
|
+
realtimeLogStream = createRealtimeLogStream(ctx, logger);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
81
|
+
logger.warn({ err: error }, 'Could not start publishing device run session events in real time.');
|
|
82
|
+
reportRealtimeLogFailure(error, 'setup');
|
|
83
|
+
}
|
|
60
84
|
const states = new Map();
|
|
61
85
|
const controller = new AbortController();
|
|
62
86
|
let parseFailureCount = 0;
|
|
@@ -81,7 +105,10 @@ async function startDeviceRunSessionEventCollectionAsync({ ctx, deviceRunSession
|
|
|
81
105
|
state,
|
|
82
106
|
source,
|
|
83
107
|
deviceRunSessionId,
|
|
84
|
-
writeEvent: event =>
|
|
108
|
+
writeEvent: event => {
|
|
109
|
+
eventLogStream.write(event);
|
|
110
|
+
realtimeLogStream?.write({ ...event, logId: event.eventId });
|
|
111
|
+
},
|
|
85
112
|
onParseFailure: ({ failure, lineNumber }) => {
|
|
86
113
|
parseFailureCount += 1;
|
|
87
114
|
parseFailureCounts[failure] += 1;
|
|
@@ -155,16 +182,47 @@ async function startDeviceRunSessionEventCollectionAsync({ ctx, deviceRunSession
|
|
|
155
182
|
extras: { deviceRunSessionId, parseFailureCount, parseFailureCounts },
|
|
156
183
|
});
|
|
157
184
|
}
|
|
158
|
-
|
|
159
|
-
await eventLogStream.cleanUp();
|
|
160
|
-
}
|
|
161
|
-
catch (err) {
|
|
162
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
163
|
-
logger.warn({ err: error }, 'Could not finish device run session event collection.');
|
|
164
|
-
reportEventLogFailure(error, 'cleanup');
|
|
165
|
-
}
|
|
185
|
+
await Promise.all([cleanUpEventLogStreamAsync(), cleanUpRealtimeLogStreamAsync()]);
|
|
166
186
|
},
|
|
167
187
|
};
|
|
188
|
+
async function cleanUpEventLogStreamAsync() {
|
|
189
|
+
try {
|
|
190
|
+
await eventLogStream.cleanUp();
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
194
|
+
logger.warn({ err: error }, 'Could not finish persisting device run session events.');
|
|
195
|
+
reportEventLogFailure(error, 'cleanup');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async function cleanUpRealtimeLogStreamAsync() {
|
|
199
|
+
try {
|
|
200
|
+
await realtimeLogStream?.cleanUp();
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
204
|
+
logger.warn({ err: error }, 'Could not finish publishing device run session events in real time.');
|
|
205
|
+
reportRealtimeLogFailure(error, 'cleanup');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function createRealtimeLogStream(ctx, logger) {
|
|
210
|
+
const baseUrl = ctx.env.EXPO_LOCAL
|
|
211
|
+
? 'http://localhost:4999/logs/'
|
|
212
|
+
: ctx.env.EXPO_STAGING
|
|
213
|
+
? 'https://staging-logs.expo.dev/logs/'
|
|
214
|
+
: undefined;
|
|
215
|
+
const jobRunId = ctx.env.EAS_BUILD_ID;
|
|
216
|
+
const robotAccessToken = ctx.job.secrets?.robotAccessToken;
|
|
217
|
+
if (!baseUrl || !jobRunId || !robotAccessToken) {
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
return new HttpLogStream_1.default({
|
|
221
|
+
url: new URL(`${jobRunId}/${EAS_LOGS_THREAD}`, baseUrl).toString(),
|
|
222
|
+
headers: { Authorization: `Bearer ${robotAccessToken}` },
|
|
223
|
+
logger,
|
|
224
|
+
bufferRetentionMs: EAS_LOGS_BUFFER_RETENTION_MS,
|
|
225
|
+
});
|
|
168
226
|
}
|
|
169
227
|
async function createEventLogUploadSessionAsync(ctx, deviceRunSessionId) {
|
|
170
228
|
const result = await ctx.graphqlClient
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { bunyan } from '@expo/logger';
|
|
2
|
-
import { BuildStepEnv } from '@expo/steps';
|
|
2
|
+
import { BuildRuntimePlatform, BuildStepEnv } from '@expo/steps';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { CustomBuildContext } from '../../customBuildContext';
|
|
5
5
|
export declare function getDeviceRunSessionIdOrThrow(env: BuildStepEnv): string;
|
|
@@ -21,6 +21,26 @@ export declare function waitForDeviceRunSessionStoppedAsync({ ctx, deviceRunSess
|
|
|
21
21
|
logger: bunyan;
|
|
22
22
|
signal?: AbortSignal;
|
|
23
23
|
}): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Install ffmpeg when the runtime does not already provide it, so argent's
|
|
26
|
+
* `screen-recording-start` tool can encode a video. The worker images do not
|
|
27
|
+
* ship ffmpeg yet, so without this the tool fails with "`ffmpeg` was not found
|
|
28
|
+
* on PATH" — on macOS (iOS simulators) and Linux (Android emulators) alike.
|
|
29
|
+
*
|
|
30
|
+
* Best-effort by design: screen recording is one optional argent tool, so a
|
|
31
|
+
* failure here is logged and the session continues without it.
|
|
32
|
+
*
|
|
33
|
+
* The whole body is wrapped because the caller runs this in the background with
|
|
34
|
+
* `void`. There is no unhandledRejection handler in the worker, so a rejection
|
|
35
|
+
* escaping here would crash the process and take the live session with it.
|
|
36
|
+
* `spawn` is not an async function and can throw synchronously, which
|
|
37
|
+
* `asyncResult` cannot catch — it only wraps an already-created promise.
|
|
38
|
+
*/
|
|
39
|
+
export declare function ensureFfmpegInstalledAsync({ runtimePlatform, env, logger, }: {
|
|
40
|
+
runtimePlatform: BuildRuntimePlatform;
|
|
41
|
+
env: BuildStepEnv;
|
|
42
|
+
logger: bunyan;
|
|
43
|
+
}): Promise<void>;
|
|
24
44
|
/**
|
|
25
45
|
* Translate Cloudflare ICE servers into serve-sim CLI flags: `--stun-url` (the
|
|
26
46
|
* credential-less entries) and `--turn-url`/`--turn-username`/`--turn-credential`
|
|
@@ -51,6 +71,7 @@ export type DetachedProcessHandle = {
|
|
|
51
71
|
/** PID of the directly spawned process, if the OS assigned one. */
|
|
52
72
|
pid: number | undefined;
|
|
53
73
|
getOutput: () => string;
|
|
74
|
+
stopAsync: () => Promise<void>;
|
|
54
75
|
};
|
|
55
76
|
export declare function spawnDetached({ command, args, cwd, env, }: {
|
|
56
77
|
command: string;
|
|
@@ -58,14 +79,31 @@ export declare function spawnDetached({ command, args, cwd, env, }: {
|
|
|
58
79
|
cwd?: string;
|
|
59
80
|
env: BuildStepEnv;
|
|
60
81
|
}): DetachedProcessHandle;
|
|
82
|
+
export declare function metricsCorsOriginToServeSimArgs(env: BuildStepEnv): string[];
|
|
83
|
+
export declare function createServeSimArgs({ port, turnArgs, metricsCorsArgs, }: {
|
|
84
|
+
port: number;
|
|
85
|
+
turnArgs?: string[];
|
|
86
|
+
metricsCorsArgs?: string[];
|
|
87
|
+
}): string[];
|
|
88
|
+
export declare function waitForServeSimReadyAsync({ serveSim, port, timeoutMs, }: {
|
|
89
|
+
serveSim: Pick<DetachedProcessHandle, 'pid' | 'getOutput'>;
|
|
90
|
+
port: number;
|
|
91
|
+
timeoutMs: number;
|
|
92
|
+
}): Promise<void>;
|
|
93
|
+
export type ServeSimPreviewHandle = {
|
|
94
|
+
previewUrl: string;
|
|
95
|
+
stopAsync: () => Promise<void>;
|
|
96
|
+
};
|
|
61
97
|
export declare function startServeSimWithTunnelAsync(ctx: CustomBuildContext, { baseDomain, env, logger, timeoutMs, }: {
|
|
62
98
|
baseDomain: string;
|
|
63
99
|
env: BuildStepEnv;
|
|
64
100
|
logger: bunyan;
|
|
65
101
|
timeoutMs: number;
|
|
66
|
-
}): Promise<
|
|
67
|
-
|
|
68
|
-
|
|
102
|
+
}): Promise<ServeSimPreviewHandle>;
|
|
103
|
+
export type NgrokTunnelHandle = {
|
|
104
|
+
url: string;
|
|
105
|
+
stopAsync: () => Promise<void>;
|
|
106
|
+
};
|
|
69
107
|
export declare function startNgrokTunnelAsync({ port, subdomainPrefix, baseDomain, authtoken, rewriteHostHeader, logger, }: {
|
|
70
108
|
port: number;
|
|
71
109
|
subdomainPrefix: string;
|
|
@@ -73,7 +111,7 @@ export declare function startNgrokTunnelAsync({ port, subdomainPrefix, baseDomai
|
|
|
73
111
|
authtoken: string;
|
|
74
112
|
rewriteHostHeader?: boolean;
|
|
75
113
|
logger: bunyan;
|
|
76
|
-
}): Promise<
|
|
114
|
+
}): Promise<NgrokTunnelHandle>;
|
|
77
115
|
export declare function waitForFileAsync<T>({ filePath, timeoutMs, description, parse, }: {
|
|
78
116
|
filePath: string;
|
|
79
117
|
timeoutMs: number;
|