@absolutejs/absolute 0.20.0-beta.27 → 0.20.0-beta.29

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.
@@ -325,31 +325,31 @@ var object = (value) => typeof value === "object" && value !== null && !Array.is
325
325
  return;
326
326
  directory = parent;
327
327
  }
328
- }, metadataError = (id, detail) => new TypeError(`Invalid AbsoluteJS Sync schema metadata for ${id}: ${detail}`), positiveVersion2 = (value, id, field) => {
328
+ }, metadataError = (id, detail) => new TypeError(`Invalid AbsoluteJS Sync schema metadata for ${id}: ${detail}`), positiveVersion2 = (value, id, field2) => {
329
329
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)
330
- throw metadataError(id, `${field} must be a positive safe integer.`);
330
+ throw metadataError(id, `${field2} must be a positive safe integer.`);
331
331
  return value;
332
- }, nonEmpty = (value, id, field) => {
332
+ }, nonEmpty = (value, id, field2) => {
333
333
  if (typeof value !== "string" || value.trim() !== value || value.length === 0)
334
- throw metadataError(id, `${field} must be a non-empty trimmed string.`);
334
+ throw metadataError(id, `${field2} must be a non-empty trimmed string.`);
335
335
  return value;
336
336
  }, requireObject = (value, id, detail) => {
337
337
  if (!object(value))
338
338
  throw metadataError(id, detail);
339
339
  return value;
340
- }, unknownField = (record, key) => record[key], normalizeJsonValue2 = (value, id, field) => {
340
+ }, unknownField = (record, key) => record[key], normalizeJsonValue2 = (value, id, field2) => {
341
341
  if (value === null || typeof value === "string" || typeof value === "boolean")
342
342
  return value;
343
343
  if (typeof value === "number" && Number.isFinite(value))
344
344
  return value;
345
345
  if (Array.isArray(value))
346
- return value.map((entry) => normalizeJsonValue2(entry, id, field));
346
+ return value.map((entry) => normalizeJsonValue2(entry, id, field2));
347
347
  if (object(value))
348
348
  return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
349
349
  key,
350
- normalizeJsonValue2(entry, id, field)
350
+ normalizeJsonValue2(entry, id, field2)
351
351
  ]));
352
- throw metadataError(id, `${field} must be JSON-safe.`);
352
+ throw metadataError(id, `${field2} must be JSON-safe.`);
353
353
  }, operation = (value, id, index) => {
354
354
  const record = requireObject(value, id, `migration operation ${index} must be an object.`);
355
355
  const type = Reflect.get(record, "type");
@@ -363,13 +363,13 @@ var object = (value) => typeof value === "object" && value !== null && !Array.is
363
363
  to: nonEmpty(Reflect.get(record, "to"), id, `operation ${index}.to`),
364
364
  type
365
365
  };
366
- const field = nonEmpty(Reflect.get(record, "field"), id, `operation ${index}.field`);
366
+ const field2 = nonEmpty(Reflect.get(record, "field"), id, `operation ${index}.field`);
367
367
  if (type === "remove-field")
368
- return { collection, field, type };
368
+ return { collection, field: field2, type };
369
369
  if (type === "set-default")
370
370
  return {
371
371
  collection,
372
- field,
372
+ field: field2,
373
373
  type,
374
374
  value: normalizeJsonValue2(Reflect.get(record, "value"), id, `operation ${index}.value`)
375
375
  };
@@ -598,24 +598,24 @@ var DEVICES_PACKAGE = "@absolutejs/devices", CAPACITOR_ADAPTER = "@absolutejs/de
598
598
  if (!object2(value))
599
599
  throw new TypeError(`${path} must contain an object.`);
600
600
  return value;
