@absolutejs/absolute 0.20.0-beta.18 → 0.20.0-beta.19

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.
@@ -5069,6 +5069,12 @@ var IGNORED_DIRECTORIES = new Set([
5069
5069
  var IDENTIFIER_PATTERN = /^[A-Za-z_$][\w$]*$/u;
5070
5070
  var CAPACITOR_MODULE_PATTERN = /^@absolutejs\/devices-capacitor\/[a-z][a-z0-9-]*$/u;
5071
5071
  var CAPACITOR_PACKAGE_PATTERN = /^@capacitor\/[a-z][a-z0-9-]*@\d+\.\d+\.\d+$/u;
5072
+ var ANDROID_PERMISSION_PATTERN = /^android\.permission\.[A-Z][A-Z0-9_]*$/u;
5073
+ var IOS_USAGE_DESCRIPTIONS = new Set([
5074
+ "camera",
5075
+ "photo-library",
5076
+ "photo-library-add"
5077
+ ]);
5072
5078
  var object2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
5073
5079
  var readJson = (path) => {
5074
5080
  const value = JSON.parse(readFileSync4(path, "utf8"));
@@ -5081,6 +5087,26 @@ var text = (value, field) => {
5081
5087
  throw new TypeError(`${field} must be a non-empty string.`);
5082
5088
  return value;
5083
5089
  };
5090
+ var androidPermissions = (value, field) => {
5091
+ if (value === undefined)
5092
+ return;
5093
+ if (!object2(value))
5094
+ throw new TypeError(`${field} must be an object.`);
5095
+ const { permissions } = value;
5096
+ if (!Array.isArray(permissions) || !permissions.every((permission) => typeof permission === "string" && ANDROID_PERMISSION_PATTERN.test(permission)))
5097
+ throw new TypeError(`${field}.permissions must contain Android permission names.`);
5098
+ return [...permissions];
5099
+ };
5100
+ var iosUsageDescriptions = (value, field) => {
5101
+ if (value === undefined)
5102
+ return;
5103
+ if (!object2(value))
5104
+ throw new TypeError(`${field} must be an object.`);
5105
+ const { usageDescriptions } = value;
5106
+ if (!Array.isArray(usageDescriptions) || !usageDescriptions.every((purpose) => typeof purpose === "string" && IOS_USAGE_DESCRIPTIONS.has(purpose)))
5107
+ throw new TypeError(`${field}.usageDescriptions contains an unsupported purpose.`);
5108
+ return [...usageDescriptions];
5109
+ };
5084
5110
  var parseProvider = (name, value) => {
5085
5111
  if (!IDENTIFIER_PATTERN.test(name))
5086
5112
  throw new TypeError("Device capability names must be identifiers.");
@@ -5094,8 +5120,34 @@ var parseProvider = (name, value) => {
5094
5120
  throw new TypeError(`${name}.module must be an official devices-capacitor subpath.`);
5095
5121
  if (!Array.isArray(value.packages) || !value.packages.every((spec) => typeof spec === "string" && CAPACITOR_PACKAGE_PATTERN.test(spec)))
5096
5122
  throw new TypeError(`${name}.packages must contain exact official Capacitor package versions.`);
5097
- return { factory, module, packages: [...value.packages] };
5123
+ let native;
5124
+ const { native: nativeMetadata } = value;
5125
+ if (nativeMetadata !== undefined) {
5126
+ if (!object2(nativeMetadata))
5127
+ throw new TypeError(`${name}.native must be an object.`);
5128
+ const { android, ios } = nativeMetadata;
5129
+ const permissions = androidPermissions(android, `${name}.native.android`);
5130
+ const usageDescriptions = iosUsageDescriptions(ios, `${name}.native.ios`);
5131
+ native = {
5132
+ ...permissions === undefined ? {} : { android: { permissions } },
5133
+ ...usageDescriptions === undefined ? {} : { ios: { usageDescriptions } }
5134
+ };
5135
+ }
5136
+ return {
5137
+ factory,
5138
+ module,
5139
+ ...native === undefined ? {} : { native },
5140
+ packages: [...value.packages]
5141
+ };
5098
5142
  };
5143
+ var absoluteDeviceNativeRequirements = (plan) => ({
5144
+ androidPermissions: [
5145
+ ...new Set(plan.capabilities.flatMap((name) => plan.providers[name]?.native?.android?.permissions ?? []))
5146
+ ].sort(),
5147
+ iosUsageDescriptions: [
5148
+ ...new Set(plan.capabilities.flatMap((name) => plan.providers[name]?.native?.ios?.usageDescriptions ?? []))
5149
+ ].sort()
5150
+ });
5099
5151
  var loadAbsoluteDeviceCapabilityProviders = (projectRoot) => {
5100
5152
  const path = join13(resolve11(projectRoot), "node_modules", CAPACITOR_ADAPTER, "package.json");
5101
5153
  const manifest = readJson(path);
@@ -5720,6 +5772,90 @@ var applyAbsoluteNativeDeepLinks = async (config, platforms = config.platforms)
5720
5772
  changed: results.filter(({ didChange }) => didChange).map(({ platform }) => platform)
5721
5773
  };
5722
5774
  };
5775
+ // src/mobile/nativeDeviceCapabilities.ts
5776
+ import { readFile as readFile15, rename as rename12, writeFile as writeFile13 } from "fs/promises";
5777
+ import { join as join16 } from "path";
5778
+ var START_MARKER2 = "<!-- absolutejs:device-capabilities:start -->";
5779
+ var END_MARKER2 = "<!-- absolutejs:device-capabilities:end -->";
5780
+ var NOT_FOUND2 = -1;
5781
+ var escapeXml2 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
5782
+ var writeChangedFile2 = async (path, source) => {
5783
+ const current = await readFile15(path, "utf8");
5784
+ if (current === source)
5785
+ return false;
5786
+ const temporary = `${path}.${crypto.randomUUID()}.tmp`;
5787
+ await writeFile13(temporary, source, { flag: "wx" });
5788
+ await rename12(temporary, path);
5789
+ return true;
5790
+ };
5791
+ var managed = (source, region, insertion) => {
5792
+ const start = source.indexOf(START_MARKER2);
5793
+ const end = source.indexOf(END_MARKER2);
5794
+ if (start === NOT_FOUND2 !== (end === NOT_FOUND2) || start !== NOT_FOUND2 && end < start)
5795
+ throw new TypeError("AbsoluteJS device-capability ownership markers are malformed.");
5796
+ if (start !== NOT_FOUND2) {
5797
+ const lineStart = source.lastIndexOf(`
5798
+ `, start) + 1;
5799
+ const nextLine = source.indexOf(`
5800
+ `, end + END_MARKER2.length);
5801
+ const lineEnd = nextLine === NOT_FOUND2 ? source.length : nextLine + 1;
5802
+ return `${source.slice(0, lineStart)}${region}${source.slice(lineEnd)}`;
5803
+ }
5804
+ if (region.length === 0)
5805
+ return source;
5806
+ if (insertion === NOT_FOUND2)
5807
+ throw new TypeError("Could not find a safe native project location for device permissions.");
5808
+ return `${source.slice(0, insertion)}${region}${source.slice(insertion)}`;
5809
+ };
5810
+ var IOS_KEYS = {
5811
+ camera: "NSCameraUsageDescription",
5812
+ "photo-library": "NSPhotoLibraryUsageDescription",
5813
+ "photo-library-add": "NSPhotoLibraryAddUsageDescription"
5814
+ };
5815
+ var iosDescription = (appName, purpose) => {
5816
+ if (purpose === "camera")
5817
+ return `${appName} uses your camera when you choose to take a photo.`;
5818
+ if (purpose === "photo-library")
5819
+ return `${appName} accesses your photo library only for photo actions you choose.`;
5820
+ return `${appName} adds to your photo library only for photo actions you choose.`;
5821
+ };
5822
+ var configureIos2 = async (config, plan) => {
5823
+ const path = join16(config.nativeProjectDirectory, "ios/App/App/Info.plist");
5824
+ const source = await readFile15(path, "utf8");
5825
+ const requirements = absoluteDeviceNativeRequirements(plan);
5826
+ const content = requirements.iosUsageDescriptions.map((purpose) => ` <key>${IOS_KEYS[purpose]}</key>
5827
+ <string>${escapeXml2(iosDescription(config.appName, purpose))}</string>`).join(`
5828
+ `);
5829
+ const region = content ? ` ${START_MARKER2}
5830
+ ${content}
5831
+ ${END_MARKER2}
5832
+ ` : "";
5833
+ return writeChangedFile2(path, managed(source, region, source.lastIndexOf("</dict>")));
5834
+ };
5835
+ var configureAndroid2 = async (config, plan) => {
5836
+ const path = join16(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
5837
+ const source = await readFile15(path, "utf8");
5838
+ const permissions = absoluteDeviceNativeRequirements(plan).androidPermissions;
5839
+ const content = permissions.map((permission) => ` <uses-permission android:name="${escapeXml2(permission)}" />`).join(`
5840
+ `);
5841
+ const region = content ? ` ${START_MARKER2}
5842
+ ${content}
5843
+ ${END_MARKER2}
5844
+ ` : "";
5845
+ const application = source.indexOf("<application");
5846
+ const insertion = application === NOT_FOUND2 ? NOT_FOUND2 : source.lastIndexOf(`
5847
+ `, application) + 1;
5848
+ return writeChangedFile2(path, managed(source, region, insertion));
5849
+ };
5850
+ var applyAbsoluteNativeDeviceCapabilities = async (projectRoot, config, platforms = config.platforms, plan = resolveAbsoluteDeviceCapabilityPlan(projectRoot)) => {
5851
+ const results = await Promise.all(platforms.map(async (platform) => ({
5852
+ didChange: platform === "ios" ? await configureIos2(config, plan) : await configureAndroid2(config, plan),
5853
+ platform
5854
+ })));
5855
+ return {
5856
+ changed: results.filter(({ didChange }) => didChange).map(({ platform }) => platform)
5857
+ };
5858
+ };
5723
5859
  // src/mobile/releasePublisher.ts
5724
5860
  import { access as access9 } from "fs/promises";
5725
5861
  import { isAbsolute as isAbsolute6, relative as relative10, resolve as resolve13, sep as sep6 } from "path";
@@ -6440,11 +6576,13 @@ export {
6440
6576
  buildAbsoluteIosRelease,
6441
6577
  buildAbsoluteAndroidRelease,
6442
6578
  assertAbsoluteDeviceCapabilityPackages,
6579
+ applyAbsoluteNativeDeviceCapabilities,
6443
6580
  applyAbsoluteNativeDeepLinks,
6444
6581
  activateAbsoluteMobilePage,
6445
6582
  acceptsAbsoluteMobilePage,
6446
6583
  absoluteRemoteProjectSyncCommands,
6447
6584
  absoluteRemoteMacSshBase,
6585
+ absoluteDeviceNativeRequirements,
6448
6586
  MOBILE_PAGE_REQUEST_HEADERS,
6449
6587
  AbsoluteMobilePageProtocolError,
6450
6588
  APPLE_ASSOCIATION_PATH,
@@ -6468,5 +6606,5 @@ export {
6468
6606
  ABSOLUTE_ANDROID_RELEASE_FORMAT
6469
6607
  };
6470
6608
 
6471
- //# debugId=09531F7676B08D9D64756E2164756E21
6609
+ //# debugId=8F3479AD17C2968F64756E2164756E21
6472
6610
  //# sourceMappingURL=index.js.map