@absolutejs/absolute 0.20.0-beta.20 → 0.20.0-beta.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -6948,6 +6948,8 @@ var init_deviceCapabilities = __esm(() => {
6948
6948
  ANDROID_PERMISSION_PATTERN = /^android\.permission\.[A-Z][A-Z0-9_]*$/u;
6949
6949
  IOS_USAGE_DESCRIPTIONS = new Set([
6950
6950
  "camera",
6951
+ "location-always",
6952
+ "location-when-in-use",
6951
6953
  "photo-library",
6952
6954
  "photo-library-add"
6953
6955
  ]);
@@ -16498,6 +16500,10 @@ var START_MARKER2 = "<!-- absolutejs:device-capabilities:start -->", END_MARKER2
16498
16500
  return `${appName} uses your camera when you choose to take a photo.`;
16499
16501
  if (purpose === "photo-library")
16500
16502
  return `${appName} accesses your photo library only for photo actions you choose.`;
16503
+ if (purpose === "location-when-in-use")
16504
+ return `${appName} uses your location only while you are using the app and request a location-based action.`;
16505
+ if (purpose === "location-always")
16506
+ return `${appName} does not track location in the background; this description supports the foreground location provider required by the native runtime.`;
16501
16507
  return `${appName} adds to your photo library only for photo actions you choose.`;
16502
16508
  }, configureIos2 = async (config, plan) => {
16503
16509
  const path = join47(config.nativeProjectDirectory, "ios/App/App/Info.plist");
@@ -16538,6 +16544,8 @@ var init_nativeDeviceCapabilities = __esm(() => {
16538
16544
  init_deviceCapabilities();
16539
16545
  IOS_KEYS = {
16540
16546
  camera: "NSCameraUsageDescription",
16547
+ "location-always": "NSLocationAlwaysAndWhenInUseUsageDescription",
16548
+ "location-when-in-use": "NSLocationWhenInUseUsageDescription",
16541
16549
  "photo-library": "NSPhotoLibraryUsageDescription",
16542
16550
  "photo-library-add": "NSPhotoLibraryAddUsageDescription"
16543
16551
  };
@@ -17446,6 +17454,8 @@ var init_releaseDoctor = __esm(() => {
17446
17454
  RELEASE_ASSET_EXTENSIONS = new Set([".html", ".js", ".mjs"]);
17447
17455
  IOS_USAGE_KEYS = {
17448
17456
  camera: "NSCameraUsageDescription",
17457
+ "location-always": "NSLocationAlwaysAndWhenInUseUsageDescription",
17458
+ "location-when-in-use": "NSLocationWhenInUseUsageDescription",
17449
17459
  "photo-library": "NSPhotoLibraryUsageDescription",
17450
17460
  "photo-library-add": "NSPhotoLibraryAddUsageDescription"
17451
17461
  };
@@ -17696,6 +17706,152 @@ var init_iosConformance = __esm(() => {
17696
17706
  HMR_LINE = new RegExp(String.raw`\[hmr:ios\]\s+([^\n]*?)\s+(applied in|falling back to reload after|failed after)\s+(\d+)ms(?:; server\s+(\d+)ms, client\s+(\d+)ms)?`, "u");
17697
17707
  });
17698
17708
 
17709
+ // src/mobile/iosTestReport.ts
17710
+ import { mkdir as mkdir13, readFile as readFile18, writeFile as writeFile15 } from "fs/promises";
17711
+ import { join as join51 } from "path";
17712
+ var MANUAL_CHECKS, secretPattern, bearerPattern, coordinatePattern, sanitizeIosReportText = (value) => value.replace(bearerPattern, "Bearer [REDACTED]").replace(secretPattern, "$1$2[REDACTED]").replace(coordinatePattern, "$1$2[REDACTED]").replace(/(https?:\/\/[^\s?#]+)[?#][^\s]*/giu, "$1?[REDACTED]"), markdownCell = (value) => sanitizeIosReportText(value).replaceAll("|", "\\|").replaceAll(`
17713
+ `, "<br>"), createAbsoluteIosPartnerReport = (options) => {
17714
+ const { run } = options;
17715
+ const evidence = run.screenshot ? `Simulator screenshot: ${run.screenshot}` : undefined;
17716
+ let hmrResult = "NOT_RUN";
17717
+ if (run.hmr)
17718
+ hmrResult = run.hmr.outcome === "failed" ? "FAIL" : "PASS";
17719
+ const automatedChecks = [
17720
+ {
17721
+ details: `Captured macOS, Xcode, Bun, and AbsoluteJS versions for simulator ${run.udid}.`,
17722
+ id: "AUTO-SETUP-01",
17723
+ result: "PASS"
17724
+ },
17725
+ {
17726
+ details: run.status === "pass" ? `The app was installed, launched, and connected to native HMR in ${run.durationMs}ms.` : `The automated simulator run failed after ${run.durationMs}ms: ${run.error ?? "No error detail was available."}`,
17727
+ ...evidence ? { evidence } : {},
17728
+ id: "AUTO-DEV-01",
17729
+ result: run.status === "pass" ? "PASS" : "FAIL"
17730
+ },
17731
+ {
17732
+ details: run.hmr ? `Observed native HMR ${run.hmr.outcome} in ${run.hmr.durationMs}ms${run.hmr.serverMs === undefined ? "" : ` (server ${run.hmr.serverMs}ms, client ${run.hmr.clientMs}ms)`}.` : "Correlated edit timing was not requested. Rerun with --wait-for-hmr.",
17733
+ id: "AUTO-HMR-01",
17734
+ result: hmrResult
17735
+ },
17736
+ {
17737
+ details: run.screenshot ? "A simulator screenshot was captured. Visually review it before sharing this directory." : "No simulator screenshot was captured.",
17738
+ ...evidence ? { evidence } : {},
17739
+ id: "AUTO-ARTIFACT-01",
17740
+ result: run.screenshot ? "PASS" : "FAIL"
17741
+ }
17742
+ ];
17743
+ const manualChecks = MANUAL_CHECKS.map(([id, details]) => ({
17744
+ details,
17745
+ id,
17746
+ result: "NOT_RUN"
17747
+ }));
17748
+ return {
17749
+ automatedChecks,
17750
+ generatedAt: options.generatedAt ?? new Date().toISOString(),
17751
+ manualChecks,
17752
+ metadata: {
17753
+ absolutejsVersion: options.absolutejsVersion,
17754
+ bunVersion: options.bunVersion,
17755
+ macosVersion: options.macosVersion,
17756
+ provider: "capacitor",
17757
+ xcodeVersion: options.xcodeVersion
17758
+ },
17759
+ overallResult: run.status === "fail" ? "FAIL" : "INCOMPLETE",
17760
+ platform: "ios",
17761
+ reportVersion: 1,
17762
+ run
17763
+ };
17764
+ }, readPackageVersionForIosReport = async (packageJsonPath) => {
17765
+ const manifest = JSON.parse(await readFile18(packageJsonPath, "utf8"));
17766
+ if (typeof manifest !== "object" || manifest === null)
17767
+ return "unknown";
17768
+ const version2 = Reflect.get(manifest, "version");
17769
+ return typeof version2 === "string" ? version2 : "unknown";
17770
+ }, renderAbsoluteIosPartnerReport = (report) => {
17771
+ const table = (checks) => checks.map((check2) => `| ${check2.id} | ${check2.result} | ${markdownCell(check2.details)} | ${markdownCell(check2.evidence ?? "")} |`).join(`
17772
+ `);
17773
+ return `# AbsoluteJS iOS test report
17774
+
17775
+ - Overall result: ${report.overallResult}
17776
+ - Generated: ${report.generatedAt}
17777
+ - AbsoluteJS: ${markdownCell(report.metadata.absolutejsVersion)}
17778
+ - macOS: ${markdownCell(report.metadata.macosVersion)}
17779
+ - Xcode: ${markdownCell(report.metadata.xcodeVersion)}
17780
+ - Bun: ${markdownCell(report.metadata.bunVersion)}
17781
+ - App bundle ID: ${markdownCell(report.run.appId)}
17782
+ - Simulator UDID: ${markdownCell(report.run.udid)}
17783
+ - Automated run: ${report.run.status.toUpperCase()} (${report.run.durationMs}ms)
17784
+
17785
+ ` + `This report is local and is never uploaded by AbsoluteJS. Before sharing its directory, visually inspect screenshots and logs. Never add passwords, signing material, tokens, cookies, private Sync data, or exact coordinates.
17786
+
17787
+ ## Automated checks
17788
+
17789
+ | Test ID | Result | Observed result / timing | Evidence |
17790
+ | --- | --- | --- | --- |
17791
+ ${table(report.automatedChecks)}
17792
+
17793
+ ## Partner checklist
17794
+
17795
+ Replace each \`NOT_RUN\` with \`PASS\`, \`FAIL\`, or \`SKIPPED\` after following \`docs/IOS_MACOS_TESTING.md\`. A failure must name sanitized evidence and state actual versus expected behavior.
17796
+
17797
+ | Test ID | Result | Observed result / timing | Evidence or failure details |
17798
+ | --- | --- | --- | --- |
17799
+ ${table(report.manualChecks)}
17800
+ `;
17801
+ }, writeAbsoluteIosPartnerReport = async (directory, report) => {
17802
+ await mkdir13(directory, { recursive: true });
17803
+ const jsonPath = join51(directory, "report.json");
17804
+ const markdownPath = join51(directory, "report.md");
17805
+ await Promise.all([
17806
+ writeFile15(jsonPath, `${JSON.stringify(report, null, 2)}
17807
+ `),
17808
+ writeFile15(markdownPath, renderAbsoluteIosPartnerReport(report))
17809
+ ]);
17810
+ return { directory, jsonPath, markdownPath };
17811
+ };
17812
+ var init_iosTestReport = __esm(() => {
17813
+ MANUAL_CHECKS = [
17814
+ [
17815
+ "SETUP-01",
17816
+ "Confirm and record all Mac, Xcode, Bun, device, and package versions."
17817
+ ],
17818
+ ["SETUP-02", "Confirm Xcode setup and the required iOS runtime."],
17819
+ ["SETUP-03", "Confirm the runbook package versions are installed."],
17820
+ ["SETUP-04", "Confirm the staging bundle ID and production server origin."],
17821
+ ["SETUP-05", "Confirm generated iOS project signing and Xcode warnings."],
17822
+ ["DEV-01", "Record cold and warm bun dev startup timings."],
17823
+ ["DEV-02", "Complete route traversal, HMR, relaunch, and recovery checks."],
17824
+ ["CAP-01", "Complete automatic device-capability provisioning checks."],
17825
+ ...Array.from({ length: 14 }, (_, index) => [
17826
+ `LOC-${String(index + 1).padStart(2, "0")}`,
17827
+ `Complete foreground-location runbook check LOC-${String(index + 1).padStart(2, "0")} without recording exact coordinates.`
17828
+ ]),
17829
+ [
17830
+ "AUTH-01",
17831
+ "Complete system-browser sign-in, callback, restore, and sign-out checks."
17832
+ ],
17833
+ [
17834
+ "SYNC-01",
17835
+ "Complete online, offline, reconnect, isolation, and conflict checks."
17836
+ ],
17837
+ ["BGSYNC-01", "Complete physical-device background Sync acceptance."],
17838
+ ["REMOTE-01", "Complete remote-Mac acceptance, or mark SKIPPED."],
17839
+ ["BUILD-01", "Pass release doctor and produce a signed IPA."],
17840
+ [
17841
+ "SHIP-01",
17842
+ "Upload, process, assign, install, and launch the TestFlight build."
17843
+ ],
17844
+ ["UPDATE-01", "Prove upload retry reuse and a subsequent web-only update."],
17845
+ [
17846
+ "REPORT-01",
17847
+ "Review this directory for sensitive content and complete every row."
17848
+ ]
17849
+ ];
17850
+ secretPattern = /(authorization|access[_ -]?token|refresh[_ -]?token|socket[_ -]?ticket|password|cookie)(\s*[=:]\s*)([^\s,;]+)/giu;
17851
+ bearerPattern = /bearer\s+[^\s,;]+/giu;
17852
+ coordinatePattern = /\b(latitude|longitude|lat|lng)(\s*[=:]\s*)-?\d+(?:\.\d+)?/giu;
17853
+ });
17854
+
17699
17855
  // src/mobile/releasePublisher.ts
17700
17856
  import { access as access10 } from "fs/promises";
17701
17857
  import { isAbsolute as isAbsolute8, relative as relative26, resolve as resolve40, sep as sep7 } from "path";
@@ -17794,11 +17950,11 @@ var exports_mobile = {};
17794
17950
  __export(exports_mobile, {
17795
17951
  runMobile: () => runMobile
17796
17952
  });
17797
- import { access as access11, mkdir as mkdir13, readFile as readFile18, writeFile as writeFile15 } from "fs/promises";
17798
- import { join as join51, resolve as resolve41 } from "path";
17953
+ import { access as access11, mkdir as mkdir14, readFile as readFile19, writeFile as writeFile16 } from "fs/promises";
17954
+ import { join as join52, resolve as resolve41 } from "path";
17799
17955
  import { createInterface } from "readline/promises";
17800
17956
  var NOT_FOUND3 = -1, isRecord15 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), CAPACITOR_PACKAGES, CAPACITOR_PACKAGE_SPECS, CAPACITOR_SYNC_PACKAGE_SPECS, packageNameFromSpec = (spec) => spec.slice(0, spec.lastIndexOf("@")), directProjectPackages = async (projectRoot) => {
17801
- const manifest = JSON.parse(await readFile18(join51(projectRoot, "package.json"), "utf8"));
17957
+ const manifest = JSON.parse(await readFile19(join52(projectRoot, "package.json"), "utf8"));
17802
17958
  if (!isRecord15(manifest))
17803
17959
  throw new TypeError("Application package.json must contain an object.");
17804
17960
  const names = new Set;
@@ -17811,7 +17967,7 @@ var NOT_FOUND3 = -1, isRecord15 = (value) => typeof value === "object" && value
17811
17967
  return names;
17812
17968
  }, resolvedPackageVersion = async (projectRoot, packageName) => {
17813
17969
  try {
17814
- const manifest = JSON.parse(await readFile18(join51(projectRoot, "node_modules", packageName, "package.json"), "utf8"));
17970
+ const manifest = JSON.parse(await readFile19(join52(projectRoot, "node_modules", packageName, "package.json"), "utf8"));
17815
17971
  return isRecord15(manifest) && typeof manifest.version === "string" ? manifest.version : undefined;
17816
17972
  } catch {
17817
17973
  return;
@@ -17852,7 +18008,7 @@ var NOT_FOUND3 = -1, isRecord15 = (value) => typeof value === "object" && value
17852
18008
  }
17853
18009
  return value;
17854
18010
  }, capacitorExecutable = async (projectRoot) => {
17855
- const executable = join51(projectRoot, "node_modules", ".bin", "cap");
18011
+ const executable = join52(projectRoot, "node_modules", ".bin", "cap");
17856
18012
  try {
17857
18013
  await access11(executable);
17858
18014
  return executable;
@@ -18173,7 +18329,7 @@ Mobile release transport checks failed.`);
18173
18329
  const durationMs = Math.round(performance.now() - startedAt);
18174
18330
  console.log(`Built ${release.metadata.signed ? "signed" : "unsigned"} Android App Bundle in ${getDurationString(durationMs)}.`);
18175
18331
  console.log(`Artifact: ${release.artifactPath}`);
18176
- console.log(`Metadata: ${join51(release.releaseRoot, "release.json")}`);
18332
+ console.log(`Metadata: ${join52(release.releaseRoot, "release.json")}`);
18177
18333
  return release;
18178
18334
  } finally {
18179
18335
  sendTelemetryEvent("mobile:android-release-build", {
@@ -18276,7 +18432,7 @@ Mobile release transport checks failed.`);
18276
18432
  const durationMs = Math.round(performance.now() - startedAt);
18277
18433
  console.log(`Built ${release.metadata.signed ? "signed" : "unsigned"} iOS IPA ${release.metadata.marketingVersion}${release.metadata.buildNumber ? ` (${release.metadata.buildNumber})` : ""} in ${getDurationString(durationMs)}.`);
18278
18434
  console.log(`Artifact: ${release.artifactPath}`);
18279
- console.log(`Metadata: ${join51(release.releaseRoot, "release.json")}`);
18435
+ console.log(`Metadata: ${join52(release.releaseRoot, "release.json")}`);
18280
18436
  return release;
18281
18437
  } finally {
18282
18438
  sendTelemetryEvent("mobile:ios-release-build", {
@@ -18383,7 +18539,7 @@ Mobile release transport checks failed.`);
18383
18539
  checks.push({
18384
18540
  id: "sync.storage-schema",
18385
18541
  label: `Offline schema ${schema.components.map((component2) => `${component2.id}@${component2.version}`).join(", ")}`,
18386
- path: join51(projectRoot, "package.json"),
18542
+ path: join52(projectRoot, "package.json"),
18387
18543
  platform: "host",
18388
18544
  status: "pass"
18389
18545
  });
@@ -18391,7 +18547,7 @@ Mobile release transport checks failed.`);
18391
18547
  checks.push({
18392
18548
  id: "sync.storage-schema",
18393
18549
  label: "Offline schema metadata is invalid",
18394
- path: join51(projectRoot, "package.json"),
18550
+ path: join52(projectRoot, "package.json"),
18395
18551
  platform: "host",
18396
18552
  remediation: error instanceof Error ? error.message : String(error),
18397
18553
  status: "fail"
@@ -18544,12 +18700,12 @@ Emulator setup verification:`);
18544
18700
  timeoutMs
18545
18701
  });
18546
18702
  }, writeAndroidFailureArtifacts = async (options) => {
18547
- await mkdir13(options.artifactRoot, { recursive: true });
18548
- const screenshot = options.session ? await options.session.screenshot(join51(options.artifactRoot, "android-failure.png")).catch(() => {
18703
+ await mkdir14(options.artifactRoot, { recursive: true });
18704
+ const screenshot = options.session ? await options.session.screenshot(join52(options.artifactRoot, "android-failure.png")).catch(() => {
18549
18705
  return;
18550
18706
  }) : undefined;
18551
- const diagnosticPath = join51(options.artifactRoot, "android-failure.json");
18552
- await writeFile15(diagnosticPath, `${JSON.stringify({
18707
+ const diagnosticPath = join52(options.artifactRoot, "android-failure.json");
18708
+ await writeFile16(diagnosticPath, `${JSON.stringify({
18553
18709
  diagnostics: options.session?.diagnostics ?? [],
18554
18710
  error: options.error instanceof Error ? options.error.message : String(options.error),
18555
18711
  platform: "android",
@@ -18725,8 +18881,8 @@ Emulator setup verification:`);
18725
18881
  throw new Error(`${label} failed: ${result.stderr.trim() || result.stdout.trim() || `status ${result.exitCode}`}`);
18726
18882
  return result;
18727
18883
  }, writeIosFailureArtifacts = async (options) => {
18728
- await mkdir13(options.artifactRoot, { recursive: true });
18729
- const screenshot = join51(options.artifactRoot, "ios-failure.png");
18884
+ await mkdir14(options.artifactRoot, { recursive: true });
18885
+ const screenshot = join52(options.artifactRoot, "ios-failure.png");
18730
18886
  const screenshotResult = captureCommand4([
18731
18887
  options.xcrun,
18732
18888
  "simctl",
@@ -18735,8 +18891,8 @@ Emulator setup verification:`);
18735
18891
  "screenshot",
18736
18892
  screenshot
18737
18893
  ]);
18738
- const diagnosticPath = join51(options.artifactRoot, "ios-failure.json");
18739
- await writeFile15(diagnosticPath, `${JSON.stringify({
18894
+ const diagnosticPath = join52(options.artifactRoot, "ios-failure.json");
18895
+ await writeFile16(diagnosticPath, `${JSON.stringify({
18740
18896
  appId: options.appId,
18741
18897
  error: options.error instanceof Error ? options.error.message : String(options.error),
18742
18898
  platform: "ios",
@@ -18750,6 +18906,45 @@ Emulator setup verification:`);
18750
18906
  diagnosticPath,
18751
18907
  screenshot: screenshotResult.exitCode === 0 ? screenshot : undefined
18752
18908
  };
18909
+ }, iosReportRoot = (args, projectRoot) => {
18910
+ const index = args.indexOf("--report");
18911
+ if (index === NOT_FOUND3)
18912
+ return;
18913
+ const candidate = args[index + 1];
18914
+ const explicit = candidate?.startsWith("--") ? undefined : candidate;
18915
+ const timestamp = new Date().toISOString().replaceAll(":", "-");
18916
+ return safeArtifactRoot(projectRoot, explicit ?? `.absolutejs/mobile/test-reports/ios-${timestamp}`);
18917
+ }, iosReportMetadata = async (xcrun) => {
18918
+ const xcodebuildPath = requireCapturedIosCommand([xcrun, "--find", "xcodebuild"], "Xcode version inspection").stdout.trim();
18919
+ const xcodeVersion = requireCapturedIosCommand([xcodebuildPath, "-version"], "Xcode version inspection").stdout.trim();
18920
+ const macosVersion = requireCapturedIosCommand(["/usr/bin/sw_vers", "-productVersion"], "macOS version inspection").stdout.trim();
18921
+ let absolutejsVersion = process.env.ABSOLUTE_VERSION ?? "unknown";
18922
+ for (const candidate of [
18923
+ resolve41(import.meta.dir, "..", "..", "package.json"),
18924
+ resolve41(import.meta.dir, "..", "..", "..", "package.json")
18925
+ ]) {
18926
+ const version2 = await readPackageVersionForIosReport(candidate).catch(() => "unknown");
18927
+ if (version2 === "unknown")
18928
+ continue;
18929
+ absolutejsVersion = version2;
18930
+ break;
18931
+ }
18932
+ return {
18933
+ absolutejsVersion,
18934
+ bunVersion: Bun.version,
18935
+ macosVersion,
18936
+ xcodeVersion
18937
+ };
18938
+ }, writeRequestedIosReport = async (options) => {
18939
+ const reportRoot = iosReportRoot(options.args, options.projectRoot);
18940
+ if (!reportRoot)
18941
+ return;
18942
+ const metadata = await iosReportMetadata(options.xcrun);
18943
+ const paths = await writeAbsoluteIosPartnerReport(reportRoot, createAbsoluteIosPartnerReport({ ...metadata, run: options.run }));
18944
+ const print = options.args.includes("--json") ? console.error : console.log;
18945
+ print(`iOS partner report: ${paths.markdownPath}`);
18946
+ print(`Return this report directory: ${paths.directory}`);
18947
+ return paths;
18753
18948
  }, testIos = async (args) => {
18754
18949
  const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
18755
18950
  const { https, instance, port } = requireIosTestContext(args, projectRoot);
@@ -18760,7 +18955,8 @@ Emulator setup verification:`);
18760
18955
  const timeoutMs = androidTestTimeout(args);
18761
18956
  const xcrun = await requireIosXcrun();
18762
18957
  const simulator = selectIosSimulator(xcrun, valueAfter(args, "--udid") ?? valueAfter(args, "--serial"));
18763
- const artifactRoot = safeArtifactRoot(projectRoot, valueAfter(args, "--artifacts"));
18958
+ const reportRoot = iosReportRoot(args, projectRoot);
18959
+ const artifactRoot = reportRoot ?? safeArtifactRoot(projectRoot, valueAfter(args, "--artifacts"));
18764
18960
  const startedAt = performance.now();
18765
18961
  try {
18766
18962
  requireCapturedIosCommand([
@@ -18780,8 +18976,8 @@ Emulator setup verification:`);
18780
18976
  mobile.appId
18781
18977
  ], "iOS app launch");
18782
18978
  await waitForIosHmrClient({ https, port, timeoutMs });
18783
- await mkdir13(artifactRoot, { recursive: true });
18784
- const screenshot = join51(artifactRoot, "ios-simulator.png");
18979
+ await mkdir14(artifactRoot, { recursive: true });
18980
+ const screenshot = join52(artifactRoot, "ios-simulator.png");
18785
18981
  requireCapturedIosCommand([xcrun, "simctl", "io", simulator.udid, "screenshot", screenshot], "iOS simulator screenshot");
18786
18982
  const hmrApply = await waitForRequestedIosHmr(args, instance, timeoutMs);
18787
18983
  const report = {
@@ -18804,6 +19000,28 @@ Emulator setup verification:`);
18804
19000
  waitedForHmr: args.includes("--wait-for-hmr")
18805
19001
  });
18806
19002
  printIosTestReport(report, args.includes("--json"));
19003
+ await writeRequestedIosReport({
19004
+ args,
19005
+ projectRoot,
19006
+ run: {
19007
+ appId: report.appId,
19008
+ durationMs: report.durationMs,
19009
+ ...report.hmrApply ? {
19010
+ hmr: {
19011
+ ...report.hmrApply.clientMs === undefined ? {} : { clientMs: report.hmrApply.clientMs },
19012
+ durationMs: report.hmrApply.duration,
19013
+ outcome: report.hmrApply.outcome,
19014
+ ...report.hmrApply.serverMs === undefined ? {} : { serverMs: report.hmrApply.serverMs }
19015
+ }
19016
+ } : {},
19017
+ hmrConnected: report.hmrConnected,
19018
+ port: report.port,
19019
+ screenshot: report.screenshot,
19020
+ status: report.status,
19021
+ udid: report.udid
19022
+ },
19023
+ xcrun
19024
+ });
18807
19025
  return report;
18808
19026
  } catch (error) {
18809
19027
  const durationMs = Math.round(performance.now() - startedAt);
@@ -18822,6 +19040,21 @@ Emulator setup verification:`);
18822
19040
  udid: simulator.udid,
18823
19041
  xcrun
18824
19042
  });
19043
+ await writeRequestedIosReport({
19044
+ args,
19045
+ projectRoot,
19046
+ run: {
19047
+ appId: mobile.appId,
19048
+ durationMs,
19049
+ error: sanitizeIosReportText(error instanceof Error ? error.message : String(error)),
19050
+ hmrConnected: false,
19051
+ port,
19052
+ ...screenshot ? { screenshot } : {},
19053
+ status: "fail",
19054
+ udid: simulator.udid
19055
+ },
19056
+ xcrun
19057
+ });
18825
19058
  throw new Error(`${error instanceof Error ? error.message : String(error)} Failure diagnostics: ${diagnosticPath}${screenshot ? `; screenshot: ${screenshot}` : ""}`, { cause: error });
18826
19059
  }
18827
19060
  }, runMobile = async (args) => {
@@ -18878,7 +19111,7 @@ Emulator setup verification:`);
18878
19111
  await publishIos(args.slice(2));
18879
19112
  return;
18880
19113
  }
18881
- throw new TypeError("Usage: absolute mobile <pair mac <name> <user@host> [--port n] [--workspace path] | remotes [--json] | unpair mac <name> | init [--no-native] [--force] | sync [ios|android] | associations [--outdir dir] [--verify] | doctor [ios|android|release] [--remote name] [--json|--fix [--yes]] | build <android|ios> [server-entry] [--outdir dir] [--web-outdir dir] [--unsigned] | publish android [server-entry] [--registry module] [--channel name] [--play-track track] [--play-status completed|draft|halted|in-progress] [--play-rollout fraction] [--play-name name] [--play-notes language=text] [--play-update-priority 0..5] [--play-hold-review] [--play-cancel-existing-review] [--outdir dir] [--web-outdir dir] [--unsigned] | publish ios [server-entry] [--registry module] [--channel name] [--testflight-group name-or-id] [--testflight-notes locale=text] [--testflight-submit-review] [--outdir dir] [--web-outdir dir] [--unsigned] | test android [--route path] [--wait-for-hmr] [--timeout ms] [--port n] [--serial id] [--artifacts dir] [--json] | test ios [--wait-for-hmr] [--timeout ms] [--port n] [--udid id] [--artifacts dir] [--json]> [--config path]");
19114
+ throw new TypeError("Usage: absolute mobile <pair mac <name> <user@host> [--port n] [--workspace path] | remotes [--json] | unpair mac <name> | init [--no-native] [--force] | sync [ios|android] | associations [--outdir dir] [--verify] | doctor [ios|android|release] [--remote name] [--json|--fix [--yes]] | build <android|ios> [server-entry] [--outdir dir] [--web-outdir dir] [--unsigned] | publish android [server-entry] [--registry module] [--channel name] [--play-track track] [--play-status completed|draft|halted|in-progress] [--play-rollout fraction] [--play-name name] [--play-notes language=text] [--play-update-priority 0..5] [--play-hold-review] [--play-cancel-existing-review] [--outdir dir] [--web-outdir dir] [--unsigned] | publish ios [server-entry] [--registry module] [--channel name] [--testflight-group name-or-id] [--testflight-notes locale=text] [--testflight-submit-review] [--outdir dir] [--web-outdir dir] [--unsigned] | test android [--route path] [--wait-for-hmr] [--timeout ms] [--port n] [--serial id] [--artifacts dir] [--json] | test ios [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--udid id] [--artifacts dir] [--json]> [--config path]");
18882
19115
  };
18883
19116
  var init_mobile = __esm(() => {
18884
19117
  init_dependencies();
@@ -18900,6 +19133,7 @@ var init_mobile = __esm(() => {
18900
19133
  init_iosRelease();
18901
19134
  init_iosSimulatorController();
18902
19135
  init_iosConformance();
19136
+ init_iosTestReport();
18903
19137
  init_releasePublisher();
18904
19138
  init_start();
18905
19139
  init_utils();
@@ -18929,11 +19163,11 @@ var init_mobile = __esm(() => {
18929
19163
  "@capacitor/cli@8.5.0",
18930
19164
  "@capacitor/android@8.5.0",
18931
19165
  "@capacitor/ios@8.5.0",
18932
- "@absolutejs/devices@0.2.0",
18933
- "@absolutejs/devices-capacitor@0.3.1"
19166
+ "@absolutejs/devices@0.3.0",
19167
+ "@absolutejs/devices-capacitor@0.4.0"
18934
19168
  ];
18935
19169
  CAPACITOR_SYNC_PACKAGE_SPECS = [
18936
- "@absolutejs/sync-capacitor@0.9.0",
19170
+ "@absolutejs/sync-capacitor@0.9.1",
18937
19171
  "@capacitor-community/sqlite@8.1.1"
18938
19172
  ];
18939
19173
  });
@@ -18943,9 +19177,9 @@ var exports_typecheck = {};
18943
19177
  __export(exports_typecheck, {
18944
19178
  typecheck: () => typecheck
18945
19179
  });
18946
- import { resolve as resolve42, join as join52 } from "path";
19180
+ import { resolve as resolve42, join as join53 } from "path";
18947
19181
  import { existsSync as existsSync42, readFileSync as readFileSync40 } from "fs";
18948
- import { mkdir as mkdir14, writeFile as writeFile16 } from "fs/promises";
19182
+ import { mkdir as mkdir15, writeFile as writeFile17 } from "fs/promises";
18949
19183
  var isCommandService3 = (service) => service.kind === "command" || Array.isArray(service.command), resolveConfigPath = (configPath2) => resolve42(configPath2 ?? process.env.ABSOLUTE_CONFIG ?? "absolute.config.ts"), getTypecheckTargets = async (configPath2) => {
18950
19184
  if (!existsSync42(resolveConfigPath(configPath2))) {
18951
19185
  const defaultService = {};
@@ -19052,8 +19286,8 @@ Found ${errorCount} error${suffix}.`;
19052
19286
  console.error("\x1B[31m\u2717\x1B[0m vue-tsc is required for Vue type checking. Install it: bun add -d vue-tsc");
19053
19287
  process.exit(1);
19054
19288
  }
19055
- const vueTsconfigPath = join52(cacheDir, "tsconfig.vue-check.json");
19056
- await writeFile16(vueTsconfigPath, JSON.stringify({
19289
+ const vueTsconfigPath = join53(cacheDir, "tsconfig.vue-check.json");
19290
+ await writeFile17(vueTsconfigPath, JSON.stringify({
19057
19291
  compilerOptions: {
19058
19292
  rootDir: ".."
19059
19293
  },
@@ -19072,7 +19306,7 @@ Found ${errorCount} error${suffix}.`;
19072
19306
  ...base,
19073
19307
  "--incremental",
19074
19308
  "--tsBuildInfoFile",
19075
- join52(cacheDir, "vue-tsc.tsbuildinfo")
19309
+ join53(cacheDir, "vue-tsc.tsbuildinfo")
19076
19310
  ]);
19077
19311
  if (cached.exitCode === 0 || cached.output.length > 0)
19078
19312
  return cached;
@@ -19083,8 +19317,8 @@ Found ${errorCount} error${suffix}.`;
19083
19317
  console.error("\x1B[31m\u2717\x1B[0m @angular/compiler-cli is required for Angular type checking. Install it: bun add -d @angular/compiler-cli");
19084
19318
  process.exit(1);
19085
19319
  }
19086
- const angularTsconfigPath = join52(cacheDir, "tsconfig.angular-check.json");
19087
- await writeFile16(angularTsconfigPath, JSON.stringify({
19320
+ const angularTsconfigPath = join53(cacheDir, "tsconfig.angular-check.json");
19321
+ await writeFile17(angularTsconfigPath, JSON.stringify({
19088
19322
  angularCompilerOptions: {
19089
19323
  strictTemplates: true
19090
19324
  },
@@ -19103,8 +19337,8 @@ Found ${errorCount} error${suffix}.`;
19103
19337
  console.error("\x1B[31m\u2717\x1B[0m typescript is required for type checking. Install it: bun add -d typescript");
19104
19338
  process.exit(1);
19105
19339
  }
19106
- const tscConfigPath = join52(cacheDir, "tsconfig.typecheck.json");
19107
- return writeFile16(tscConfigPath, JSON.stringify({
19340
+ const tscConfigPath = join53(cacheDir, "tsconfig.typecheck.json");
19341
+ return writeFile17(tscConfigPath, JSON.stringify({
19108
19342
  compilerOptions: {
19109
19343
  rootDir: ".."
19110
19344
  },
@@ -19118,7 +19352,7 @@ Found ${errorCount} error${suffix}.`;
19118
19352
  resolve42(tscConfigPath),
19119
19353
  "--incremental",
19120
19354
  "--tsBuildInfoFile",
19121
- join52(cacheDir, "tsc.tsbuildinfo"),
19355
+ join53(cacheDir, "tsc.tsbuildinfo"),
19122
19356
  "--pretty"
19123
19357
  ]));
19124
19358
  }, buildSvelteCheck = async (cacheDir, svelteDir) => {
@@ -19127,8 +19361,8 @@ Found ${errorCount} error${suffix}.`;
19127
19361
  console.error("\x1B[31m\u2717\x1B[0m svelte-check is required for Svelte type checking. Install it: bun add -d svelte-check");
19128
19362
  process.exit(1);
19129
19363
  }
19130
- const svelteTsconfigPath = join52(cacheDir, "tsconfig.svelte-check.json");
19131
- await writeFile16(svelteTsconfigPath, JSON.stringify({
19364
+ const svelteTsconfigPath = join53(cacheDir, "tsconfig.svelte-check.json");
19365
+ await writeFile17(svelteTsconfigPath, JSON.stringify({
19132
19366
  extends: resolve42("tsconfig.json"),
19133
19367
  files: ABSOLUTE_TYPECHECK_FILES,
19134
19368
  include: [`../${svelteDir}/**/*`]
@@ -19157,7 +19391,7 @@ Found ${errorCount} error${suffix}.`;
19157
19391
  ...new Set(targets.map((config) => config.angularDirectory).filter((dir) => typeof dir === "string" && dir.length > 0))
19158
19392
  ];
19159
19393
  const cacheDir = ".absolutejs";
19160
- await mkdir14(cacheDir, { recursive: true });
19394
+ await mkdir15(cacheDir, { recursive: true });
19161
19395
  const checks = [];
19162
19396
  checks.push(hasVue ? buildVueTscCheck(cacheDir) : buildTscCheck(cacheDir));
19163
19397
  for (const svelteDir of hasSvelte ? svelteDirs : []) {
package/dist/index.js CHANGED
@@ -11834,6 +11834,20 @@ var DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, DEFAULT_QUALITY, OPTIMIZATION_END
11834
11834
  return "webp";
11835
11835
  }
11836
11836
  return "jpeg";
11837
+ }, sniffImageMime = (buffer) => {
11838
+ if (buffer.length < 12)
11839
+ return null;
11840
+ if (buffer[0] === 137 && buffer[1] === 80 && buffer[2] === 78)
11841
+ return "image/png";
11842
+ if (buffer[0] === 255 && buffer[1] === 216)
11843
+ return "image/jpeg";
11844
+ if (buffer[0] === 71 && buffer[1] === 73 && buffer[2] === 70)
11845
+ return "image/gif";
11846
+ if (buffer.toString("ascii", 0, 4) === "RIFF" && buffer.toString("ascii", 8, 12) === "WEBP")
11847
+ return "image/webp";
11848
+ if (buffer.toString("ascii", 4, 12) === "ftypavif")
11849
+ return "image/avif";
11850
+ return null;
11837
11851
  }, AVIF_QUALITY_OFFSET = 20, AVIF_EFFORT = 3, PNG_COMPRESSION_LEVEL = 9, optimizeWithBunImage = async (buffer, width, quality, format) => {
11838
11852
  const pipeline = new Bun.Image(buffer).resize(width, undefined, {
11839
11853
  withoutEnlargement: true
@@ -30465,7 +30479,7 @@ var DEFAULT_CACHE_TTL_SECONDS = 60, MS_PER_SECOND = 1000, MAX_QUALITY = 100, avi
30465
30479
  const { isRemote, resolvedPath } = security;
30466
30480
  const acceptHeader = request.headers.get("Accept") ?? "";
30467
30481
  const format = negotiateFormat(acceptHeader, configuredFormats);
30468
- const mime = formatToMime(format);
30482
+ let mime = formatToMime(format);
30469
30483
  const cacheKey2 = getCacheKey(url, width, quality, format);
30470
30484
  const cached = readFromCache(cacheDir, cacheKey2);
30471
30485
  if (cached && !isCacheStale(cached.meta)) {
@@ -30505,6 +30519,7 @@ var DEFAULT_CACHE_TTL_SECONDS = 60, MS_PER_SECOND = 1000, MAX_QUALITY = 100, avi
30505
30519
  optimizedBuffer = await optimizeImage(sourceBuffer, width, quality, format);
30506
30520
  } catch {
30507
30521
  optimizedBuffer = sourceBuffer;
30522
+ mime = sniffImageMime(sourceBuffer) ?? mime;
30508
30523
  }
30509
30524
  const etag = `"${cacheKey2}"`;
30510
30525
  const meta = {
@@ -40419,5 +40434,5 @@ export {
40419
40434
  ANGULAR_INIT_TIMEOUT_MS
40420
40435
  };
40421
40436
 
40422
- //# debugId=C0E84CA8E87CA8B764756E2164756E21
40437
+ //# debugId=FE6F812740A4A80564756E2164756E21
40423
40438
  //# sourceMappingURL=index.js.map