601
- }, text = (value, field) => {
601
+ }, text = (value, field2) => {
602
602
  if (typeof value !== "string" || value.length === 0)
603
- throw new TypeError(`${field} must be a non-empty string.`);
603
+ throw new TypeError(`${field2} must be a non-empty string.`);
604
604
  return value;
605
- }, androidPermissions = (value, field) => {
605
+ }, androidPermissions = (value, field2) => {
606
606
  if (value === undefined)
607
607
  return;
608
608
  if (!object2(value))
609
- throw new TypeError(`${field} must be an object.`);
609
+ throw new TypeError(`${field2} must be an object.`);
610
610
  const { permissions } = value;
611
611
  if (!Array.isArray(permissions) || !permissions.every((permission) => typeof permission === "string" && ANDROID_PERMISSION_PATTERN.test(permission)))
612
- throw new TypeError(`${field}.permissions must contain Android permission names.`);
612
+ throw new TypeError(`${field2}.permissions must contain Android permission names.`);
613
613
  return [...permissions];
614
- }, iosPrivacyAccessedApis = (value, field) => {
614
+ }, iosPrivacyAccessedApis = (value, field2) => {
615
615
  if (value === undefined)
616
616
  return;
617
617
  if (!object2(value))
618
- throw new TypeError(`${field} must be an object.`);
618
+ throw new TypeError(`${field2} must be an object.`);
619
619
  const privacy = {};
620
620
  for (const api of IOS_PRIVACY_ACCESSED_APIS) {
621
621
  const reasons = value[api];
@@ -623,17 +623,17 @@ var DEVICES_PACKAGE = "@absolutejs/devices", CAPACITOR_ADAPTER = "@absolutejs/de
623
623
  continue;
624
624
  const supported = IOS_PRIVACY_ACCESSED_API_REASONS[api];
625
625
  if (!Array.isArray(reasons) || reasons.length === 0 || !reasons.every((reason) => typeof reason === "string" && supported.has(reason)))
626
- throw new TypeError(`${field} contains an unsupported API or reason.`);
626
+ throw new TypeError(`${field2} contains an unsupported API or reason.`);
627
627
  privacy[api] = [...reasons];
628
628
  }
629
629
  if (Object.keys(value).some((api) => !IOS_PRIVACY_ACCESSED_APIS.some((known) => known === api)))
630
- throw new TypeError(`${field} contains an unsupported API or reason.`);
630
+ throw new TypeError(`${field2} contains an unsupported API or reason.`);
631
631
  return privacy;
632
- }, iosNativeRequirements = (value, field) => {
632
+ }, iosNativeRequirements = (value, field2) => {
633
633
  if (value === undefined)
634
634
  return;
635
635
  if (!object2(value))
636
- throw new TypeError(`${field} must be an object.`);
636
+ throw new TypeError(`${field2} must be an object.`);
637
637
  const {
638
638
  privacyAccessedApis,
639
639
  pushNotifications,
@@ -641,12 +641,12 @@ var DEVICES_PACKAGE = "@absolutejs/devices", CAPACITOR_ADAPTER = "@absolutejs/de
641
641
  usageDescriptions
642
642
  } = value;
643
643
  if (pushNotifications !== undefined && pushNotifications !== true)
644
- throw new TypeError(`${field}.pushNotifications must be true.`);
644
+ throw new TypeError(`${field2}.pushNotifications must be true.`);
645
645
  if (systemBars !== undefined && systemBars !== true)
646
- throw new TypeError(`${field}.systemBars must be true.`);
646
+ throw new TypeError(`${field2}.systemBars must be true.`);
647
647
  if (usageDescriptions !== undefined && (!Array.isArray(usageDescriptions) || !usageDescriptions.every((purpose) => typeof purpose === "string" && IOS_USAGE_DESCRIPTIONS.has(purpose))))
648
- throw new TypeError(`${field}.usageDescriptions contains an unsupported purpose.`);
649
- const privacy = iosPrivacyAccessedApis(privacyAccessedApis, `${field}.privacyAccessedApis`);
648
+ throw new TypeError(`${field2}.usageDescriptions contains an unsupported purpose.`);
649
+ const privacy = iosPrivacyAccessedApis(privacyAccessedApis, `${field2}.privacyAccessedApis`);
650
650
  return {
651
651
  ...privacy === undefined ? {} : { privacyAccessedApis: privacy },
652
652
  ...pushNotifications === true ? { pushNotifications: true } : {},
@@ -771,8 +771,8 @@ var DEVICES_PACKAGE = "@absolutejs/devices", CAPACITOR_ADAPTER = "@absolutejs/de
771
771
  }, directAbsoluteProjectPackages = (projectRoot) => {
772
772
  const manifest = readJson(join13(resolve11(projectRoot), "package.json"));
773
773
  const packages = new Set;
774
- for (const field of ["dependencies", "devDependencies"]) {
775
- const dependencies = manifest[field];
774
+ for (const field2 of ["dependencies", "devDependencies"]) {
775
+ const dependencies = manifest[field2];
776
776
  if (object2(dependencies))
777
777
  for (const name of Object.keys(dependencies))
778
778
  packages.add(name);
@@ -2069,6 +2069,92 @@ var buildAbsoluteAndroidRelease = async (options) => {
2069
2069
  };
2070
2070
  return installRelease(artifactPath, metadata, safeOutputDirectory(projectRoot, options.outputDirectory));
2071
2071
  };
2072
+ // src/mobile/androidUpgradeConformance.ts
2073
+ import { performance as performance2 } from "perf_hooks";
2074
+ var captureCommand3 = async (command) => {
2075
+ const process2 = Bun.spawn(command, { stderr: "pipe", stdout: "pipe" });
2076
+ const [exitCode, stderr, stdout] = await Promise.all([
2077
+ process2.exited,
2078
+ new Response(process2.stderr).text(),
2079
+ new Response(process2.stdout).text()
2080
+ ]);
2081
+ return { exitCode, stderr, stdout };
2082
+ };
2083
+ var field = (output, name) => new RegExp(`^\\s*${name}=([^\\r\\n]+)$`, "mu").exec(output)?.[1]?.trim();
2084
+ var inspectAbsoluteAndroidInstalledApp = async (adb, serial, appId, run = captureCommand3) => {
2085
+ const result = await run([
2086
+ adb,
2087
+ "-s",
2088
+ serial,
2089
+ "shell",
2090
+ "dumpsys",
2091
+ "package",
2092
+ appId
2093
+ ]);
2094
+ if (result.exitCode !== 0)
2095
+ throw new Error(`Could not inspect installed Android app ${appId}: ${result.stderr.trim() || result.stdout.trim()}`);
2096
+ const installed = parseAbsoluteAndroidInstalledApp(appId, result.stdout);
2097
+ if (!installed)
2098
+ throw new Error(`Android app ${appId} is not installed on ${serial}.`);
2099
+ return installed;
2100
+ };
2101
+ var parseAbsoluteAndroidInstalledApp = (appId, output) => {
2102
+ const packageName = /^\s*Package \[([^\]]+)\]/mu.exec(output)?.[1];
2103
+ if (packageName !== appId && !output.includes(`package:${appId}`))
2104
+ return null;
2105
+ const versionCodeText = /^\s*versionCode=(\d+)/mu.exec(output)?.[1];
2106
+ return {
2107
+ appId,
2108
+ ...field(output, "dataDir") ? { dataDirectory: field(output, "dataDir") } : {},
2109
+ ...field(output, "firstInstallTime") ? { firstInstallTime: field(output, "firstInstallTime") } : {},
2110
+ ...field(output, "lastUpdateTime") ? { lastUpdateTime: field(output, "lastUpdateTime") } : {},
2111
+ ...field(output, "userId") || field(output, "appId") ? { uid: field(output, "userId") ?? field(output, "appId") } : {},
2112
+ ...versionCodeText ? { versionCode: Number(versionCodeText) } : {},
2113
+ ...field(output, "versionName") ? { versionName: field(output, "versionName") } : {}
2114
+ };
2115
+ };
2116
+ var unchanged = (name, before, after) => {
2117
+ if (!before || !after)
2118
+ throw new Error(`Android did not report ${name} for the upgrade proof.`);
2119
+ if (before !== after)
2120
+ throw new Error(`Android ${name} changed during the in-place upgrade.`);
2121
+ };
2122
+ var runAbsoluteAndroidUpgradeConformance = async (options) => {
2123
+ const run = options.run ?? captureCommand3;
2124
+ const startedAt = performance2.now();
2125
+ const before = await inspectAbsoluteAndroidInstalledApp(options.adb, options.serial, options.appId, run);
2126
+ const installStartedAt = performance2.now();
2127
+ const installed = await run([
2128
+ options.adb,
2129
+ "-s",
2130
+ options.serial,
2131
+ "install",
2132
+ "-r",
2133
+ options.apkPath
2134
+ ]);
2135
+ const installMs = Math.round(performance2.now() - installStartedAt);
2136
+ if (installed.exitCode !== 0 || !installed.stdout.includes("Success"))
2137
+ throw new Error(`Android in-place upgrade failed: ${installed.stderr.trim() || installed.stdout.trim()}`);
2138
+ const after = await inspectAbsoluteAndroidInstalledApp(options.adb, options.serial, options.appId, run);
2139
+ unchanged("application UID", before.uid, after.uid);
2140
+ unchanged("data directory", before.dataDirectory, after.dataDirectory);
2141
+ unchanged("first install timestamp", before.firstInstallTime, after.firstInstallTime);
2142
+ if (before.versionCode !== undefined && after.versionCode !== undefined && after.versionCode <= before.versionCode)
2143
+ throw new Error(`Android versionCode did not increase (${before.versionCode} -> ${after.versionCode}).`);
2144
+ await options.afterInstall?.(after);
2145
+ const state = await options.verifyState();
2146
+ const compatibilityPass = !options.compatibility || options.compatibility.nPlusOne === "compatible" && options.compatibility.nPlusTwo === "compatible" && options.compatibility.nPlusThree === "upgrade-required" && options.compatibility.rollback === "compatible";
2147
+ const outcome = Object.values(state).every(Boolean) && compatibilityPass ? "pass" : "fail";
2148
+ return {
2149
+ after,
2150
+ before,
2151
+ ...options.compatibility ? { compatibility: options.compatibility } : {},
2152
+ durationMs: Math.round(performance2.now() - startedAt),
2153
+ installMs,
2154
+ outcome,
2155
+ state
2156
+ };
2157
+ };
2072
2158
  // src/mobile/iosRelease.ts
2073
2159
  import { createHash as createHash5 } from "crypto";
2074
2160
  import {
@@ -3841,18 +3927,18 @@ var SCHEME_PATTERN = /^[a-z][a-z0-9+.-]*$/;
3841
3927
  var APPLE_APP_ID_PREFIX_PATTERN = /^[A-Z0-9]{10}$/;
3842
3928
  var CERTIFICATE_FINGERPRINT_PATTERN = /^[0-9A-F]{64}$/;
3843
3929
  var HOSTNAME_PATTERN = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/;
3844
- var resolveProjectPath = (projectRoot, value, field) => {
3930
+ var resolveProjectPath = (projectRoot, value, field2) => {
3845
3931
  const root = resolve6(projectRoot);
3846
3932
  const path = resolve6(root, value);
3847
3933
  if (path !== root && !path.startsWith(`${root}/`)) {
3848
- throw new TypeError(`${field} must remain inside the project root.`);
3934
+ throw new TypeError(`${field2} must remain inside the project root.`);
3849
3935
  }
3850
3936
  return path;
3851
3937
  };
3852
- var requireText = (value, field) => {
3938
+ var requireText = (value, field2) => {
3853
3939
  const normalized = value.trim();
3854
3940
  if (!normalized)
3855
- throw new TypeError(`${field} must not be empty.`);
3941
+ throw new TypeError(`${field2} must not be empty.`);
3856
3942
  return normalized;
3857
3943
  };
3858
3944
  var normalizeEntry = (entry) => {
@@ -3961,7 +4047,7 @@ var HTTP_OK = 200;
3961
4047
  var VERIFY_TIMEOUT_MS = 1e4;
3962
4048
  var ANDROID_ASSOCIATION_PATH = "/.well-known/assetlinks.json";
3963
4049
  var APPLE_ASSOCIATION_PATH = "/.well-known/apple-app-site-association";
3964
- var missingIdentity = (field, platform) => new TypeError(`${field} is required to publish ${platform} deep-link association files.`);
4050
+ var missingIdentity = (field2, platform) => new TypeError(`${field2} is required to publish ${platform} deep-link association files.`);
3965
4051
  var createAppleDocument = (config, requireAll) => {
3966
4052
  if (!config.platforms.includes("ios"))
3967
4053
  return;
@@ -4298,8 +4384,8 @@ var buildAbsoluteMobileCompatibilityRelease = async (options) => {
4298
4384
  if (priorAppIds.size > 1 || priorAppIds.size === 1 && !priorAppIds.has(options.appId)) {
4299
4385
  throw new TypeError("Previous mobile compatibility artifacts belong to another app.");
4300
4386
  }
4301
- const unchanged = options.previousArtifacts?.find((artifact2) => artifact2.appBuild === appBuild && artifact2.runtime === options.runtime);
4302
- const generation = unchanged?.generation ?? Math.max(0, ...(options.previousArtifacts ?? []).map((artifact2) => artifact2.generation)) + 1;
4387
+ const unchanged2 = options.previousArtifacts?.find((artifact2) => artifact2.appBuild === appBuild && artifact2.runtime === options.runtime);
4388
+ const generation = unchanged2?.generation ?? Math.max(0, ...(options.previousArtifacts ?? []).map((artifact2) => artifact2.generation)) + 1;
4303
4389
  const artifact = createAbsoluteMobileCompatibilityArtifact({
4304
4390
  appBuild,
4305
4391
  appId: options.appId,
@@ -5605,6 +5691,10 @@ var applyMobileCorsHeaders = (response, origin) => {
5605
5691
  response.headers.append("vary", "Origin");
5606
5692
  return response;
5607
5693
  };
5694
+ var finalizeMobileResponse = (request, response) => {
5695
+ const origin = mobileWebViewOrigin(request);
5696
+ return origin ? applyMobileCorsHeaders(response, origin) : response;
5697
+ };
5608
5698
  var mobilePreflightResponse = (request) => {
5609
5699
  if (request.method !== "OPTIONS")
5610
5700
  return;
@@ -5662,23 +5752,24 @@ var createAbsoluteMobileCompatibilityDispatcher = (options) => {
5662
5752
  return;
5663
5753
  const resolved = resolveAbsoluteMobileCompatibilityRelease(parsed.client, artifacts);
5664
5754
  if (resolved.kind === "upgrade-required") {
5665
- return createAbsoluteMobileUpgradeResponse(resolved.result);
5755
+ return finalizeMobileResponse(request, createAbsoluteMobileUpgradeResponse(resolved.result));
5666
5756
  }
5667
5757
  if (!artifactOwnsRequest(resolved.artifact, parsed.client.pageId, request)) {
5668
- return createAbsoluteMobileInvalidRequestResponse("The requested URL is not assigned to this mobile page.");
5758
+ return finalizeMobileResponse(request, createAbsoluteMobileInvalidRequestResponse("The requested URL is not assigned to this mobile page."));
5669
5759
  }
5670
5760
  if (resolved.artifact.releaseId === options.currentReleaseId) {
5671
5761
  return;
5672
5762
  }
5673
5763
  try {
5674
5764
  const producer = await resolveProducer(resolved.artifact);
5675
- return runWithAbsoluteMobileProducer({
5765
+ const response = await runWithAbsoluteMobileProducer({
5676
5766
  page: resolved.page,
5677
5767
  releaseId: resolved.artifact.releaseId
5678
5768
  }, () => producer.handle(request));
5769
+ return finalizeMobileResponse(request, response);
5679
5770
  } catch (error) {
5680
5771
  console.error(`[Mobile] Failed to load retained producer ${resolved.artifact.releaseId}:`, error);
5681
- return createAbsoluteMobilePageErrorResponse(parsed.client.pageId);
5772
+ return finalizeMobileResponse(request, createAbsoluteMobilePageErrorResponse(parsed.client.pageId));
5682
5773
  }
5683
5774
  }).afterHandle("global", ({ request, responseValue }) => {
5684
5775
  const origin = mobileWebViewOrigin(request);
@@ -6841,6 +6932,7 @@ export {
6841
6932
  startAbsoluteIosDevSession,
6842
6933
  serializeAbsoluteMobileAuthEnvironment,
6843
6934
  runWithAbsoluteMobileProducer,
6935
+ runAbsoluteAndroidUpgradeConformance,
6844
6936
  retainAbsoluteMobileCompatibilityArtifacts,
6845
6937
  resolveAbsoluteMobileRoute,
6846
6938
  resolveAbsoluteMobileNavigation,
@@ -6869,6 +6961,7 @@ export {
6869
6961
  parseAbsoluteMobileBuildPageMetadata,
6870
6962
  parseAbsoluteIosLogLine,
6871
6963
  parseAbsoluteIosHmrLog,
6964
+ parseAbsoluteAndroidInstalledApp,
6872
6965
  pairAbsoluteRemoteMac,
6873
6966
  normalizeAbsoluteMobileConfig,
6874
6967
  navigateAbsoluteMobilePage,
@@ -6888,6 +6981,7 @@ export {
6888
6981
  installAbsoluteMobileAuthEnvironment,
6889
6982
  inspectAbsoluteRemoteMac,
6890
6983
  inspectAbsoluteMobileRouteMetadata,
6984
+ inspectAbsoluteAndroidInstalledApp,
6891
6985
  hashAbsoluteMobilePropsSchema,
6892
6986
  getCurrentAbsoluteMobileProducerContext,
6893
6987
  getAbsoluteRemoteMacProfile,
@@ -6951,5 +7045,5 @@ export {
6951
7045
  ABSOLUTE_ANDROID_RELEASE_FORMAT
6952
7046
  };
6953
7047
 
6954
- //# debugId=70D55943FDDD4B5264756E2164756E21
7048
+ //# debugId=D67F614C7C9ABE9264756E2164756E21
6955
7049
  //# sourceMappingURL=index.js.map