@expo/cli 56.1.14 → 56.1.16
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/build/bin/cli +1 -1
- package/build/src/api/graphql/client.js +19 -4
- package/build/src/api/graphql/client.js.map +1 -1
- package/build/src/api/graphql/mutations/TunnelMutation.js +31 -0
- package/build/src/api/graphql/mutations/TunnelMutation.js.map +1 -0
- package/build/src/events/index.js +1 -1
- package/build/src/prebuild/prebuildAsync.js +3 -1
- package/build/src/prebuild/prebuildAsync.js.map +1 -1
- package/build/src/start/doctor/apple/SimulatorAppPrerequisite.js +53 -91
- package/build/src/start/doctor/apple/SimulatorAppPrerequisite.js.map +1 -1
- package/build/src/start/platforms/ios/AppleDeviceManager.js +8 -2
- package/build/src/start/platforms/ios/AppleDeviceManager.js.map +1 -1
- package/build/src/start/platforms/ios/ensureSimulatorAppRunning.js +26 -11
- package/build/src/start/platforms/ios/ensureSimulatorAppRunning.js.map +1 -1
- package/build/src/start/server/AsyncWsTunnel.js +120 -35
- package/build/src/start/server/AsyncWsTunnel.js.map +1 -1
- package/build/src/start/server/BundlerDevServer.js +12 -2
- package/build/src/start/server/BundlerDevServer.js.map +1 -1
- package/build/src/start/server/metro/MetroTerminalReporter.js +2 -1
- package/build/src/start/server/metro/MetroTerminalReporter.js.map +1 -1
- package/build/src/start/server/metro/serializeHtml.js +11 -2
- package/build/src/start/server/metro/serializeHtml.js.map +1 -1
- package/build/src/utils/env.js +3 -0
- package/build/src/utils/env.js.map +1 -1
- package/build/src/utils/telemetry/clients/FetchClient.js +1 -1
- package/build/src/utils/telemetry/utils/context.js +1 -1
- package/package.json +13 -13
|
@@ -9,7 +9,7 @@ Object.defineProperty(exports, "ensureSimulatorAppRunningAsync", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
function _osascript() {
|
|
12
|
-
const data =
|
|
12
|
+
const data = require("@expo/osascript");
|
|
13
13
|
_osascript = function() {
|
|
14
14
|
return data;
|
|
15
15
|
};
|
|
@@ -95,8 +95,8 @@ async function waitForSimulatorAppToStart({ maxWaitTime } = {}) {
|
|
|
95
95
|
// I think the app can be open while no simulators are booted.
|
|
96
96
|
async function isSimulatorAppRunningAsync() {
|
|
97
97
|
try {
|
|
98
|
-
const
|
|
99
|
-
if (
|
|
98
|
+
const result = await (0, _osascript().spawnAsync)('tell app "System Events" to count processes whose name is "Simulator" or name is "DeviceHub"');
|
|
99
|
+
if (result.stdout.trim() === '0') {
|
|
100
100
|
return false;
|
|
101
101
|
}
|
|
102
102
|
} catch (error) {
|
|
@@ -108,15 +108,30 @@ async function isSimulatorAppRunningAsync() {
|
|
|
108
108
|
return true;
|
|
109
109
|
}
|
|
110
110
|
async function openSimulatorAppAsync(device) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
111
|
+
try {
|
|
112
|
+
const args = [
|
|
113
|
+
'-a',
|
|
114
|
+
'Simulator'
|
|
115
|
+
];
|
|
116
|
+
if (device.udid) {
|
|
117
|
+
// This has no effect if the app is already running.
|
|
118
|
+
args.push('--args', '-CurrentDeviceUDID', device.udid);
|
|
119
|
+
}
|
|
120
|
+
await (0, _spawnasync().default)('open', args);
|
|
121
|
+
} catch {
|
|
122
|
+
// Xcode 27+ replaces Simulator.app with DeviceHub, so `open -a Simulator` fails.
|
|
123
|
+
// DeviceHub registers the `devices://` URL scheme, which lets us focus the right
|
|
124
|
+
// device by its UDID — `open -a DeviceHub` can only bring the app forward.
|
|
125
|
+
const deviceHubArgs = device.udid ? [
|
|
126
|
+
`devices://device/open?id=${device.udid}`
|
|
127
|
+
] : [
|
|
128
|
+
'-a',
|
|
129
|
+
'DeviceHub'
|
|
130
|
+
];
|
|
131
|
+
await (0, _spawnasync().default)('open', deviceHubArgs).catch(()=>{
|
|
132
|
+
// Noop - we can't do much more here
|
|
133
|
+
});
|
|
118
134
|
}
|
|
119
|
-
await (0, _spawnasync().default)('open', args);
|
|
120
135
|
}
|
|
121
136
|
|
|
122
137
|
//# sourceMappingURL=ensureSimulatorAppRunning.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/start/platforms/ios/ensureSimulatorAppRunning.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"sources":["../../../../../src/start/platforms/ios/ensureSimulatorAppRunning.ts"],"sourcesContent":["import { spawnAsync as spawnAppleScriptAsync } from '@expo/osascript';\nimport spawnAsync from '@expo/spawn-async';\n\nimport type { Device } from './simctl';\nimport * as Log from '../../../log';\nimport { waitForActionAsync } from '../../../utils/delay';\nimport { CommandError } from '../../../utils/errors';\n\n/** Open the Simulator.app and return when the system registers it as 'open'. */\nexport async function ensureSimulatorAppRunningAsync(\n device: Partial<Pick<Device, 'udid'>>,\n {\n maxWaitTime,\n }: {\n maxWaitTime?: number;\n } = {}\n): Promise<void> {\n if (await isSimulatorAppRunningAsync()) {\n return;\n }\n\n Log.log(`\\u203A Opening the iOS simulator, this might take a moment.`);\n\n // In theory this would ensure the correct simulator is booted as well.\n // This isn't theory though, this is Xcode.\n await openSimulatorAppAsync(device);\n\n if (!(await waitForSimulatorAppToStart({ maxWaitTime }))) {\n throw new CommandError(\n 'SIMULATOR_TIMEOUT',\n `Simulator app did not open fast enough. Try opening Simulator first, then running your app.`\n );\n }\n}\n\nasync function waitForSimulatorAppToStart({\n maxWaitTime,\n}: { maxWaitTime?: number } = {}): Promise<boolean> {\n return waitForActionAsync<boolean>({\n interval: 50,\n maxWaitTime,\n action: isSimulatorAppRunningAsync,\n });\n}\n\n// I think the app can be open while no simulators are booted.\nasync function isSimulatorAppRunningAsync(): Promise<boolean> {\n try {\n const result = await spawnAppleScriptAsync(\n 'tell app \"System Events\" to count processes whose name is \"Simulator\" or name is \"DeviceHub\"'\n );\n if (result.stdout.trim() === '0') {\n return false;\n }\n } catch (error: any) {\n if (error.message.includes('Application isn’t running')) {\n return false;\n }\n throw error;\n }\n\n return true;\n}\n\nasync function openSimulatorAppAsync(device: { udid?: string }) {\n try {\n const args = ['-a', 'Simulator'];\n if (device.udid) {\n // This has no effect if the app is already running.\n args.push('--args', '-CurrentDeviceUDID', device.udid);\n }\n await spawnAsync('open', args);\n } catch {\n // Xcode 27+ replaces Simulator.app with DeviceHub, so `open -a Simulator` fails.\n // DeviceHub registers the `devices://` URL scheme, which lets us focus the right\n // device by its UDID — `open -a DeviceHub` can only bring the app forward.\n const deviceHubArgs = device.udid\n ? [`devices://device/open?id=${device.udid}`]\n : ['-a', 'DeviceHub'];\n await spawnAsync('open', deviceHubArgs).catch(() => {\n // Noop - we can't do much more here\n });\n }\n}\n"],"names":["ensureSimulatorAppRunningAsync","device","maxWaitTime","isSimulatorAppRunningAsync","Log","log","openSimulatorAppAsync","waitForSimulatorAppToStart","CommandError","waitForActionAsync","interval","action","result","spawnAppleScriptAsync","stdout","trim","error","message","includes","args","udid","push","spawnAsync","deviceHubArgs","catch"],"mappings":";;;;+BASsBA;;;eAAAA;;;;yBAT8B;;;;;;;gEAC7B;;;;;;6DAGF;uBACc;wBACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGtB,eAAeA,+BACpBC,MAAqC,EACrC,EACEC,WAAW,EAGZ,GAAG,CAAC,CAAC;IAEN,IAAI,MAAMC,8BAA8B;QACtC;IACF;IAEAC,KAAIC,GAAG,CAAC,CAAC,2DAA2D,CAAC;IAErE,uEAAuE;IACvE,2CAA2C;IAC3C,MAAMC,sBAAsBL;IAE5B,IAAI,CAAE,MAAMM,2BAA2B;QAAEL;IAAY,IAAK;QACxD,MAAM,IAAIM,oBAAY,CACpB,qBACA,CAAC,2FAA2F,CAAC;IAEjG;AACF;AAEA,eAAeD,2BAA2B,EACxCL,WAAW,EACc,GAAG,CAAC,CAAC;IAC9B,OAAOO,IAAAA,yBAAkB,EAAU;QACjCC,UAAU;QACVR;QACAS,QAAQR;IACV;AACF;AAEA,8DAA8D;AAC9D,eAAeA;IACb,IAAI;QACF,MAAMS,SAAS,MAAMC,IAAAA,uBAAqB,EACxC;QAEF,IAAID,OAAOE,MAAM,CAACC,IAAI,OAAO,KAAK;YAChC,OAAO;QACT;IACF,EAAE,OAAOC,OAAY;QACnB,IAAIA,MAAMC,OAAO,CAACC,QAAQ,CAAC,8BAA8B;YACvD,OAAO;QACT;QACA,MAAMF;IACR;IAEA,OAAO;AACT;AAEA,eAAeV,sBAAsBL,MAAyB;IAC5D,IAAI;QACF,MAAMkB,OAAO;YAAC;YAAM;SAAY;QAChC,IAAIlB,OAAOmB,IAAI,EAAE;YACf,oDAAoD;YACpDD,KAAKE,IAAI,CAAC,UAAU,sBAAsBpB,OAAOmB,IAAI;QACvD;QACA,MAAME,IAAAA,qBAAU,EAAC,QAAQH;IAC3B,EAAE,OAAM;QACN,iFAAiF;QACjF,iFAAiF;QACjF,2EAA2E;QAC3E,MAAMI,gBAAgBtB,OAAOmB,IAAI,GAC7B;YAAC,CAAC,yBAAyB,EAAEnB,OAAOmB,IAAI,EAAE;SAAC,GAC3C;YAAC;YAAM;SAAY;QACvB,MAAME,IAAAA,qBAAU,EAAC,QAAQC,eAAeC,KAAK,CAAC;QAC5C,oCAAoC;QACtC;IACF;AACF"}
|
|
@@ -2,12 +2,27 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get AsyncWsTunnel () {
|
|
8
13
|
return AsyncWsTunnel;
|
|
14
|
+
},
|
|
15
|
+
get getExpoAccountTunnelUrlAsync () {
|
|
16
|
+
return getExpoAccountTunnelUrlAsync;
|
|
9
17
|
}
|
|
10
18
|
});
|
|
19
|
+
function _config() {
|
|
20
|
+
const data = require("@expo/config");
|
|
21
|
+
_config = function() {
|
|
22
|
+
return data;
|
|
23
|
+
};
|
|
24
|
+
return data;
|
|
25
|
+
}
|
|
11
26
|
function _wstunnel() {
|
|
12
27
|
const data = /*#__PURE__*/ _interop_require_wildcard(require("@expo/ws-tunnel"));
|
|
13
28
|
_wstunnel = function() {
|
|
@@ -43,6 +58,10 @@ function _nodepath() {
|
|
|
43
58
|
};
|
|
44
59
|
return data;
|
|
45
60
|
}
|
|
61
|
+
const _TunnelMutation = require("../../api/graphql/mutations/TunnelMutation");
|
|
62
|
+
const _AppQuery = require("../../api/graphql/queries/AppQuery");
|
|
63
|
+
const _UserSettings = require("../../api/user/UserSettings");
|
|
64
|
+
const _user = require("../../api/user/user");
|
|
46
65
|
const _log = /*#__PURE__*/ _interop_require_wildcard(require("../../log"));
|
|
47
66
|
const _env = require("../../utils/env");
|
|
48
67
|
const _errors = require("../../utils/errors");
|
|
@@ -94,25 +113,44 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
94
113
|
}
|
|
95
114
|
const debug = require('debug')('expo:start:server:ws-tunnel');
|
|
96
115
|
class AsyncWsTunnel {
|
|
97
|
-
constructor(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
116
|
+
constructor(projectRoot, port, options = {}){
|
|
117
|
+
this.projectRoot = projectRoot;
|
|
118
|
+
this.port = port;
|
|
119
|
+
this.options = options;
|
|
120
|
+
this.serverUrl = null;
|
|
102
121
|
}
|
|
103
122
|
getActiveUrl() {
|
|
104
|
-
|
|
123
|
+
var _this_serverUrl;
|
|
124
|
+
return ((_this_serverUrl = this.serverUrl) == null ? void 0 : _this_serverUrl.href) ?? null;
|
|
105
125
|
}
|
|
106
126
|
async startAsync() {
|
|
107
127
|
this.serverUrl = await _wstunnel().startAsync({
|
|
108
|
-
...
|
|
128
|
+
...await this.getTunnelOptionsAsync(),
|
|
109
129
|
onStatusChange (status) {
|
|
110
130
|
if (status === 'disconnected') {
|
|
111
131
|
_log.error(_chalk().default.red('Tunnel connection has been closed. This is often related to intermittent connection problems with the ws proxy servers. Restart the dev server to try connecting again.') + _chalk().default.gray('\nCheck the Expo status page for outages: https://status.expo.dev/'));
|
|
112
132
|
}
|
|
113
133
|
}
|
|
114
134
|
});
|
|
115
|
-
debug('Tunnel URL:', this.serverUrl);
|
|
135
|
+
debug('Tunnel URL:', this.serverUrl.href);
|
|
136
|
+
}
|
|
137
|
+
async getTunnelOptionsAsync() {
|
|
138
|
+
if (this.options.useExpoAccount) {
|
|
139
|
+
return this.getExpoAccountTunnelOptionsAsync();
|
|
140
|
+
} else {
|
|
141
|
+
return getLegacyTunnelOptions(this.port);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async getExpoAccountTunnelOptionsAsync() {
|
|
145
|
+
const apiUrl = await getExpoAccountTunnelUrlAsync(this.projectRoot);
|
|
146
|
+
if (!apiUrl) {
|
|
147
|
+
const cause = (0, _UserSettings.hasCredentials)() ? `Your Expo account may not have access to it, or the tunnel service is unavailable.` : `You're not logged in to your Expo account — run 'npx expo login'.`;
|
|
148
|
+
throw new _errors.CommandError('WS_TUNNEL_SIGNED_URL', `Couldn't create a signed tunnel URL for this project. ${cause} ` + `Unset EXPO_UNSTABLE_TUNNEL_V2 to use an ngrok tunnel instead.`);
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
apiUrl,
|
|
152
|
+
targetUrl: `http://localhost:${this.port}`
|
|
153
|
+
};
|
|
116
154
|
}
|
|
117
155
|
async stopAsync() {
|
|
118
156
|
debug('Stopping Tunnel');
|
|
@@ -120,36 +158,83 @@ class AsyncWsTunnel {
|
|
|
120
158
|
this.serverUrl = null;
|
|
121
159
|
}
|
|
122
160
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
161
|
+
function getLegacyTunnelOptions(port) {
|
|
162
|
+
if (port !== 8081) {
|
|
163
|
+
throw new _errors.CommandError('WS_TUNNEL_PORT', `WS-tunnel only supports tunneling over port 8081, attempted to use port ${port}`);
|
|
164
|
+
}
|
|
165
|
+
function randomSessionId() {
|
|
166
|
+
const randomPart = ()=>(Math.random().toString(36) + '00000').slice(2, 7);
|
|
167
|
+
return randomPart() + randomPart() + randomPart();
|
|
168
|
+
}
|
|
169
|
+
function getWebcontainerSession() {
|
|
170
|
+
let session = randomSessionId();
|
|
171
|
+
if ((0, _env.envIsWebcontainer)()) {
|
|
172
|
+
const leaseId = Buffer.from((0, _nodeos().hostname)()).toString('base64url');
|
|
173
|
+
const leaseFile = _nodepath().join((0, _nodeos().tmpdir)(), `_ws_tunnel_lease_${leaseId}`);
|
|
174
|
+
try {
|
|
175
|
+
session = _nodefs().readFileSync(leaseFile, 'utf8').trim() || session;
|
|
176
|
+
} catch {}
|
|
177
|
+
try {
|
|
178
|
+
_nodefs().writeFileSync(leaseFile, session, 'utf8');
|
|
179
|
+
} catch {}
|
|
180
|
+
}
|
|
181
|
+
return session;
|
|
182
|
+
}
|
|
142
183
|
const userDefinedSubdomain = _env.env.EXPO_TUNNEL_SUBDOMAIN;
|
|
143
184
|
if (userDefinedSubdomain && typeof userDefinedSubdomain === 'string') {
|
|
144
185
|
debug('Session:', userDefinedSubdomain);
|
|
145
186
|
return {
|
|
146
187
|
session: userDefinedSubdomain
|
|
147
188
|
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
session: getWebcontainerSession()
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
async function getExpoAccountTunnelUrlAsync(projectRoot) {
|
|
195
|
+
async function resolveExpoAccountIdAsync(projectRoot) {
|
|
196
|
+
var _exp_extra_eas, _exp_extra, _actor_accounts_;
|
|
197
|
+
const { exp } = (0, _config().getConfig)(projectRoot, {
|
|
198
|
+
skipSDKVersionRequirement: true
|
|
199
|
+
});
|
|
200
|
+
const easProjectId = (_exp_extra = exp.extra) == null ? void 0 : (_exp_extra_eas = _exp_extra.eas) == null ? void 0 : _exp_extra_eas.projectId;
|
|
201
|
+
if (easProjectId) {
|
|
202
|
+
try {
|
|
203
|
+
var _app_ownerAccount;
|
|
204
|
+
const app = await _AppQuery.AppQuery.byIdAsync(easProjectId);
|
|
205
|
+
const appOwnerAccountId = app == null ? void 0 : (_app_ownerAccount = app.ownerAccount) == null ? void 0 : _app_ownerAccount.id;
|
|
206
|
+
if (appOwnerAccountId) {
|
|
207
|
+
return appOwnerAccountId;
|
|
208
|
+
}
|
|
209
|
+
} catch (error) {
|
|
210
|
+
debug('Failed to resolve owning account from EAS project ID:', error);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const actor = await (0, _user.getUserAsync)();
|
|
214
|
+
if (!actor) {
|
|
215
|
+
return null;
|
|
216
|
+
} else if (actor.__typename === 'User' || actor.__typename === 'SSOUser') {
|
|
217
|
+
var _actor_primaryAccount;
|
|
218
|
+
const actorPrimaryAccountId = (_actor_primaryAccount = actor.primaryAccount) == null ? void 0 : _actor_primaryAccount.id;
|
|
219
|
+
if (actorPrimaryAccountId) {
|
|
220
|
+
return actorPrimaryAccountId;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// Robots have no primary account; fall back to their first available account.
|
|
224
|
+
return ((_actor_accounts_ = actor.accounts[0]) == null ? void 0 : _actor_accounts_.id) ?? null;
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
const accountId = await resolveExpoAccountIdAsync(projectRoot);
|
|
228
|
+
if (!accountId) {
|
|
229
|
+
debug('No Expo account available to create a signed tunnel URL; user is likely logged out.');
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
const { url } = await _TunnelMutation.TunnelMutation.createSignedTunnelUrlAsync(accountId);
|
|
233
|
+
debug('Created signed tunnel URL for account:', accountId);
|
|
234
|
+
return url;
|
|
235
|
+
} catch (error) {
|
|
236
|
+
debug('Failed to create a signed tunnel URL:', error);
|
|
237
|
+
return null;
|
|
153
238
|
}
|
|
154
239
|
}
|
|
155
240
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/start/server/AsyncWsTunnel.ts"],"sourcesContent":["import * as tunnel from '@expo/ws-tunnel';\nimport chalk from 'chalk';\nimport * as fs from 'node:fs';\nimport { tmpdir, hostname } from 'node:os';\nimport * as path from 'node:path';\n\nimport * as Log from '../../log';\nimport { env, envIsWebcontainer } from '../../utils/env';\nimport { CommandError } from '../../utils/errors';\n\nconst debug = require('debug')('expo:start:server:ws-tunnel') as typeof console.log;\n\nexport
|
|
1
|
+
{"version":3,"sources":["../../../../src/start/server/AsyncWsTunnel.ts"],"sourcesContent":["import { getConfig } from '@expo/config';\nimport * as tunnel from '@expo/ws-tunnel';\nimport chalk from 'chalk';\nimport * as fs from 'node:fs';\nimport { tmpdir, hostname } from 'node:os';\nimport * as path from 'node:path';\n\nimport { TunnelMutation } from '../../api/graphql/mutations/TunnelMutation';\nimport { AppQuery } from '../../api/graphql/queries/AppQuery';\nimport { hasCredentials } from '../../api/user/UserSettings';\nimport { getUserAsync } from '../../api/user/user';\nimport * as Log from '../../log';\nimport { env, envIsWebcontainer } from '../../utils/env';\nimport { CommandError } from '../../utils/errors';\n\nconst debug = require('debug')('expo:start:server:ws-tunnel') as typeof console.log;\n\nexport interface AsyncWsTunnelOptions {\n useExpoAccount?: boolean;\n}\n\nexport class AsyncWsTunnel {\n private serverUrl: URL | null = null;\n\n constructor(\n private projectRoot: string,\n private port: number,\n private options: AsyncWsTunnelOptions = {}\n ) {}\n\n public getActiveUrl(): string | null {\n return this.serverUrl?.href ?? null;\n }\n\n async startAsync(): Promise<void> {\n this.serverUrl = await tunnel.startAsync({\n ...(await this.getTunnelOptionsAsync()),\n onStatusChange(status) {\n if (status === 'disconnected') {\n Log.error(\n chalk.red(\n 'Tunnel connection has been closed. This is often related to intermittent connection problems with the ws proxy servers. Restart the dev server to try connecting again.'\n ) + chalk.gray('\\nCheck the Expo status page for outages: https://status.expo.dev/')\n );\n }\n },\n });\n\n debug('Tunnel URL:', this.serverUrl.href);\n }\n\n private async getTunnelOptionsAsync(): Promise<tunnel.WsTunnelOptions> {\n if (this.options.useExpoAccount) {\n return this.getExpoAccountTunnelOptionsAsync();\n } else {\n return getLegacyTunnelOptions(this.port);\n }\n }\n\n private async getExpoAccountTunnelOptionsAsync(): Promise<tunnel.WsTunnelOptions> {\n const apiUrl = await getExpoAccountTunnelUrlAsync(this.projectRoot);\n if (!apiUrl) {\n const cause = hasCredentials()\n ? `Your Expo account may not have access to it, or the tunnel service is unavailable.`\n : `You're not logged in to your Expo account — run 'npx expo login'.`;\n throw new CommandError(\n 'WS_TUNNEL_SIGNED_URL',\n `Couldn't create a signed tunnel URL for this project. ${cause} ` +\n `Unset EXPO_UNSTABLE_TUNNEL_V2 to use an ngrok tunnel instead.`\n );\n }\n return { apiUrl, targetUrl: `http://localhost:${this.port}` };\n }\n\n async stopAsync(): Promise<void> {\n debug('Stopping Tunnel');\n await tunnel.stopAsync();\n this.serverUrl = null;\n }\n}\n\nfunction getLegacyTunnelOptions(port: number): tunnel.WsTunnelOptions {\n if (port !== 8081) {\n throw new CommandError(\n 'WS_TUNNEL_PORT',\n `WS-tunnel only supports tunneling over port 8081, attempted to use port ${port}`\n );\n }\n\n function randomSessionId(): string {\n const randomPart = () => (Math.random().toString(36) + '00000').slice(2, 7);\n return randomPart() + randomPart() + randomPart();\n }\n\n function getWebcontainerSession(): string {\n let session = randomSessionId();\n if (envIsWebcontainer()) {\n const leaseId = Buffer.from(hostname()).toString('base64url');\n const leaseFile = path.join(tmpdir(), `_ws_tunnel_lease_${leaseId}`);\n try {\n session = fs.readFileSync(leaseFile, 'utf8').trim() || session;\n } catch {}\n try {\n fs.writeFileSync(leaseFile, session, 'utf8');\n } catch {}\n }\n return session;\n }\n\n const userDefinedSubdomain = env.EXPO_TUNNEL_SUBDOMAIN;\n if (userDefinedSubdomain && typeof userDefinedSubdomain === 'string') {\n debug('Session:', userDefinedSubdomain);\n return { session: userDefinedSubdomain };\n }\n return { session: getWebcontainerSession() };\n}\n\nexport async function getExpoAccountTunnelUrlAsync(projectRoot: string): Promise<string | null> {\n async function resolveExpoAccountIdAsync(projectRoot: string): Promise<string | null> {\n const { exp } = getConfig(projectRoot, { skipSDKVersionRequirement: true });\n const easProjectId = exp.extra?.eas?.projectId as string | undefined | null;\n if (easProjectId) {\n try {\n const app = await AppQuery.byIdAsync(easProjectId);\n const appOwnerAccountId = app?.ownerAccount?.id;\n if (appOwnerAccountId) {\n return appOwnerAccountId;\n }\n } catch (error) {\n debug('Failed to resolve owning account from EAS project ID:', error);\n }\n }\n\n const actor = await getUserAsync();\n if (!actor) {\n return null;\n } else if (actor.__typename === 'User' || actor.__typename === 'SSOUser') {\n const actorPrimaryAccountId = actor.primaryAccount?.id;\n if (actorPrimaryAccountId) {\n return actorPrimaryAccountId;\n }\n }\n\n // Robots have no primary account; fall back to their first available account.\n return actor.accounts[0]?.id ?? null;\n }\n\n try {\n const accountId = await resolveExpoAccountIdAsync(projectRoot);\n if (!accountId) {\n debug('No Expo account available to create a signed tunnel URL; user is likely logged out.');\n return null;\n }\n const { url } = await TunnelMutation.createSignedTunnelUrlAsync(accountId);\n debug('Created signed tunnel URL for account:', accountId);\n return url;\n } catch (error) {\n debug('Failed to create a signed tunnel URL:', error);\n return null;\n }\n}\n"],"names":["AsyncWsTunnel","getExpoAccountTunnelUrlAsync","debug","require","projectRoot","port","options","serverUrl","getActiveUrl","href","startAsync","tunnel","getTunnelOptionsAsync","onStatusChange","status","Log","error","chalk","red","gray","useExpoAccount","getExpoAccountTunnelOptionsAsync","getLegacyTunnelOptions","apiUrl","cause","hasCredentials","CommandError","targetUrl","stopAsync","randomSessionId","randomPart","Math","random","toString","slice","getWebcontainerSession","session","envIsWebcontainer","leaseId","Buffer","from","hostname","leaseFile","path","join","tmpdir","fs","readFileSync","trim","writeFileSync","userDefinedSubdomain","env","EXPO_TUNNEL_SUBDOMAIN","resolveExpoAccountIdAsync","exp","actor","getConfig","skipSDKVersionRequirement","easProjectId","extra","eas","projectId","app","AppQuery","byIdAsync","appOwnerAccountId","ownerAccount","id","getUserAsync","__typename","actorPrimaryAccountId","primaryAccount","accounts","accountId","url","TunnelMutation","createSignedTunnelUrlAsync"],"mappings":";;;;;;;;;;;QAqBaA;eAAAA;;QAgGSC;eAAAA;;;;yBArHI;;;;;;;iEACF;;;;;;;gEACN;;;;;;;iEACE;;;;;;;yBACa;;;;;;;iEACX;;;;;;gCAES;0BACN;8BACM;sBACF;6DACR;qBACkB;wBACV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE7B,MAAMC,QAAQC,QAAQ,SAAS;AAMxB,MAAMH;IAGX,YACE,AAAQI,WAAmB,EAC3B,AAAQC,IAAY,EACpB,AAAQC,UAAgC,CAAC,CAAC,CAC1C;aAHQF,cAAAA;aACAC,OAAAA;aACAC,UAAAA;aALFC,YAAwB;IAM7B;IAEIC,eAA8B;YAC5B;QAAP,OAAO,EAAA,kBAAA,IAAI,CAACD,SAAS,qBAAd,gBAAgBE,IAAI,KAAI;IACjC;IAEA,MAAMC,aAA4B;QAChC,IAAI,CAACH,SAAS,GAAG,MAAMI,YAAOD,UAAU,CAAC;YACvC,GAAI,MAAM,IAAI,CAACE,qBAAqB,EAAE;YACtCC,gBAAeC,MAAM;gBACnB,IAAIA,WAAW,gBAAgB;oBAC7BC,KAAIC,KAAK,CACPC,gBAAK,CAACC,GAAG,CACP,6KACED,gBAAK,CAACE,IAAI,CAAC;gBAEnB;YACF;QACF;QAEAjB,MAAM,eAAe,IAAI,CAACK,SAAS,CAACE,IAAI;IAC1C;IAEA,MAAcG,wBAAyD;QACrE,IAAI,IAAI,CAACN,OAAO,CAACc,cAAc,EAAE;YAC/B,OAAO,IAAI,CAACC,gCAAgC;QAC9C,OAAO;YACL,OAAOC,uBAAuB,IAAI,CAACjB,IAAI;QACzC;IACF;IAEA,MAAcgB,mCAAoE;QAChF,MAAME,SAAS,MAAMtB,6BAA6B,IAAI,CAACG,WAAW;QAClE,IAAI,CAACmB,QAAQ;YACX,MAAMC,QAAQC,IAAAA,4BAAc,MACxB,CAAC,kFAAkF,CAAC,GACpF,CAAC,iEAAiE,CAAC;YACvE,MAAM,IAAIC,oBAAY,CACpB,wBACA,CAAC,sDAAsD,EAAEF,MAAM,CAAC,CAAC,GAC/D,CAAC,6DAA6D,CAAC;QAErE;QACA,OAAO;YAAED;YAAQI,WAAW,CAAC,iBAAiB,EAAE,IAAI,CAACtB,IAAI,EAAE;QAAC;IAC9D;IAEA,MAAMuB,YAA2B;QAC/B1B,MAAM;QACN,MAAMS,YAAOiB,SAAS;QACtB,IAAI,CAACrB,SAAS,GAAG;IACnB;AACF;AAEA,SAASe,uBAAuBjB,IAAY;IAC1C,IAAIA,SAAS,MAAM;QACjB,MAAM,IAAIqB,oBAAY,CACpB,kBACA,CAAC,wEAAwE,EAAErB,MAAM;IAErF;IAEA,SAASwB;QACP,MAAMC,aAAa,IAAM,AAACC,CAAAA,KAAKC,MAAM,GAAGC,QAAQ,CAAC,MAAM,OAAM,EAAGC,KAAK,CAAC,GAAG;QACzE,OAAOJ,eAAeA,eAAeA;IACvC;IAEA,SAASK;QACP,IAAIC,UAAUP;QACd,IAAIQ,IAAAA,sBAAiB,KAAI;YACvB,MAAMC,UAAUC,OAAOC,IAAI,CAACC,IAAAA,kBAAQ,KAAIR,QAAQ,CAAC;YACjD,MAAMS,YAAYC,YAAKC,IAAI,CAACC,IAAAA,gBAAM,KAAI,CAAC,iBAAiB,EAAEP,SAAS;YACnE,IAAI;gBACFF,UAAUU,UAAGC,YAAY,CAACL,WAAW,QAAQM,IAAI,MAAMZ;YACzD,EAAE,OAAM,CAAC;YACT,IAAI;gBACFU,UAAGG,aAAa,CAACP,WAAWN,SAAS;YACvC,EAAE,OAAM,CAAC;QACX;QACA,OAAOA;IACT;IAEA,MAAMc,uBAAuBC,QAAG,CAACC,qBAAqB;IACtD,IAAIF,wBAAwB,OAAOA,yBAAyB,UAAU;QACpEhD,MAAM,YAAYgD;QAClB,OAAO;YAAEd,SAASc;QAAqB;IACzC;IACA,OAAO;QAAEd,SAASD;IAAyB;AAC7C;AAEO,eAAelC,6BAA6BG,WAAmB;IACpE,eAAeiD,0BAA0BjD,WAAmB;YAErCkD,gBAAAA,YAwBdC;QAzBP,MAAM,EAAED,GAAG,EAAE,GAAGE,IAAAA,mBAAS,EAACpD,aAAa;YAAEqD,2BAA2B;QAAK;QACzE,MAAMC,gBAAeJ,aAAAA,IAAIK,KAAK,sBAATL,iBAAAA,WAAWM,GAAG,qBAAdN,eAAgBO,SAAS;QAC9C,IAAIH,cAAc;YAChB,IAAI;oBAEwBI;gBAD1B,MAAMA,MAAM,MAAMC,kBAAQ,CAACC,SAAS,CAACN;gBACrC,MAAMO,oBAAoBH,wBAAAA,oBAAAA,IAAKI,YAAY,qBAAjBJ,kBAAmBK,EAAE;gBAC/C,IAAIF,mBAAmB;oBACrB,OAAOA;gBACT;YACF,EAAE,OAAOjD,OAAO;gBACdd,MAAM,yDAAyDc;YACjE;QACF;QAEA,MAAMuC,QAAQ,MAAMa,IAAAA,kBAAY;QAChC,IAAI,CAACb,OAAO;YACV,OAAO;QACT,OAAO,IAAIA,MAAMc,UAAU,KAAK,UAAUd,MAAMc,UAAU,KAAK,WAAW;gBAC1Cd;YAA9B,MAAMe,yBAAwBf,wBAAAA,MAAMgB,cAAc,qBAApBhB,sBAAsBY,EAAE;YACtD,IAAIG,uBAAuB;gBACzB,OAAOA;YACT;QACF;QAEA,8EAA8E;QAC9E,OAAOf,EAAAA,mBAAAA,MAAMiB,QAAQ,CAAC,EAAE,qBAAjBjB,iBAAmBY,EAAE,KAAI;IAClC;IAEA,IAAI;QACF,MAAMM,YAAY,MAAMpB,0BAA0BjD;QAClD,IAAI,CAACqE,WAAW;YACdvE,MAAM;YACN,OAAO;QACT;QACA,MAAM,EAAEwE,GAAG,EAAE,GAAG,MAAMC,8BAAc,CAACC,0BAA0B,CAACH;QAChEvE,MAAM,0CAA0CuE;QAChD,OAAOC;IACT,EAAE,OAAO1D,OAAO;QACdd,MAAM,yCAAyCc;QAC/C,OAAO;IACT;AACF"}
|
|
@@ -189,15 +189,25 @@ class BundlerDevServer {
|
|
|
189
189
|
this.notifier = new _FileNotifier.FileNotifier(this.projectRoot, this.getConfigModuleIds());
|
|
190
190
|
this.notifier.startObserving();
|
|
191
191
|
}
|
|
192
|
-
/** Create
|
|
192
|
+
/** Create the tunnel instance and start the tunnel server. Exposed for testing. */ async _startTunnelAsync() {
|
|
193
193
|
var _this_getInstance;
|
|
194
194
|
const port = (_this_getInstance = this.getInstance()) == null ? void 0 : _this_getInstance.location.port;
|
|
195
195
|
if (!port) return null;
|
|
196
196
|
debug('[tunnel] connect to port: ' + port);
|
|
197
|
-
this.tunnel =
|
|
197
|
+
this.tunnel = this._createTunnel(port);
|
|
198
198
|
await this.tunnel.startAsync();
|
|
199
199
|
return this.tunnel;
|
|
200
200
|
}
|
|
201
|
+
/** Resolve which tunnel implementation to use, without starting it. */ _createTunnel(port) {
|
|
202
|
+
const useV2Tunnel = _env.env.EXPO_UNSTABLE_TUNNEL_V2 || (0, _env.envIsWebcontainer)();
|
|
203
|
+
if (useV2Tunnel) {
|
|
204
|
+
const useExpoAccount = !!_env.env.EXPO_UNSTABLE_TUNNEL_V2;
|
|
205
|
+
return new _AsyncWsTunnel.AsyncWsTunnel(this.projectRoot, port, {
|
|
206
|
+
useExpoAccount
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return new _AsyncNgrok.AsyncNgrok(this.projectRoot, port);
|
|
210
|
+
}
|
|
201
211
|
async startDevSessionAsync() {
|
|
202
212
|
// This is used to make Expo Go open the project in either Expo Go, or the web browser.
|
|
203
213
|
// Must come after ngrok (`startTunnelAsync`) setup.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/start/server/BundlerDevServer.ts"],"sourcesContent":["import assert from 'assert';\nimport resolveFrom from 'resolve-from';\n\nimport { AsyncNgrok } from './AsyncNgrok';\nimport { AsyncWsTunnel } from './AsyncWsTunnel';\nimport { Bonjour } from './Bonjour';\nimport DevToolsPluginManager from './DevToolsPluginManager';\nimport { DevelopmentSession } from './DevelopmentSession';\nimport type { CreateURLOptions } from './UrlCreator';\nimport { UrlCreator } from './UrlCreator';\nimport type { PlatformBundlers } from './platformBundlers';\nimport * as Log from '../../log';\nimport { FileNotifier } from '../../utils/FileNotifier';\nimport { resolveWithTimeout } from '../../utils/delay';\nimport { env, envIsWebcontainer } from '../../utils/env';\nimport { CommandError } from '../../utils/errors';\nimport { isInteractive } from '../../utils/interactive';\nimport { openBrowserAsync } from '../../utils/open';\nimport type { BaseResolveDeviceProps, PlatformManager } from '../platforms/PlatformManager';\n\nconst debug = require('debug')('expo:start:server:devServer') as typeof console.log;\n\nexport type MessageSocket = {\n broadcast: (method: string, params?: Record<string, any> | undefined) => void;\n};\n\nexport type ServerLike = {\n close(callback?: (err?: Error) => void): void;\n addListener?(event: string, listener: (...args: any[]) => void): unknown;\n};\n\nexport type DevServerInstance = {\n /** Bundler dev server instance. */\n server: ServerLike;\n /** Dev server URL location properties. */\n location: {\n url: string;\n port: number;\n protocol: 'http' | 'https';\n host?: string;\n };\n /** Additional middleware that's attached to the `server`. */\n middleware: any;\n /** Message socket for communicating with the runtime. */\n messageSocket: MessageSocket;\n};\n\nexport interface BundlerStartOptions {\n /** Should the dev server use `https` protocol. */\n https?: boolean;\n /** Should start the dev servers in development mode (minify). */\n mode?: 'development' | 'production';\n /** Is dev client enabled. */\n devClient?: boolean;\n /** Should run dev servers with clean caches. */\n resetDevServer?: boolean;\n /** Code signing private key path (defaults to same directory as certificate) */\n privateKeyPath?: string;\n\n /** Max amount of workers (threads) to use with Metro bundler, defaults to undefined for max workers. */\n maxWorkers?: number;\n /** Port to start the dev server on. */\n port?: number;\n\n /** Should start a headless dev server e.g. mock representation to approximate info from a server running in a different process. */\n headless?: boolean;\n /** Should instruct the bundler to create minified bundles. */\n minify?: boolean;\n\n /** Will the bundler be used for exporting. NOTE: This is an odd option to pass to the dev server. */\n isExporting?: boolean;\n\n // Webpack options\n /** Should modify and create PWA icons. */\n isImageEditingEnabled?: boolean;\n\n location: CreateURLOptions;\n}\n\nconst PLATFORM_MANAGERS = {\n simulator: () =>\n require('../platforms/ios/ApplePlatformManager')\n .ApplePlatformManager as typeof import('../platforms/ios/ApplePlatformManager').ApplePlatformManager,\n emulator: () =>\n require('../platforms/android/AndroidPlatformManager')\n .AndroidPlatformManager as typeof import('../platforms/android/AndroidPlatformManager').AndroidPlatformManager,\n};\n\ntype PlatformManagers = {\n [K in keyof typeof PLATFORM_MANAGERS]: InstanceType<ReturnType<(typeof PLATFORM_MANAGERS)[K]>>;\n};\n\ntype PlatformDevice<Platform extends keyof PlatformManagers> =\n PlatformManagers[Platform] extends PlatformManager<infer Device, any> ? Device : never;\n\ntype PlatformLaunchProps<Platform extends keyof PlatformManagers> =\n PlatformManagers[Platform] extends PlatformManager<any, infer LaunchProps> ? LaunchProps : never;\n\nexport abstract class BundlerDevServer {\n /** Name of the bundler. */\n abstract get name(): string;\n\n /** Tunnel instance for managing tunnel connections. */\n protected tunnel: AsyncNgrok | AsyncWsTunnel | null = null;\n /** Interfaces with the Expo 'Development Session' API. */\n protected devSession: DevelopmentSession | null = null;\n /** Announces dev server via Bonjour */\n protected bonjour: Bonjour | null = null;\n /** Http server and related info. */\n protected instance: DevServerInstance | null = null;\n /** Native platform interfaces for opening projects. */\n private platformManagers: { [K in keyof PlatformManagers]?: PlatformManagers[K] | undefined } =\n {};\n /** Manages the creation of dev server URLs. */\n protected urlCreator?: UrlCreator | null = null;\n\n private notifier: FileNotifier | null = null;\n protected readonly devToolsPluginManager: DevToolsPluginManager;\n public isDevClient: boolean;\n\n constructor(\n /** Project root folder. */\n public projectRoot: string,\n /** A mapping of bundlers to platforms. */\n public platformBundlers: PlatformBundlers,\n /** Advanced options */\n options?: {\n /**\n * The instance of DevToolsPluginManager\n * @default new DevToolsPluginManager(projectRoot)\n */\n devToolsPluginManager?: DevToolsPluginManager;\n // TODO: Replace with custom scheme maybe...\n isDevClient?: boolean;\n }\n ) {\n this.devToolsPluginManager =\n options?.devToolsPluginManager ?? new DevToolsPluginManager(projectRoot);\n this.isDevClient = options?.isDevClient ?? false;\n }\n\n protected setInstance(instance: DevServerInstance) {\n this.instance = instance;\n }\n\n /** Get the manifest middleware function. */\n protected async getManifestMiddlewareAsync(\n options: Pick<BundlerStartOptions, 'minify' | 'mode' | 'privateKeyPath'> = {}\n ) {\n const Middleware = require('./middleware/ExpoGoManifestHandlerMiddleware')\n .ExpoGoManifestHandlerMiddleware as typeof import('./middleware/ExpoGoManifestHandlerMiddleware').ExpoGoManifestHandlerMiddleware;\n\n const urlCreator = this.getUrlCreator();\n const middleware = new Middleware(this.projectRoot, {\n constructUrl: urlCreator.constructUrl.bind(urlCreator),\n mode: options.mode,\n minify: options.minify,\n isNativeWebpack: this.name === 'webpack' && this.isTargetingNative(),\n privateKeyPath: options.privateKeyPath,\n });\n return middleware;\n }\n\n /** Start the dev server using settings defined in the start command. */\n public async startAsync(options: BundlerStartOptions): Promise<DevServerInstance> {\n await this.stopAsync();\n\n let instance: DevServerInstance;\n if (options.headless) {\n instance = await this.startHeadlessAsync(options);\n } else {\n instance = await this.startImplementationAsync(options);\n }\n\n this.setInstance(instance);\n await this.postStartAsync(options);\n return instance;\n }\n\n protected abstract startImplementationAsync(\n options: BundlerStartOptions\n ): Promise<DevServerInstance>;\n\n public async waitForTypeScriptAsync(): Promise<boolean> {\n return false;\n }\n\n public abstract startTypeScriptServices(): Promise<void>;\n\n public async watchEnvironmentVariables(): Promise<void> {\n // noop -- We've only implemented this functionality in Metro.\n }\n\n /**\n * Creates a mock server representation that can be used to estimate URLs for a server started in another process.\n * This is used for the run commands where you can reuse the server from a previous run.\n */\n private async startHeadlessAsync(options: BundlerStartOptions): Promise<DevServerInstance> {\n if (!options.port)\n throw new CommandError('HEADLESS_SERVER', 'headless dev server requires a port option');\n await this.initUrlCreator(options);\n return {\n // Create a mock server\n server: {\n close: (callback: () => void) => {\n this.instance = null;\n callback?.();\n },\n addListener() {},\n },\n location: {\n // The port is the main thing we want to send back.\n port: options.port,\n // localhost isn't always correct.\n host: 'localhost',\n // http is the only supported protocol on native.\n url: `http://localhost:${options.port}`,\n protocol: 'http',\n },\n middleware: {},\n messageSocket: {\n broadcast: () => {\n throw new CommandError('HEADLESS_SERVER', 'Cannot broadcast messages to headless server');\n },\n },\n };\n }\n\n /**\n * Runs after the `startAsync` function, performing any additional common operations.\n * You can assume the dev server is started by the time this function is called.\n */\n protected async postStartAsync(options: BundlerStartOptions) {\n if (\n options.location.hostType === 'tunnel' &&\n !env.EXPO_OFFLINE &&\n // This is a hack to prevent using tunnel on web since we block it upstream for some reason.\n this.isTargetingNative()\n ) {\n await this._startTunnelAsync();\n } else if (envIsWebcontainer()) {\n await this._startTunnelAsync();\n }\n\n if (!options.isExporting) {\n await Promise.all([this.startDevSessionAsync(), this.startBonjourAsync()]);\n this.watchConfig();\n }\n }\n\n protected abstract getConfigModuleIds(): string[];\n\n protected watchConfig() {\n this.notifier?.stopObserving();\n this.notifier = new FileNotifier(this.projectRoot, this.getConfigModuleIds());\n this.notifier.startObserving();\n }\n\n /** Create ngrok instance and start the tunnel server. Exposed for testing. */\n public async _startTunnelAsync(): Promise<AsyncNgrok | AsyncWsTunnel | null> {\n const port = this.getInstance()?.location.port;\n if (!port) return null;\n debug('[tunnel] connect to port: ' + port);\n this.tunnel = envIsWebcontainer()\n ? new AsyncWsTunnel(this.projectRoot, port)\n : new AsyncNgrok(this.projectRoot, port);\n await this.tunnel.startAsync();\n return this.tunnel;\n }\n\n protected async startDevSessionAsync() {\n // This is used to make Expo Go open the project in either Expo Go, or the web browser.\n // Must come after ngrok (`startTunnelAsync`) setup.\n this.devSession = new DevelopmentSession(\n this.projectRoot,\n // This URL will be used on external devices so the computer IP won't be relevant.\n this.isTargetingNative()\n ? this.getNativeRuntimeUrl()\n : this.getDevServerUrl({ hostType: 'localhost' })\n );\n\n await this.devSession.startAsync({\n runtime: this.isTargetingNative() ? 'native' : 'web',\n });\n }\n\n protected async startBonjourAsync() {\n // This is used to make Expo Go open the project in either Expo Go, or the web browser.\n // Must come after ngrok (`startTunnelAsync`) setup.\n if (!this.bonjour) {\n this.bonjour = new Bonjour(this.projectRoot, this.getInstance()?.location.port);\n }\n\n await this.bonjour.announceAsync({});\n }\n\n public isTargetingNative() {\n // Temporary hack while we implement multi-bundler dev server proxy.\n return true;\n }\n\n public isTargetingWeb() {\n return this.platformBundlers.web === this.name;\n }\n\n /**\n * Sends a message over web sockets to any connected device,\n * does nothing when the dev server is not running.\n *\n * @param method name of the command. In RN projects `reload`, and `devMenu` are available. In Expo Go, `sendDevCommand` is available.\n * @param params\n */\n public broadcastMessage(\n method: 'reload' | 'devMenu' | 'sendDevCommand',\n params?: Record<string, any>\n ) {\n this.getInstance()?.messageSocket.broadcast(method, params);\n }\n\n /** Get the running dev server instance. */\n public getInstance() {\n return this.instance;\n }\n\n /** Stop the running dev server instance. */\n async stopAsync() {\n // Reset url creator\n this.urlCreator = undefined;\n\n // Stop file watching.\n this.notifier?.stopObserving();\n\n await Promise.all([\n // Stop the bonjour advertiser\n this.bonjour?.closeAsync(),\n // Stop the dev session timer and tell Expo API to remove dev session.\n this.devSession?.closeAsync(),\n ]);\n\n // Stop tunnel if running.\n await this.tunnel?.stopAsync().catch((e) => {\n Log.error(`Error stopping tunnel:`);\n Log.exception(e);\n });\n\n return resolveWithTimeout(\n () =>\n new Promise<void>((resolve, reject) => {\n // Close the server.\n debug(`Stopping dev server (bundler: ${this.name})`);\n\n if (this.instance?.server) {\n // Check if server is even running.\n this.instance.server.close((error) => {\n debug(`Stopped dev server (bundler: ${this.name})`);\n this.instance = null;\n if (error) {\n if ('code' in error && error.code === 'ERR_SERVER_NOT_RUNNING') {\n resolve();\n } else {\n reject(error);\n }\n } else {\n resolve();\n }\n });\n } else {\n debug(`Stopped dev server (bundler: ${this.name})`);\n this.instance = null;\n resolve();\n }\n }),\n {\n // NOTE(Bacon): Metro dev server doesn't seem to be closing in time.\n timeout: 1000,\n errorMessage: `Timeout waiting for '${this.name}' dev server to close`,\n }\n );\n }\n\n // TODO(@kitten): This should be created top-down rather than bottom up from implementors\n protected async initUrlCreator(\n options: Partial<Pick<BundlerStartOptions, 'port' | 'location'>> = {}\n ) {\n assert(options?.port, 'Dev server instance not found');\n assert(!this.urlCreator, 'Dev server is already initialized');\n const urlCreator = await UrlCreator.init(options.location, {\n port: options.port,\n getTunnelUrl: this.getTunnelUrl.bind(this),\n });\n this.urlCreator = urlCreator;\n return urlCreator;\n }\n\n public getUrlCreator() {\n assert(this.urlCreator, 'Dev server is uninitialized');\n return this.urlCreator;\n }\n\n public getNativeRuntimeUrl(opts: Partial<CreateURLOptions> = {}) {\n return this.isDevClient\n ? (this.getUrlCreator().constructDevClientUrl(opts) ?? this.getDevServerUrl())\n : this.getUrlCreator().constructUrl({ ...opts, scheme: 'exp' });\n }\n\n /** Get the URL for the running instance of the dev server. */\n public getDevServerUrl(options: { hostType?: 'localhost' } = {}): string | null {\n const instance = this.getInstance();\n if (!instance?.location) {\n return null;\n }\n\n // If we have an active WS tunnel instance, we always need to return the tunnel location.\n if (this.tunnel && this.tunnel instanceof AsyncWsTunnel) {\n return this.getUrlCreator().constructUrl();\n }\n\n const { location } = instance;\n if (options.hostType === 'localhost') {\n return `${location.protocol}://localhost:${location.port}`;\n }\n\n return location.url ?? null;\n }\n\n public getDevServerUrlOrAssert(options: { hostType?: 'localhost' } = {}): string {\n const instance = this.getDevServerUrl(options);\n if (!instance) {\n throw new CommandError(\n 'DEV_SERVER',\n `Cannot get the dev server URL before the server has started - bundler[${this.name}]`\n );\n }\n\n return instance;\n }\n\n /** Get the base URL for JS inspector */\n public getJsInspectorBaseUrl(): string {\n if (this.name !== 'metro') {\n throw new CommandError(\n 'DEV_SERVER',\n `Cannot get the JS inspector base url - bundler[${this.name}]`\n );\n }\n return this.getUrlCreator().constructUrl({ scheme: 'http' });\n }\n\n /** Get the tunnel URL from the tunnel. */\n public getTunnelUrl(): string | null {\n return this.tunnel?.getActiveUrl() ?? null;\n }\n\n /** Open the dev server in a runtime. */\n public async openPlatformAsync(\n launchTarget: keyof PlatformManagers | 'desktop',\n resolver: BaseResolveDeviceProps<any> = {}\n ) {\n if (launchTarget === 'desktop') {\n const serverUrl = this.getDevServerUrl({ hostType: 'localhost' });\n // Allow opening the tunnel URL when using Metro web.\n const url = this.name === 'metro' ? (this.getTunnelUrl() ?? serverUrl) : serverUrl;\n // Only launch the browser automatically if the process is interactive, otherwise we'll assume it's an agent.\n if (isInteractive()) {\n await openBrowserAsync(url!);\n }\n return { url };\n }\n\n const runtime = this.isTargetingNative() ? (this.isDevClient ? 'custom' : 'expo') : 'web';\n const manager = await this.getPlatformManagerAsync(launchTarget);\n return manager.openAsync({ runtime }, resolver);\n }\n\n /** Open the dev server in a runtime. */\n public async openCustomRuntimeAsync<Platform extends keyof PlatformManagers>(\n launchTarget: Platform,\n launchProps: Partial<PlatformLaunchProps<Platform>> = {},\n resolver: BaseResolveDeviceProps<PlatformDevice<Platform>> = {}\n ) {\n const runtime = this.isTargetingNative() ? (this.isDevClient ? 'custom' : 'expo') : 'web';\n if (runtime !== 'custom') {\n throw new CommandError(\n `dev server cannot open custom runtimes either because it does not target native platforms or because it is not targeting dev clients. (target: ${runtime})`\n );\n }\n\n const manager = await this.getPlatformManagerAsync(launchTarget);\n return manager.openAsync(\n { runtime: 'custom', props: launchProps },\n resolver as BaseResolveDeviceProps<any>\n );\n }\n\n /** Get the URL for opening in Expo Go. */\n protected getExpoGoUrl(): string {\n return this.getUrlCreator().constructUrl({ scheme: 'exp' });\n }\n\n /** Should use the interstitial page for selecting which runtime to use. */\n protected isRedirectPageEnabled(): boolean {\n return (\n !env.EXPO_NO_REDIRECT_PAGE &&\n // if user passed --dev-client flag, skip interstitial page\n !this.isDevClient &&\n // Checks if dev client is installed.\n !!resolveFrom.silent(this.projectRoot, 'expo-dev-client')\n );\n }\n\n /** Get the redirect URL when redirecting is enabled. */\n public getRedirectUrl(platform: keyof PlatformManagers | null = null): string | null {\n if (!this.isRedirectPageEnabled()) {\n debug('Redirect page is disabled');\n return null;\n }\n\n return (\n this.getUrlCreator().constructLoadingUrl(\n {},\n platform === 'emulator' ? 'android' : platform === 'simulator' ? 'ios' : null\n ) ?? null\n );\n }\n\n protected async getPlatformManagerAsync<Platform extends keyof PlatformManagers>(\n ofPlatform: Platform\n ): Promise<PlatformManagers[Platform]> {\n const platform: keyof PlatformManagers = ofPlatform;\n if (!this.platformManagers[platform]) {\n const port = this.getInstance()?.location.port;\n if (!port || !this.urlCreator) {\n throw new CommandError(\n 'DEV_SERVER',\n 'Cannot interact with native platforms until dev server has started'\n );\n }\n debug(`Creating platform manager (platform: ${platform}, port: ${port})`);\n const managerParams = {\n getCustomRuntimeUrl: this.urlCreator.constructDevClientUrl.bind(this.urlCreator),\n getExpoGoUrl: this.getExpoGoUrl.bind(this),\n getRedirectUrl: this.getRedirectUrl.bind(this, platform),\n getDevServerUrl: this.getDevServerUrl.bind(this, { hostType: 'localhost' }),\n };\n switch (platform) {\n case 'simulator': {\n const Manager = PLATFORM_MANAGERS[platform]();\n this.platformManagers[platform] = new Manager(this.projectRoot, port, managerParams);\n break;\n }\n case 'emulator': {\n const Manager = PLATFORM_MANAGERS[platform]();\n this.platformManagers[platform] = new Manager(this.projectRoot, port, managerParams);\n break;\n }\n }\n }\n return this.platformManagers[platform] as PlatformManagers[Platform];\n }\n}\n"],"names":["BundlerDevServer","debug","require","PLATFORM_MANAGERS","simulator","ApplePlatformManager","emulator","AndroidPlatformManager","projectRoot","platformBundlers","options","tunnel","devSession","bonjour","instance","platformManagers","urlCreator","notifier","devToolsPluginManager","DevToolsPluginManager","isDevClient","setInstance","getManifestMiddlewareAsync","Middleware","ExpoGoManifestHandlerMiddleware","getUrlCreator","middleware","constructUrl","bind","mode","minify","isNativeWebpack","name","isTargetingNative","privateKeyPath","startAsync","stopAsync","headless","startHeadlessAsync","startImplementationAsync","postStartAsync","waitForTypeScriptAsync","watchEnvironmentVariables","port","CommandError","initUrlCreator","server","close","callback","addListener","location","host","url","protocol","messageSocket","broadcast","hostType","env","EXPO_OFFLINE","_startTunnelAsync","envIsWebcontainer","isExporting","Promise","all","startDevSessionAsync","startBonjourAsync","watchConfig","stopObserving","FileNotifier","getConfigModuleIds","startObserving","getInstance","AsyncWsTunnel","AsyncNgrok","DevelopmentSession","getNativeRuntimeUrl","getDevServerUrl","runtime","Bonjour","announceAsync","isTargetingWeb","web","broadcastMessage","method","params","undefined","closeAsync","catch","e","Log","error","exception","resolveWithTimeout","resolve","reject","code","timeout","errorMessage","assert","UrlCreator","init","getTunnelUrl","opts","constructDevClientUrl","scheme","getDevServerUrlOrAssert","getJsInspectorBaseUrl","getActiveUrl","openPlatformAsync","launchTarget","resolver","serverUrl","isInteractive","openBrowserAsync","manager","getPlatformManagerAsync","openAsync","openCustomRuntimeAsync","launchProps","props","getExpoGoUrl","isRedirectPageEnabled","EXPO_NO_REDIRECT_PAGE","resolveFrom","silent","getRedirectUrl","platform","constructLoadingUrl","ofPlatform","managerParams","getCustomRuntimeUrl","Manager"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/start/server/BundlerDevServer.ts"],"sourcesContent":["import assert from 'assert';\nimport resolveFrom from 'resolve-from';\n\nimport { AsyncNgrok } from './AsyncNgrok';\nimport { AsyncWsTunnel } from './AsyncWsTunnel';\nimport { Bonjour } from './Bonjour';\nimport DevToolsPluginManager from './DevToolsPluginManager';\nimport { DevelopmentSession } from './DevelopmentSession';\nimport type { CreateURLOptions } from './UrlCreator';\nimport { UrlCreator } from './UrlCreator';\nimport type { PlatformBundlers } from './platformBundlers';\nimport * as Log from '../../log';\nimport { FileNotifier } from '../../utils/FileNotifier';\nimport { resolveWithTimeout } from '../../utils/delay';\nimport { env, envIsWebcontainer } from '../../utils/env';\nimport { CommandError } from '../../utils/errors';\nimport { isInteractive } from '../../utils/interactive';\nimport { openBrowserAsync } from '../../utils/open';\nimport type { BaseResolveDeviceProps, PlatformManager } from '../platforms/PlatformManager';\n\nconst debug = require('debug')('expo:start:server:devServer') as typeof console.log;\n\nexport type MessageSocket = {\n broadcast: (method: string, params?: Record<string, any> | undefined) => void;\n};\n\nexport type ServerLike = {\n close(callback?: (err?: Error) => void): void;\n addListener?(event: string, listener: (...args: any[]) => void): unknown;\n};\n\nexport type DevServerInstance = {\n /** Bundler dev server instance. */\n server: ServerLike;\n /** Dev server URL location properties. */\n location: {\n url: string;\n port: number;\n protocol: 'http' | 'https';\n host?: string;\n };\n /** Additional middleware that's attached to the `server`. */\n middleware: any;\n /** Message socket for communicating with the runtime. */\n messageSocket: MessageSocket;\n};\n\nexport interface BundlerStartOptions {\n /** Should the dev server use `https` protocol. */\n https?: boolean;\n /** Should start the dev servers in development mode (minify). */\n mode?: 'development' | 'production';\n /** Is dev client enabled. */\n devClient?: boolean;\n /** Should run dev servers with clean caches. */\n resetDevServer?: boolean;\n /** Code signing private key path (defaults to same directory as certificate) */\n privateKeyPath?: string;\n\n /** Max amount of workers (threads) to use with Metro bundler, defaults to undefined for max workers. */\n maxWorkers?: number;\n /** Port to start the dev server on. */\n port?: number;\n\n /** Should start a headless dev server e.g. mock representation to approximate info from a server running in a different process. */\n headless?: boolean;\n /** Should instruct the bundler to create minified bundles. */\n minify?: boolean;\n\n /** Will the bundler be used for exporting. NOTE: This is an odd option to pass to the dev server. */\n isExporting?: boolean;\n\n // Webpack options\n /** Should modify and create PWA icons. */\n isImageEditingEnabled?: boolean;\n\n location: CreateURLOptions;\n}\n\nconst PLATFORM_MANAGERS = {\n simulator: () =>\n require('../platforms/ios/ApplePlatformManager')\n .ApplePlatformManager as typeof import('../platforms/ios/ApplePlatformManager').ApplePlatformManager,\n emulator: () =>\n require('../platforms/android/AndroidPlatformManager')\n .AndroidPlatformManager as typeof import('../platforms/android/AndroidPlatformManager').AndroidPlatformManager,\n};\n\ntype PlatformManagers = {\n [K in keyof typeof PLATFORM_MANAGERS]: InstanceType<ReturnType<(typeof PLATFORM_MANAGERS)[K]>>;\n};\n\ntype PlatformDevice<Platform extends keyof PlatformManagers> =\n PlatformManagers[Platform] extends PlatformManager<infer Device, any> ? Device : never;\n\ntype PlatformLaunchProps<Platform extends keyof PlatformManagers> =\n PlatformManagers[Platform] extends PlatformManager<any, infer LaunchProps> ? LaunchProps : never;\n\nexport abstract class BundlerDevServer {\n /** Name of the bundler. */\n abstract get name(): string;\n\n /** Tunnel instance for managing tunnel connections. */\n protected tunnel: AsyncNgrok | AsyncWsTunnel | null = null;\n /** Interfaces with the Expo 'Development Session' API. */\n protected devSession: DevelopmentSession | null = null;\n /** Announces dev server via Bonjour */\n protected bonjour: Bonjour | null = null;\n /** Http server and related info. */\n protected instance: DevServerInstance | null = null;\n /** Native platform interfaces for opening projects. */\n private platformManagers: { [K in keyof PlatformManagers]?: PlatformManagers[K] | undefined } =\n {};\n /** Manages the creation of dev server URLs. */\n protected urlCreator?: UrlCreator | null = null;\n\n private notifier: FileNotifier | null = null;\n protected readonly devToolsPluginManager: DevToolsPluginManager;\n public isDevClient: boolean;\n\n constructor(\n /** Project root folder. */\n public projectRoot: string,\n /** A mapping of bundlers to platforms. */\n public platformBundlers: PlatformBundlers,\n /** Advanced options */\n options?: {\n /**\n * The instance of DevToolsPluginManager\n * @default new DevToolsPluginManager(projectRoot)\n */\n devToolsPluginManager?: DevToolsPluginManager;\n // TODO: Replace with custom scheme maybe...\n isDevClient?: boolean;\n }\n ) {\n this.devToolsPluginManager =\n options?.devToolsPluginManager ?? new DevToolsPluginManager(projectRoot);\n this.isDevClient = options?.isDevClient ?? false;\n }\n\n protected setInstance(instance: DevServerInstance) {\n this.instance = instance;\n }\n\n /** Get the manifest middleware function. */\n protected async getManifestMiddlewareAsync(\n options: Pick<BundlerStartOptions, 'minify' | 'mode' | 'privateKeyPath'> = {}\n ) {\n const Middleware = require('./middleware/ExpoGoManifestHandlerMiddleware')\n .ExpoGoManifestHandlerMiddleware as typeof import('./middleware/ExpoGoManifestHandlerMiddleware').ExpoGoManifestHandlerMiddleware;\n\n const urlCreator = this.getUrlCreator();\n const middleware = new Middleware(this.projectRoot, {\n constructUrl: urlCreator.constructUrl.bind(urlCreator),\n mode: options.mode,\n minify: options.minify,\n isNativeWebpack: this.name === 'webpack' && this.isTargetingNative(),\n privateKeyPath: options.privateKeyPath,\n });\n return middleware;\n }\n\n /** Start the dev server using settings defined in the start command. */\n public async startAsync(options: BundlerStartOptions): Promise<DevServerInstance> {\n await this.stopAsync();\n\n let instance: DevServerInstance;\n if (options.headless) {\n instance = await this.startHeadlessAsync(options);\n } else {\n instance = await this.startImplementationAsync(options);\n }\n\n this.setInstance(instance);\n await this.postStartAsync(options);\n return instance;\n }\n\n protected abstract startImplementationAsync(\n options: BundlerStartOptions\n ): Promise<DevServerInstance>;\n\n public async waitForTypeScriptAsync(): Promise<boolean> {\n return false;\n }\n\n public abstract startTypeScriptServices(): Promise<void>;\n\n public async watchEnvironmentVariables(): Promise<void> {\n // noop -- We've only implemented this functionality in Metro.\n }\n\n /**\n * Creates a mock server representation that can be used to estimate URLs for a server started in another process.\n * This is used for the run commands where you can reuse the server from a previous run.\n */\n private async startHeadlessAsync(options: BundlerStartOptions): Promise<DevServerInstance> {\n if (!options.port)\n throw new CommandError('HEADLESS_SERVER', 'headless dev server requires a port option');\n await this.initUrlCreator(options);\n return {\n // Create a mock server\n server: {\n close: (callback: () => void) => {\n this.instance = null;\n callback?.();\n },\n addListener() {},\n },\n location: {\n // The port is the main thing we want to send back.\n port: options.port,\n // localhost isn't always correct.\n host: 'localhost',\n // http is the only supported protocol on native.\n url: `http://localhost:${options.port}`,\n protocol: 'http',\n },\n middleware: {},\n messageSocket: {\n broadcast: () => {\n throw new CommandError('HEADLESS_SERVER', 'Cannot broadcast messages to headless server');\n },\n },\n };\n }\n\n /**\n * Runs after the `startAsync` function, performing any additional common operations.\n * You can assume the dev server is started by the time this function is called.\n */\n protected async postStartAsync(options: BundlerStartOptions) {\n if (\n options.location.hostType === 'tunnel' &&\n !env.EXPO_OFFLINE &&\n // This is a hack to prevent using tunnel on web since we block it upstream for some reason.\n this.isTargetingNative()\n ) {\n await this._startTunnelAsync();\n } else if (envIsWebcontainer()) {\n await this._startTunnelAsync();\n }\n\n if (!options.isExporting) {\n await Promise.all([this.startDevSessionAsync(), this.startBonjourAsync()]);\n this.watchConfig();\n }\n }\n\n protected abstract getConfigModuleIds(): string[];\n\n protected watchConfig() {\n this.notifier?.stopObserving();\n this.notifier = new FileNotifier(this.projectRoot, this.getConfigModuleIds());\n this.notifier.startObserving();\n }\n\n /** Create the tunnel instance and start the tunnel server. Exposed for testing. */\n public async _startTunnelAsync(): Promise<AsyncNgrok | AsyncWsTunnel | null> {\n const port = this.getInstance()?.location.port;\n if (!port) return null;\n debug('[tunnel] connect to port: ' + port);\n this.tunnel = this._createTunnel(port);\n await this.tunnel.startAsync();\n return this.tunnel;\n }\n\n /** Resolve which tunnel implementation to use, without starting it. */\n private _createTunnel(port: number): AsyncNgrok | AsyncWsTunnel {\n const useV2Tunnel = env.EXPO_UNSTABLE_TUNNEL_V2 || envIsWebcontainer();\n if (useV2Tunnel) {\n const useExpoAccount = !!env.EXPO_UNSTABLE_TUNNEL_V2;\n return new AsyncWsTunnel(this.projectRoot, port, { useExpoAccount });\n }\n\n return new AsyncNgrok(this.projectRoot, port);\n }\n\n protected async startDevSessionAsync() {\n // This is used to make Expo Go open the project in either Expo Go, or the web browser.\n // Must come after ngrok (`startTunnelAsync`) setup.\n this.devSession = new DevelopmentSession(\n this.projectRoot,\n // This URL will be used on external devices so the computer IP won't be relevant.\n this.isTargetingNative()\n ? this.getNativeRuntimeUrl()\n : this.getDevServerUrl({ hostType: 'localhost' })\n );\n\n await this.devSession.startAsync({\n runtime: this.isTargetingNative() ? 'native' : 'web',\n });\n }\n\n protected async startBonjourAsync() {\n // This is used to make Expo Go open the project in either Expo Go, or the web browser.\n // Must come after ngrok (`startTunnelAsync`) setup.\n if (!this.bonjour) {\n this.bonjour = new Bonjour(this.projectRoot, this.getInstance()?.location.port);\n }\n\n await this.bonjour.announceAsync({});\n }\n\n public isTargetingNative() {\n // Temporary hack while we implement multi-bundler dev server proxy.\n return true;\n }\n\n public isTargetingWeb() {\n return this.platformBundlers.web === this.name;\n }\n\n /**\n * Sends a message over web sockets to any connected device,\n * does nothing when the dev server is not running.\n *\n * @param method name of the command. In RN projects `reload`, and `devMenu` are available. In Expo Go, `sendDevCommand` is available.\n * @param params\n */\n public broadcastMessage(\n method: 'reload' | 'devMenu' | 'sendDevCommand',\n params?: Record<string, any>\n ) {\n this.getInstance()?.messageSocket.broadcast(method, params);\n }\n\n /** Get the running dev server instance. */\n public getInstance() {\n return this.instance;\n }\n\n /** Stop the running dev server instance. */\n async stopAsync() {\n // Reset url creator\n this.urlCreator = undefined;\n\n // Stop file watching.\n this.notifier?.stopObserving();\n\n await Promise.all([\n // Stop the bonjour advertiser\n this.bonjour?.closeAsync(),\n // Stop the dev session timer and tell Expo API to remove dev session.\n this.devSession?.closeAsync(),\n ]);\n\n // Stop tunnel if running.\n await this.tunnel?.stopAsync().catch((e) => {\n Log.error(`Error stopping tunnel:`);\n Log.exception(e);\n });\n\n return resolveWithTimeout(\n () =>\n new Promise<void>((resolve, reject) => {\n // Close the server.\n debug(`Stopping dev server (bundler: ${this.name})`);\n\n if (this.instance?.server) {\n // Check if server is even running.\n this.instance.server.close((error) => {\n debug(`Stopped dev server (bundler: ${this.name})`);\n this.instance = null;\n if (error) {\n if ('code' in error && error.code === 'ERR_SERVER_NOT_RUNNING') {\n resolve();\n } else {\n reject(error);\n }\n } else {\n resolve();\n }\n });\n } else {\n debug(`Stopped dev server (bundler: ${this.name})`);\n this.instance = null;\n resolve();\n }\n }),\n {\n // NOTE(Bacon): Metro dev server doesn't seem to be closing in time.\n timeout: 1000,\n errorMessage: `Timeout waiting for '${this.name}' dev server to close`,\n }\n );\n }\n\n // TODO(@kitten): This should be created top-down rather than bottom up from implementors\n protected async initUrlCreator(\n options: Partial<Pick<BundlerStartOptions, 'port' | 'location'>> = {}\n ) {\n assert(options?.port, 'Dev server instance not found');\n assert(!this.urlCreator, 'Dev server is already initialized');\n const urlCreator = await UrlCreator.init(options.location, {\n port: options.port,\n getTunnelUrl: this.getTunnelUrl.bind(this),\n });\n this.urlCreator = urlCreator;\n return urlCreator;\n }\n\n public getUrlCreator() {\n assert(this.urlCreator, 'Dev server is uninitialized');\n return this.urlCreator;\n }\n\n public getNativeRuntimeUrl(opts: Partial<CreateURLOptions> = {}) {\n return this.isDevClient\n ? (this.getUrlCreator().constructDevClientUrl(opts) ?? this.getDevServerUrl())\n : this.getUrlCreator().constructUrl({ ...opts, scheme: 'exp' });\n }\n\n /** Get the URL for the running instance of the dev server. */\n public getDevServerUrl(options: { hostType?: 'localhost' } = {}): string | null {\n const instance = this.getInstance();\n if (!instance?.location) {\n return null;\n }\n\n // If we have an active WS tunnel instance, we always need to return the tunnel location.\n if (this.tunnel && this.tunnel instanceof AsyncWsTunnel) {\n return this.getUrlCreator().constructUrl();\n }\n\n const { location } = instance;\n if (options.hostType === 'localhost') {\n return `${location.protocol}://localhost:${location.port}`;\n }\n\n return location.url ?? null;\n }\n\n public getDevServerUrlOrAssert(options: { hostType?: 'localhost' } = {}): string {\n const instance = this.getDevServerUrl(options);\n if (!instance) {\n throw new CommandError(\n 'DEV_SERVER',\n `Cannot get the dev server URL before the server has started - bundler[${this.name}]`\n );\n }\n\n return instance;\n }\n\n /** Get the base URL for JS inspector */\n public getJsInspectorBaseUrl(): string {\n if (this.name !== 'metro') {\n throw new CommandError(\n 'DEV_SERVER',\n `Cannot get the JS inspector base url - bundler[${this.name}]`\n );\n }\n return this.getUrlCreator().constructUrl({ scheme: 'http' });\n }\n\n /** Get the tunnel URL from the tunnel. */\n public getTunnelUrl(): string | null {\n return this.tunnel?.getActiveUrl() ?? null;\n }\n\n /** Open the dev server in a runtime. */\n public async openPlatformAsync(\n launchTarget: keyof PlatformManagers | 'desktop',\n resolver: BaseResolveDeviceProps<any> = {}\n ) {\n if (launchTarget === 'desktop') {\n const serverUrl = this.getDevServerUrl({ hostType: 'localhost' });\n // Allow opening the tunnel URL when using Metro web.\n const url = this.name === 'metro' ? (this.getTunnelUrl() ?? serverUrl) : serverUrl;\n // Only launch the browser automatically if the process is interactive, otherwise we'll assume it's an agent.\n if (isInteractive()) {\n await openBrowserAsync(url!);\n }\n return { url };\n }\n\n const runtime = this.isTargetingNative() ? (this.isDevClient ? 'custom' : 'expo') : 'web';\n const manager = await this.getPlatformManagerAsync(launchTarget);\n return manager.openAsync({ runtime }, resolver);\n }\n\n /** Open the dev server in a runtime. */\n public async openCustomRuntimeAsync<Platform extends keyof PlatformManagers>(\n launchTarget: Platform,\n launchProps: Partial<PlatformLaunchProps<Platform>> = {},\n resolver: BaseResolveDeviceProps<PlatformDevice<Platform>> = {}\n ) {\n const runtime = this.isTargetingNative() ? (this.isDevClient ? 'custom' : 'expo') : 'web';\n if (runtime !== 'custom') {\n throw new CommandError(\n `dev server cannot open custom runtimes either because it does not target native platforms or because it is not targeting dev clients. (target: ${runtime})`\n );\n }\n\n const manager = await this.getPlatformManagerAsync(launchTarget);\n return manager.openAsync(\n { runtime: 'custom', props: launchProps },\n resolver as BaseResolveDeviceProps<any>\n );\n }\n\n /** Get the URL for opening in Expo Go. */\n protected getExpoGoUrl(): string {\n return this.getUrlCreator().constructUrl({ scheme: 'exp' });\n }\n\n /** Should use the interstitial page for selecting which runtime to use. */\n protected isRedirectPageEnabled(): boolean {\n return (\n !env.EXPO_NO_REDIRECT_PAGE &&\n // if user passed --dev-client flag, skip interstitial page\n !this.isDevClient &&\n // Checks if dev client is installed.\n !!resolveFrom.silent(this.projectRoot, 'expo-dev-client')\n );\n }\n\n /** Get the redirect URL when redirecting is enabled. */\n public getRedirectUrl(platform: keyof PlatformManagers | null = null): string | null {\n if (!this.isRedirectPageEnabled()) {\n debug('Redirect page is disabled');\n return null;\n }\n\n return (\n this.getUrlCreator().constructLoadingUrl(\n {},\n platform === 'emulator' ? 'android' : platform === 'simulator' ? 'ios' : null\n ) ?? null\n );\n }\n\n protected async getPlatformManagerAsync<Platform extends keyof PlatformManagers>(\n ofPlatform: Platform\n ): Promise<PlatformManagers[Platform]> {\n const platform: keyof PlatformManagers = ofPlatform;\n if (!this.platformManagers[platform]) {\n const port = this.getInstance()?.location.port;\n if (!port || !this.urlCreator) {\n throw new CommandError(\n 'DEV_SERVER',\n 'Cannot interact with native platforms until dev server has started'\n );\n }\n debug(`Creating platform manager (platform: ${platform}, port: ${port})`);\n const managerParams = {\n getCustomRuntimeUrl: this.urlCreator.constructDevClientUrl.bind(this.urlCreator),\n getExpoGoUrl: this.getExpoGoUrl.bind(this),\n getRedirectUrl: this.getRedirectUrl.bind(this, platform),\n getDevServerUrl: this.getDevServerUrl.bind(this, { hostType: 'localhost' }),\n };\n switch (platform) {\n case 'simulator': {\n const Manager = PLATFORM_MANAGERS[platform]();\n this.platformManagers[platform] = new Manager(this.projectRoot, port, managerParams);\n break;\n }\n case 'emulator': {\n const Manager = PLATFORM_MANAGERS[platform]();\n this.platformManagers[platform] = new Manager(this.projectRoot, port, managerParams);\n break;\n }\n }\n }\n return this.platformManagers[platform] as PlatformManagers[Platform];\n }\n}\n"],"names":["BundlerDevServer","debug","require","PLATFORM_MANAGERS","simulator","ApplePlatformManager","emulator","AndroidPlatformManager","projectRoot","platformBundlers","options","tunnel","devSession","bonjour","instance","platformManagers","urlCreator","notifier","devToolsPluginManager","DevToolsPluginManager","isDevClient","setInstance","getManifestMiddlewareAsync","Middleware","ExpoGoManifestHandlerMiddleware","getUrlCreator","middleware","constructUrl","bind","mode","minify","isNativeWebpack","name","isTargetingNative","privateKeyPath","startAsync","stopAsync","headless","startHeadlessAsync","startImplementationAsync","postStartAsync","waitForTypeScriptAsync","watchEnvironmentVariables","port","CommandError","initUrlCreator","server","close","callback","addListener","location","host","url","protocol","messageSocket","broadcast","hostType","env","EXPO_OFFLINE","_startTunnelAsync","envIsWebcontainer","isExporting","Promise","all","startDevSessionAsync","startBonjourAsync","watchConfig","stopObserving","FileNotifier","getConfigModuleIds","startObserving","getInstance","_createTunnel","useV2Tunnel","EXPO_UNSTABLE_TUNNEL_V2","useExpoAccount","AsyncWsTunnel","AsyncNgrok","DevelopmentSession","getNativeRuntimeUrl","getDevServerUrl","runtime","Bonjour","announceAsync","isTargetingWeb","web","broadcastMessage","method","params","undefined","closeAsync","catch","e","Log","error","exception","resolveWithTimeout","resolve","reject","code","timeout","errorMessage","assert","UrlCreator","init","getTunnelUrl","opts","constructDevClientUrl","scheme","getDevServerUrlOrAssert","getJsInspectorBaseUrl","getActiveUrl","openPlatformAsync","launchTarget","resolver","serverUrl","isInteractive","openBrowserAsync","manager","getPlatformManagerAsync","openAsync","openCustomRuntimeAsync","launchProps","props","getExpoGoUrl","isRedirectPageEnabled","EXPO_NO_REDIRECT_PAGE","resolveFrom","silent","getRedirectUrl","platform","constructLoadingUrl","ofPlatform","managerParams","getCustomRuntimeUrl","Manager"],"mappings":"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"}
|
|
@@ -271,7 +271,8 @@ class MetroTerminalReporter extends _TerminalReporter.TerminalReporter {
|
|
|
271
271
|
let hasStack = false;
|
|
272
272
|
const parsed = data.map((msg)=>{
|
|
273
273
|
// Quick check to see if an unsymbolicated stack is being logged.
|
|
274
|
-
if (typeof msg === 'string' &&
|
|
274
|
+
if (typeof msg === 'string' && // Native stack frames use `.bundle//&platform=...`; web stack frames use `.bundle?platform=...`.
|
|
275
|
+
(msg.includes('.bundle//&platform=') || msg.includes('.bundle?platform='))) {
|
|
275
276
|
const stack = (0, _serverLogLikeMetro.parseErrorStringToObject)(msg);
|
|
276
277
|
if (stack) {
|
|
277
278
|
hasStack = true;
|