@absolutejs/absolute 0.20.0-beta.42 → 0.20.0-beta.43

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.
@@ -3788,11 +3788,12 @@ import {
3788
3788
 
3789
3789
  // src/mobile/remoteMacWire.ts
3790
3790
  var ABSOLUTE_REMOTE_MAC_EVENT_PREFIX = "ABSOLUTE_REMOTE_MAC\t";
3791
- var ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION = 1;
3791
+ var ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION = 2;
3792
3792
 
3793
3793
  // src/mobile/remoteMacProtocol.ts
3794
3794
  var PROFILE_FORMAT = 1;
3795
3795
  var REMOTE_STDIN_FLUSH_ATTEMPTS = 3;
3796
+ var REMOTE_SESSION_CLOSE_TIMEOUT_MS = 2000;
3796
3797
  var PROFILE_NAME = /^[a-z0-9](?:[a-z0-9._-]{0,62}[a-z0-9])?$/u;
3797
3798
  var SSH_DESTINATION = /^(?:[A-Za-z0-9._-]+@)?[A-Za-z0-9._:-]+$/u;
3798
3799
  var defaultProfilePath = () => join7(homedir2(), ".absolutejs", "mobile", "remote-macs.json");
@@ -3994,6 +3995,11 @@ var removeAbsoluteRemoteMacProfile = async (name, profilePath) => {
3994
3995
  return true;
3995
3996
  };
3996
3997
  var projectIdentity = (projectRoot, appId) => createHash7("sha256").update(`${resolvePath2(projectRoot)}\x00${appId}`).digest("hex").slice(0, 20);
3998
+ var createAbsoluteRemoteExpoIosDevProject = (config, projectRoot, profile) => {
3999
+ if (config.engine !== "expo")
4000
+ throw new TypeError("Remote Expo execution requires mobile.engine: expo.");
4001
+ return createAbsoluteRemoteIosDevProject(config, projectRoot, profile);
4002
+ };
3997
4003
  var createAbsoluteRemoteIosDevProject = (config, projectRoot, profile) => ({
3998
4004
  cap: join7(resolvePath2(projectRoot), "node_modules", ".bin", "cap"),
3999
4005
  config,
@@ -4085,6 +4091,7 @@ var portableMobileConfig = (project) => ({
4085
4091
  appId: project.config.appId,
4086
4092
  appName: project.config.appName,
4087
4093
  bundleDirectory: portableRelativePath(project.projectRoot, project.config.bundleDirectory),
4094
+ engine: project.config.engine,
4088
4095
  ...project.config.deepLinkScheme || project.config.deepLinkHosts.length > 1 || project.config.appleAppIdPrefix ? {
4089
4096
  deepLinks: {
4090
4097
  ...project.config.deepLinkScheme ? { scheme: project.config.deepLinkScheme } : {},
@@ -4097,6 +4104,16 @@ var portableMobileConfig = (project) => ({
4097
4104
  }
4098
4105
  } : {},
4099
4106
  entry: project.config.entry,
4107
+ ...project.config.engine === "expo" ? {
4108
+ expo: { sdkVersion: project.config.expoSdkVersion ?? 57 },
4109
+ routes: {
4110
+ default: "web",
4111
+ native: Object.fromEntries(Object.entries(project.config.expoNativeRoutes).map(([route, module]) => [
4112
+ route,
4113
+ portableRelativePath(project.projectRoot, module)
4114
+ ]))
4115
+ }
4116
+ } : {},
4100
4117
  ...project.config.iosVersion ? { ios: { version: project.config.iosVersion } } : {},
4101
4118
  nativeProject: {
4102
4119
  directory: portableRelativePath(project.projectRoot, project.config.nativeProjectDirectory),
@@ -4188,7 +4205,32 @@ var consumeLines2 = async (stream, onLine) => {
4188
4205
  reader.releaseLock();
4189
4206
  }
4190
4207
  };
4191
- var startAbsoluteRemoteIosDevSession = async (options) => {
4208
+ var startAbsoluteRemoteExpoIosDevSession = async (options) => {
4209
+ const session = await startAbsoluteRemoteDevSession({
4210
+ certificateAuthorityPath: options.certificateAuthorityPath,
4211
+ deviceIdentifier: options.deviceIdentifier,
4212
+ https: options.https,
4213
+ installAgent: options.installAgent,
4214
+ log: options.log,
4215
+ metroPort: options.metroPort,
4216
+ onExpoPhaseTiming: options.onPhaseTiming,
4217
+ onExpoStateChange: options.onStateChange,
4218
+ port: options.port,
4219
+ project: options.project,
4220
+ serverHost: options.serverHost,
4221
+ signal: options.signal,
4222
+ syncProject: options.syncProject,
4223
+ transport: options.transport
4224
+ });
4225
+ return {
4226
+ close: session.close,
4227
+ metroPort: options.metroPort,
4228
+ platforms: ["ios"],
4229
+ timings: session.timings
4230
+ };
4231
+ };
4232
+ var startAbsoluteRemoteIosDevSession = (options) => startAbsoluteRemoteDevSession(options);
4233
+ var startAbsoluteRemoteDevSession = async (options) => {
4192
4234
  const startedAt = performance.now();
4193
4235
  const transport = options.transport ?? defaultTransport;
4194
4236
  const installAgent = options.installAgent ?? installAbsoluteRemoteMacAgent;
@@ -4202,9 +4244,22 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
4202
4244
  const encodedConfig = Buffer.from(JSON.stringify(portableMobileConfig(options.project))).toString("base64url");
4203
4245
  const encodedCertificateAuthority = options.certificateAuthorityPath ? (await readFile9(options.certificateAuthorityPath)).toString("base64url") : undefined;
4204
4246
  const physicalDevice = options.deviceIdentifier !== undefined;
4205
- let relayPort;
4206
- if (physicalDevice)
4207
- relayPort = options.port <= 49151 ? options.port + 16384 : options.port - 16384;
4247
+ const expo = options.project.config.engine === "expo";
4248
+ if (expo && options.metroPort === undefined)
4249
+ throw new TypeError("Remote Expo execution requires a Metro port.");
4250
+ if (options.metroPort === options.port)
4251
+ throw new TypeError("Expo Metro and AbsoluteJS must use different ports.");
4252
+ const translatedRelayPort = (sourcePort) => sourcePort <= 49151 ? sourcePort + 16384 : sourcePort - 16384;
4253
+ const occupiedRemotePorts = new Set([options.port, options.metroPort].filter((value) => value !== undefined));
4254
+ const reserveRelayPort = (sourcePort) => {
4255
+ let candidate = translatedRelayPort(sourcePort);
4256
+ while (occupiedRemotePorts.has(candidate))
4257
+ candidate = candidate === 65535 ? 1024 : candidate + 1;
4258
+ occupiedRemotePorts.add(candidate);
4259
+ return candidate;
4260
+ };
4261
+ const relayPort = physicalDevice ? reserveRelayPort(options.port) : undefined;
4262
+ const metroRelayPort = physicalDevice && options.metroPort !== undefined ? reserveRelayPort(options.metroPort) : undefined;
4208
4263
  if (physicalDevice && !options.serverHost)
4209
4264
  throw new Error("Remote physical iOS development requires the Remote Mac LAN host.");
4210
4265
  const remoteCommand = [
@@ -4217,6 +4272,7 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
4217
4272
  String(options.port),
4218
4273
  "--mobile-config",
4219
4274
  shellQuote(encodedConfig),
4275
+ ...expo && options.metroPort !== undefined ? ["--metro-port", String(options.metroPort)] : [],
4220
4276
  ...encodedCertificateAuthority ? [
4221
4277
  "--certificate-authority",
4222
4278
  shellQuote(encodedCertificateAuthority)
@@ -4228,7 +4284,8 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
4228
4284
  "--server-host",
4229
4285
  shellQuote(options.serverHost ?? ""),
4230
4286
  "--relay-port",
4231
- String(relayPort)
4287
+ String(relayPort),
4288
+ ...expo && metroRelayPort !== undefined ? ["--metro-relay-port", String(metroRelayPort)] : []
4232
4289
  ] : []
4233
4290
  ].join(" ");
4234
4291
  const command = [
@@ -4237,6 +4294,10 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
4237
4294
  "ExitOnForwardFailure=yes",
4238
4295
  "-R",
4239
4296
  physicalDevice ? `127.0.0.1:${relayPort}:127.0.0.1:${options.port}` : `${options.port}:127.0.0.1:${options.port}`,
4297
+ ...expo && options.metroPort !== undefined ? [
4298
+ "-R",
4299
+ physicalDevice ? `127.0.0.1:${metroRelayPort}:127.0.0.1:${options.metroPort}` : `${options.metroPort}:127.0.0.1:${options.metroPort}`
4300
+ ] : [],
4240
4301
  "/bin/sh -lc",
4241
4302
  shellQuote(remoteCommand)
4242
4303
  ];
@@ -4262,11 +4323,19 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
4262
4323
  if (event.type === "native-log")
4263
4324
  options.nativeLog?.(event.entry);
4264
4325
  if (event.type === "state") {
4265
- ({ state } = event);
4266
- options.onStateChange?.(state);
4326
+ if (expo)
4327
+ options.onExpoStateChange?.(event.state);
4328
+ else {
4329
+ state = event.state;
4330
+ options.onStateChange?.(state);
4331
+ }
4332
+ }
4333
+ if (event.type === "timing") {
4334
+ if (expo)
4335
+ options.onExpoPhaseTiming?.(event);
4336
+ else
4337
+ options.onPhaseTiming?.(event);
4267
4338
  }
4268
- if (event.type === "timing")
4269
- options.onPhaseTiming?.(event);
4270
4339
  if (event.type === "ready") {
4271
4340
  ready = event;
4272
4341
  resolveReady();
@@ -4308,9 +4377,26 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
4308
4377
  pending.clear();
4309
4378
  return;
4310
4379
  });
4311
- await readyPromise;
4380
+ try {
4381
+ await readyPromise;
4382
+ } catch (error) {
4383
+ process2.stdin.end();
4384
+ process2.kill();
4385
+ await process2.exited.catch(() => {
4386
+ return;
4387
+ });
4388
+ throw error;
4389
+ }
4312
4390
  if (!ready)
4313
4391
  throw fatal ?? new Error("Remote Mac did not become ready.");
4392
+ if (ready.engine !== options.project.config.engine) {
4393
+ process2.stdin.end();
4394
+ process2.kill();
4395
+ await process2.exited.catch(() => {
4396
+ return;
4397
+ });
4398
+ throw new Error("Remote Mac executor returned the wrong mobile engine.");
4399
+ }
4314
4400
  const totalDuration = performance.now() - startedAt;
4315
4401
  let currentReady = {
4316
4402
  ...ready,
@@ -4322,11 +4408,11 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
4322
4408
  total: totalDuration
4323
4409
  }
4324
4410
  };
4325
- options.log?.(`Remote Mac connected (${options.project.profile.name}); agent ${agent.uploaded ? "uploaded" : "cache hit"}, project synced, and iOS ready in ${totalDuration.toFixed(2)}ms.`);
4411
+ options.log?.(`Remote Mac connected (${options.project.profile.name}); agent ${agent.uploaded ? "uploaded" : "cache hit"}, project synced, and ${expo ? "Expo " : ""}iOS ready in ${totalDuration.toFixed(2)}ms.`);
4326
4412
  const request = (commandName) => {
4327
4413
  const id = randomUUID4();
4328
4414
  const response = new Promise((resolve6, reject) => pending.set(id, { reject, resolve: resolve6 }));
4329
- process2.stdin.write(`${JSON.stringify({ command: commandName, id, v: 1 })}
4415
+ process2.stdin.write(`${JSON.stringify({ command: commandName, id, v: ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION })}
4330
4416
  `);
4331
4417
  const flush = async () => {
4332
4418
  for (let attempt = 0;attempt < REMOTE_STDIN_FLUSH_ATTEMPTS; attempt++) {
@@ -4345,13 +4431,24 @@ var startAbsoluteRemoteIosDevSession = async (options) => {
4345
4431
  if (closed)
4346
4432
  return;
4347
4433
  closed = true;
4348
- await request("close").catch(() => {
4349
- return;
4350
- });
4434
+ const timeout = () => new Promise((resolve6) => setTimeout(() => resolve6("timeout"), REMOTE_SESSION_CLOSE_TIMEOUT_MS));
4435
+ await Promise.race([
4436
+ request("close").catch(() => {
4437
+ return;
4438
+ }),
4439
+ timeout()
4440
+ ]);
4351
4441
  process2.stdin.end();
4352
- await process2.exited.catch(() => {
4353
- return;
4354
- });
4442
+ const exit = await Promise.race([
4443
+ process2.exited.then(() => "exited").catch(() => "exited"),
4444
+ timeout()
4445
+ ]);
4446
+ if (exit === "timeout") {
4447
+ process2.kill();
4448
+ await process2.exited.catch(() => {
4449
+ return;
4450
+ });
4451
+ }
4355
4452
  };
4356
4453
  const makeSession = () => ({
4357
4454
  close,
@@ -7020,7 +7117,8 @@ var commandEnvironment = (options) => ({
7020
7117
  ABSOLUTE_EXPO_DEVELOPMENT_CA_PATH: options.certificateAuthorityPath
7021
7118
  } : {},
7022
7119
  ...options.androidOrigin ? { EXPO_PUBLIC_ABSOLUTE_DEV_ANDROID_ORIGIN: options.androidOrigin } : {},
7023
- ...options.iosOrigin ? { EXPO_PUBLIC_ABSOLUTE_DEV_IOS_ORIGIN: options.iosOrigin } : {}
7120
+ ...options.iosOrigin ? { EXPO_PUBLIC_ABSOLUTE_DEV_IOS_ORIGIN: options.iosOrigin } : {},
7121
+ ...options.metroHost ? { REACT_NATIVE_PACKAGER_HOSTNAME: options.metroHost } : {}
7024
7122
  });
7025
7123
  var absoluteExpoExecutable = async (project) => {
7026
7124
  const executable = join16(project, "node_modules", ".bin", "expo");
@@ -7034,8 +7132,8 @@ var absoluteExpoExecutable = async (project) => {
7034
7132
  var planAbsoluteExpoDevSession = (config, options) => {
7035
7133
  if (config.engine !== "expo")
7036
7134
  throw new TypeError("The Expo development controller requires Expo.");
7037
- if (options.platforms.length === 0)
7038
- throw new TypeError("Expo development requires a local target platform.");
7135
+ if (options.platforms.length === 0 && options.metro === "external")
7136
+ throw new TypeError("External Expo execution requires a target platform.");
7039
7137
  const secureOrigin = [options.androidOrigin, options.iosOrigin].some((origin) => origin && new URL(origin).protocol === "https:");
7040
7138
  if (secureOrigin && !options.certificateAuthorityPath)
7041
7139
  throw new TypeError("Expo HTTPS development requires the AbsoluteJS development CA certificate.");
@@ -7052,7 +7150,7 @@ var planAbsoluteExpoDevSession = (config, options) => {
7052
7150
  env,
7053
7151
  role: "metro"
7054
7152
  };
7055
- const prepare = {
7153
+ const prepare = options.platforms.length === 0 ? undefined : {
7056
7154
  args: [
7057
7155
  "prebuild",
7058
7156
  "--clean",
@@ -7080,7 +7178,11 @@ var planAbsoluteExpoDevSession = (config, options) => {
7080
7178
  return command;
7081
7179
  });
7082
7180
  return {
7083
- commands: [prepare, metro, ...native],
7181
+ commands: [
7182
+ ...prepare ? [prepare] : [],
7183
+ ...options.metro === "external" ? [] : [metro],
7184
+ ...native
7185
+ ],
7084
7186
  metroPort: options.metroPort,
7085
7187
  project: config.nativeProjectDirectory
7086
7188
  };
@@ -7169,47 +7271,48 @@ var startAbsoluteExpoDevSession = async (options) => {
7169
7271
  const prepareCommand = plan.commands.find((command) => command.role === "native-prepare");
7170
7272
  const metroCommand = plan.commands.find((command) => command.role === "metro");
7171
7273
  const nativeCommands = plan.commands.filter((command) => command.role === "native-build");
7172
- if (!prepareCommand)
7173
- throw new TypeError("Expo native preparation command is missing.");
7174
- if (!metroCommand)
7175
- throw new TypeError("Expo Metro command is missing.");
7176
- setState("preparing-native");
7177
- const prepareStarted = performance.now();
7178
- const prepareProcess = run(executable, prepareCommand.args, {
7179
- cwd: plan.project,
7180
- env: { ...process.env, ...prepareCommand.env },
7181
- stdio: ["ignore", "pipe", "pipe"]
7182
- });
7183
- forwardLines(prepareProcess, (line) => {
7184
- if (line)
7185
- log(`[prebuild] ${line}`);
7186
- });
7187
- const abortPrepare = () => void stopProcess(prepareProcess);
7188
- options.signal?.addEventListener("abort", abortPrepare, { once: true });
7189
- const prepareExit = await waitForExit(prepareProcess);
7190
- options.signal?.removeEventListener("abort", abortPrepare);
7191
- if (options.signal?.aborted)
7192
- throw abortError();
7193
- if (prepareExit !== 0) {
7194
- setState("failed");
7195
- throw new Error(`Expo native preparation exited with status ${prepareExit}.`);
7196
- }
7197
- const prepareMs = performance.now() - prepareStarted;
7198
- timings["preparing-native"] = prepareMs;
7199
- options.onPhaseTiming?.({
7200
- durationMs: prepareMs,
7201
- phase: "preparing-native"
7202
- });
7203
- setState("starting-metro");
7274
+ const runPrepareCommand = async (command) => {
7275
+ setState("preparing-native");
7276
+ const prepareStarted = performance.now();
7277
+ const prepareProcess = run(executable, command.args, {
7278
+ cwd: plan.project,
7279
+ env: { ...process.env, ...command.env },
7280
+ stdio: ["ignore", "pipe", "pipe"]
7281
+ });
7282
+ forwardLines(prepareProcess, (line) => {
7283
+ if (line)
7284
+ log(`[prebuild] ${line}`);
7285
+ });
7286
+ const abortPrepare = () => void stopProcess(prepareProcess);
7287
+ options.signal?.addEventListener("abort", abortPrepare, { once: true });
7288
+ const prepareExit = await waitForExit(prepareProcess);
7289
+ options.signal?.removeEventListener("abort", abortPrepare);
7290
+ if (options.signal?.aborted)
7291
+ throw abortError();
7292
+ if (prepareExit !== 0) {
7293
+ setState("failed");
7294
+ throw new Error(`Expo native preparation exited with status ${prepareExit}.`);
7295
+ }
7296
+ publishTiming("preparing-native", performance.now() - prepareStarted);
7297
+ };
7298
+ if (prepareCommand)
7299
+ await runPrepareCommand(prepareCommand);
7300
+ const managedMetro = metroCommand !== undefined;
7301
+ if (managedMetro)
7302
+ setState("starting-metro");
7204
7303
  const metroStarted = performance.now();
7205
- const metro = run(executable, metroCommand.args, {
7304
+ const metro = metroCommand ? run(executable, metroCommand.args, {
7206
7305
  cwd: plan.project,
7207
7306
  env: { ...process.env, ...metroCommand.env },
7208
7307
  stdio: ["ignore", "pipe", "pipe"]
7209
- });
7308
+ }) : undefined;
7210
7309
  let metroReady = false;
7211
7310
  let resolveMetro;
7212
7311
  const metroPromise = new Promise((resolve14, reject) => {
7312
+ if (!metro) {
7313
+ resolve14();
7314
+ return;
7315
+ }
7213
7316
  const timeout = setTimeout(() => {
7214
7317
  reject(new Error("Expo Metro did not become ready within 60 seconds."));
7215
7318
  }, METRO_READY_TIMEOUT_MS);
@@ -7224,15 +7327,19 @@ var startAbsoluteExpoDevSession = async (options) => {
7224
7327
  }
7225
7328
  });
7226
7329
  });
7227
- forwardLines(metro, (line) => {
7228
- if (line)
7229
- log(`[metro] ${line}`);
7230
- if (!metroReady && /(?:Waiting on|Metro waiting on|Dev server ready)/iu.test(line)) {
7231
- metroReady = true;
7232
- resolveMetro?.();
7233
- }
7234
- });
7235
- const abort = () => void stopProcess(metro);
7330
+ if (metro)
7331
+ forwardLines(metro, (line) => {
7332
+ if (line)
7333
+ log(`[metro] ${line}`);
7334
+ if (!metroReady && /(?:Waiting on|Metro waiting on|Dev server ready)/iu.test(line)) {
7335
+ metroReady = true;
7336
+ resolveMetro?.();
7337
+ }
7338
+ });
7339
+ const abort = () => {
7340
+ if (metro)
7341
+ stopProcess(metro);
7342
+ };
7236
7343
  options.signal?.addEventListener("abort", abort, { once: true });
7237
7344
  const runNativeCommand = async (command) => {
7238
7345
  if (options.signal?.aborted)
@@ -7313,12 +7420,8 @@ var startAbsoluteExpoDevSession = async (options) => {
7313
7420
  try {
7314
7421
  await startPhysicalIosEnrollment();
7315
7422
  await metroPromise;
7316
- const metroMs = performance.now() - metroStarted;
7317
- timings["starting-metro"] = metroMs;
7318
- options.onPhaseTiming?.({
7319
- durationMs: metroMs,
7320
- phase: "starting-metro"
7321
- });
7423
+ if (managedMetro)
7424
+ publishTiming("starting-metro", performance.now() - metroStarted);
7322
7425
  await runNativeCommands(nativeCommands);
7323
7426
  setState("ready");
7324
7427
  return {
@@ -7327,14 +7430,16 @@ var startAbsoluteExpoDevSession = async (options) => {
7327
7430
  timings,
7328
7431
  close: async () => {
7329
7432
  options.signal?.removeEventListener("abort", abort);
7330
- await stopProcess(metro);
7433
+ if (metro)
7434
+ await stopProcess(metro);
7331
7435
  await closeEnrollmentServer();
7332
7436
  setState("closed");
7333
7437
  }
7334
7438
  };
7335
7439
  } catch (error) {
7336
7440
  options.signal?.removeEventListener("abort", abort);
7337
- await stopProcess(metro);
7441
+ if (metro)
7442
+ await stopProcess(metro);
7338
7443
  await closeEnrollmentServer();
7339
7444
  setState("failed");
7340
7445
  throw error;
@@ -9407,6 +9512,7 @@ export {
9407
9512
  syncAbsoluteRemoteMacProject,
9408
9513
  syncAbsoluteExpoWebAssets,
9409
9514
  startAbsoluteRemoteIosDevSession,
9515
+ startAbsoluteRemoteExpoIosDevSession,
9410
9516
  startAbsoluteIosTcpRelay,
9411
9517
  startAbsoluteIosDevSession,
9412
9518
  startAbsoluteIosCaEnrollmentServer,
@@ -9483,6 +9589,7 @@ export {
9483
9589
  discoverAbsoluteDeviceCapabilities,
9484
9590
  directAbsoluteProjectPackages,
9485
9591
  createAbsoluteRemoteIosDevProject,
9592
+ createAbsoluteRemoteExpoIosDevProject,
9486
9593
  createAbsoluteMobileUpgradeResponse,
9487
9594
  createAbsoluteMobileRouteMetadataPlugin,
9488
9595
  createAbsoluteMobilePreviewPlugin,
@@ -9545,5 +9652,5 @@ export {
9545
9652
  ABSOLUTE_ANDROID_RELEASE_FORMAT
9546
9653
  };
9547
9654
 
9548
- //# debugId=711828E2D236C77164756E2164756E21
9655
+ //# debugId=97C358B153ACDA7B64756E2164756E21
9549
9656
  //# sourceMappingURL=index.js.map