adb-ready 0.4.0 → 0.4.1

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/CHANGELOG.md CHANGED
@@ -9,6 +9,15 @@ breaking changes.
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.4.1] - 2026-09-16
13
+
14
+ ### Fixed
15
+
16
+ - Resolve Expo Go and development-client launch URLs through Expo's supported
17
+ `/_expo/link` redirect without probing an unhandled route that could consume
18
+ the request timeout, and report distinct timeout, connection, response, and
19
+ unsafe-redirect failures.
20
+
12
21
  ## [0.4.0] - 2026-09-15
13
22
 
14
23
  ### Added
package/dist/cli.js CHANGED
@@ -3304,7 +3304,7 @@ import process13 from "node:process";
3304
3304
  // package.json
3305
3305
  var package_default = {
3306
3306
  name: "adb-ready",
3307
- version: "0.4.0",
3307
+ version: "0.4.1",
3308
3308
  description: "Agent-ready Android CLI for reliable ADB sessions, app automation, and verified evidence.",
3309
3309
  private: false,
3310
3310
  type: "module",
@@ -39826,9 +39826,6 @@ var MAX_URL_LENGTH = 8 * 1024;
39826
39826
  function aborted4(signal) {
39827
39827
  return signal?.aborted === true;
39828
39828
  }
39829
- function validApplicationId(value) {
39830
- return typeof value === "string" && /^[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z0-9_]+)+$/u.test(value);
39831
- }
39832
39829
  function parseLaunchUrl(value) {
39833
39830
  if (typeof value !== "string" || value.length === 0 || value.length > MAX_URL_LENGTH) {
39834
39831
  return;
@@ -39910,34 +39907,7 @@ async function requestExpo(url4, signal) {
39910
39907
  ...location === undefined ? {} : { location }
39911
39908
  };
39912
39909
  }
39913
- function parseOpenResponse(response, requestedRuntime, devicePort) {
39914
- if (response.status !== 200)
39915
- return;
39916
- let document2;
39917
- try {
39918
- document2 = JSON.parse(response.body);
39919
- } catch {
39920
- return;
39921
- }
39922
- if (typeof document2 !== "object" || document2 === null || Array.isArray(document2)) {
39923
- return;
39924
- }
39925
- const record4 = document2;
39926
- const runtime = record4.runtime;
39927
- if (runtime !== requestedRuntime)
39928
- return;
39929
- const parsedUrl = parseLaunchUrl(record4.url);
39930
- if (parsedUrl === undefined)
39931
- return;
39932
- const applicationId = record4.appId;
39933
- return {
39934
- url: routeThroughReverse(parsedUrl, devicePort).toString(),
39935
- runtime: requestedRuntime,
39936
- source: "open",
39937
- ...validApplicationId(applicationId) ? { applicationId } : {}
39938
- };
39939
- }
39940
- function parseLegacyResponse(response, runtime, devicePort) {
39910
+ function parseLinkResponse(response, runtime, devicePort) {
39941
39911
  if (response.status !== 307)
39942
39912
  return;
39943
39913
  const parsedUrl = parseLaunchUrl(response.location);
@@ -39964,35 +39934,27 @@ async function resolveExpoLaunch(options) {
39964
39934
  options.signal?.addEventListener("abort", abort, { once: true });
39965
39935
  const timer = setTimeout(() => controller.abort(new Error("Expo launch request timed out")), timeoutMs);
39966
39936
  try {
39967
- const openUrl = new URL("/_expo/open", endpoint);
39968
- openUrl.searchParams.set("platform", "android");
39969
- openUrl.searchParams.set("runtime", options.runtime);
39970
- try {
39971
- const response = await request(openUrl.toString(), controller.signal);
39972
- const target = parseOpenResponse(response, options.runtime, options.devicePort);
39973
- if (target !== undefined)
39974
- return { status: "resolved", target };
39975
- } catch {
39976
- if (aborted4(options.signal))
39977
- return { status: "aborted" };
39978
- }
39979
- const legacyUrl = new URL("/_expo/link", endpoint);
39980
- legacyUrl.searchParams.set("platform", "android");
39937
+ const linkUrl = new URL("/_expo/link", endpoint);
39938
+ linkUrl.searchParams.set("platform", "android");
39981
39939
  if (options.runtime === "custom")
39982
- legacyUrl.searchParams.set("choice", "expo-dev-client");
39940
+ linkUrl.searchParams.set("choice", "expo-dev-client");
39983
39941
  try {
39984
- const response = await request(legacyUrl.toString(), controller.signal);
39985
- const target = parseLegacyResponse(response, options.runtime, options.devicePort);
39942
+ const response = await request(linkUrl.toString(), controller.signal);
39943
+ const target = parseLinkResponse(response, options.runtime, options.devicePort);
39986
39944
  if (target !== undefined)
39987
39945
  return { status: "resolved", target };
39946
+ return {
39947
+ status: "unavailable",
39948
+ detail: response.status !== 307 ? `Expo /_expo/link returned HTTP ${String(response.status)} instead of a redirect.` : response.location === undefined ? "Expo /_expo/link returned a redirect without a Location header." : "Expo /_expo/link returned an invalid or unsafe Android launch URL."
39949
+ };
39988
39950
  } catch {
39989
39951
  if (aborted4(options.signal))
39990
39952
  return { status: "aborted" };
39953
+ return {
39954
+ status: "unavailable",
39955
+ detail: controller.signal.aborted ? `Expo /_expo/link did not respond within ${String(timeoutMs)}ms.` : "Expo /_expo/link could not be reached."
39956
+ };
39991
39957
  }
39992
- return {
39993
- status: "unavailable",
39994
- detail: "Metro did not provide a valid Android launch URL through /_expo/open or the compatible /_expo/link endpoint."
39995
- };
39996
39958
  } finally {
39997
39959
  clearTimeout(timer);
39998
39960
  options.signal?.removeEventListener("abort", abort);
@@ -53369,4 +53331,4 @@ try {
53369
53331
  process14.removeListener("SIGTERM", abort);
53370
53332
  }
53371
53333
 
53372
- //# debugId=241ECDA59C347B2F64756E2164756E21
53334
+ //# debugId=BE31AB70DE4A62C764756E2164756E21
@@ -132,8 +132,8 @@ transport, even when `ANDROID_SERIAL` names one device. ADB Ready therefore
132
132
  does not add `--android` to detected Expo commands. After Metro passes
133
133
  readiness, ADB Ready:
134
134
 
135
- 1. asks Expo's public `/_expo/open` endpoint for the Android deep link, with a
136
- bounded `/_expo/link` fallback for Expo 55;
135
+ 1. asks Expo's bounded `/_expo/link` redirect endpoint for the Android deep
136
+ link used by Expo Go or the project development client;
137
137
  2. routes local-network Metro URLs through the verified reverse mapping while
138
138
  preserving public tunnel URLs;
139
139
  3. resolves the installed URL handler on the selected transport; and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adb-ready",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Agent-ready Android CLI for reliable ADB sessions, app automation, and verified evidence.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "title": "ADB Ready agent tool contract",
3
3
  "schemaVersion": 1,
4
- "packageVersion": "0.4.0",
4
+ "packageVersion": "0.4.1",
5
5
  "protocolVersion": "2025-11-25",
6
6
  "transport": "stdio",
7
7
  "tools": [