@ankhorage/expo-runtime 2.6.0 → 2.7.0

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -2
  3. package/dist/ExpoBarcodeScannerAdapter.d.ts.map +1 -1
  4. package/dist/ExpoBarcodeScannerAdapter.js +4 -16
  5. package/dist/ExpoBarcodeScannerAdapter.js.map +1 -1
  6. package/dist/barcodeScanRuntime.d.ts +4 -1
  7. package/dist/barcodeScanRuntime.d.ts.map +1 -1
  8. package/dist/barcodeScanRuntime.js +15 -1
  9. package/dist/barcodeScanRuntime.js.map +1 -1
  10. package/dist/expoRuntimePlanningMetadata.d.ts +59 -0
  11. package/dist/expoRuntimePlanningMetadata.d.ts.map +1 -0
  12. package/dist/expoRuntimePlanningMetadata.js +133 -0
  13. package/dist/expoRuntimePlanningMetadata.js.map +1 -0
  14. package/dist/mediaPicker/documentPicker.d.ts +1 -2
  15. package/dist/mediaPicker/documentPicker.d.ts.map +1 -1
  16. package/dist/mediaPicker/documentPicker.js +1 -1
  17. package/dist/mediaPicker/documentPicker.js.map +1 -1
  18. package/dist/mediaPicker/photoLibraryPicker.d.ts +1 -2
  19. package/dist/mediaPicker/photoLibraryPicker.d.ts.map +1 -1
  20. package/dist/mediaPicker/photoLibraryPicker.js +1 -1
  21. package/dist/mediaPicker/photoLibraryPicker.js.map +1 -1
  22. package/dist/mediaPicker/readSelectedBytes.d.ts +1 -4
  23. package/dist/mediaPicker/readSelectedBytes.d.ts.map +1 -1
  24. package/dist/mediaPicker/readSelectedBytes.js +7 -1
  25. package/dist/mediaPicker/readSelectedBytes.js.map +1 -1
  26. package/dist/platform.d.ts +83 -0
  27. package/dist/platform.d.ts.map +1 -0
  28. package/dist/platform.js +81 -0
  29. package/dist/platform.js.map +1 -0
  30. package/dist/resolveExpoRuntimePlan.d.ts +3 -23
  31. package/dist/resolveExpoRuntimePlan.d.ts.map +1 -1
  32. package/dist/resolveExpoRuntimePlan.js +155 -187
  33. package/dist/resolveExpoRuntimePlan.js.map +1 -1
  34. package/package.json +45 -29
  35. package/src/ExpoBarcodeScannerAdapter.test.tsx +47 -4
  36. package/src/ExpoBarcodeScannerAdapter.tsx +10 -19
  37. package/src/barcodeScanRuntime.ts +27 -2
  38. package/src/expoRuntimePlanningMetadata.ts +190 -0
  39. package/src/generatedAppOutput.test.ts +29 -7
  40. package/src/mediaPicker/documentPicker.ts +1 -6
  41. package/src/mediaPicker/photoLibraryPicker.ts +1 -6
  42. package/src/mediaPicker/readSelectedBytes.ts +12 -3
  43. package/src/oauthBrowserRuntime.test.ts +1 -1
  44. package/src/platform.test.ts +34 -0
  45. package/src/platform.ts +88 -0
  46. package/src/resolveExpoRuntimePlan.test.ts +130 -6
  47. package/src/resolveExpoRuntimePlan.ts +214 -244
@@ -1 +1 @@
1
- {"version":3,"file":"resolveExpoRuntimePlan.js","sourceRoot":"","sources":["../src/resolveExpoRuntimePlan.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AnkhorageCapabilityName,\n ScreenCapabilityRequirement,\n ScreenPermissionRequirement,\n} from '@ankhorage/contracts';\nimport type { Permission } from '@ankhorage/permissions';\nimport { isPermission } from '@ankhorage/permissions';\nimport {\n EXPO_PERMISSION_SUPPORT,\n type ExpoPermissionMetadata,\n type PermissionSupport,\n} from '@ankhorage/permissions/expo/manifest';\n\nexport interface ExpoRuntimePlanningScreen {\n readonly requires?: {\n readonly capabilities?: readonly ScreenCapabilityRequirement[];\n readonly permissions?: readonly ScreenPermissionRequirement[];\n };\n}\n\nexport interface ExpoRuntimePlanningManifest {\n readonly screens: Readonly<Record<string, ExpoRuntimePlanningScreen>>;\n}\n\ninterface ExpoRuntimeDependency {\n readonly name: string;\n readonly version: string;\n readonly reasons: readonly string[];\n}\n\ninterface ExpoRuntimeConfigPlugin {\n readonly name: string;\n readonly options?: Readonly<Record<string, boolean | string>>;\n}\n\nexport type ExpoRuntimeProviderId = 'permissions';\nexport type ExpoRuntimeAdapterId = 'ExpoBarcodeScannerAdapter';\n\ninterface ExpoRuntimeDiagnostic {\n readonly severity: 'error' | 'warning';\n readonly requirementType: 'capability' | 'configHint' | 'package' | 'permission';\n readonly requirement: string;\n readonly message: string;\n readonly support?: PermissionSupport;\n}\n\nexport interface ExpoRuntimePlan {\n readonly permissions: readonly ScreenPermissionRequirement[];\n readonly capabilities: readonly ScreenCapabilityRequirement[];\n readonly impliedPermissions: readonly ScreenPermissionRequirement[];\n readonly dependencies: readonly ExpoRuntimeDependency[];\n readonly nativeConfig: {\n readonly androidPermissions: readonly string[];\n readonly configHints: readonly string[];\n readonly plugins: readonly ExpoRuntimeConfigPlugin[];\n };\n readonly providers: readonly ExpoRuntimeProviderId[];\n readonly runtimeAdapters: readonly ExpoRuntimeAdapterId[];\n readonly usesExpoRuntimeRegistry: boolean;\n readonly needsPermissionsProvider: boolean;\n readonly diagnostics: readonly ExpoRuntimeDiagnostic[];\n}\n\ninterface ExpoRuntimeCapabilityMetadata {\n readonly impliedPermissions?: readonly ScreenPermissionRequirement[];\n readonly requiredPackages?: readonly string[];\n readonly providers?: readonly ExpoRuntimeProviderId[];\n readonly runtimeAdapters?: readonly ExpoRuntimeAdapterId[];\n readonly androidPermissions?: readonly string[];\n readonly plugins?: readonly ExpoRuntimeConfigPlugin[];\n}\n\ninterface ExpoRuntimeHintMetadata {\n readonly androidPermissions?: readonly string[];\n readonly plugin?: ExpoRuntimeConfigPlugin;\n}\n\ninterface ResolveExpoRuntimePlanOptions {\n readonly capabilityRegistry?: Readonly<\n Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>\n >;\n readonly dependencyVersions?: Readonly<Record<string, string>>;\n readonly permissionSupport?: Readonly<Record<Permission, ExpoPermissionMetadata>>;\n}\n\nconst CAMERA_ANDROID_PERMISSION = 'android.permission.CAMERA';\nconst EXPO_RUNTIME_PACKAGE_NAME = '@ankhorage/expo-runtime';\n\nconst GENERATED_EXPO_DEPENDENCY_VERSIONS = {\n '@ankhorage/permissions': '^0.2.0',\n '@ankhorage/expo-runtime': 'latest',\n 'expo-camera': '~17.0.10',\n} as const satisfies Record<string, string>;\n\nconst EXPO_RUNTIME_PROVIDER_PACKAGES = {\n permissions: '@ankhorage/permissions',\n} as const satisfies Record<ExpoRuntimeProviderId, string>;\n\nconst EXPO_RUNTIME_CONFIG_HINTS = {\n cameraPermission: {\n androidPermissions: [CAMERA_ANDROID_PERMISSION],\n plugin: {\n name: 'expo-camera',\n options: {\n cameraPermission: 'Allow camera access.',\n },\n },\n },\n} as const satisfies Readonly<Record<string, ExpoRuntimeHintMetadata>>;\n\nconst EXPO_CAPABILITY_RUNTIME_REGISTRY = {\n barcodeScanner: {\n impliedPermissions: [{ permission: 'camera' }],\n requiredPackages: ['expo-camera'],\n providers: ['permissions'],\n runtimeAdapters: ['ExpoBarcodeScannerAdapter'],\n androidPermissions: [CAMERA_ANDROID_PERMISSION],\n plugins: [\n {\n name: 'expo-camera',\n options: {\n cameraPermission: 'Allow camera access to scan barcodes.',\n },\n },\n ],\n },\n} as const satisfies Readonly<\n Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>\n>;\n\nexport function resolveExpoRuntimePlan(\n manifest: ExpoRuntimePlanningManifest,\n options: ResolveExpoRuntimePlanOptions = {},\n): ExpoRuntimePlan {\n const permissionsByName = new Map<string, ScreenPermissionRequirement>();\n const impliedPermissionsByName = new Map<string, ScreenPermissionRequirement>();\n const capabilitiesByName = new Map<string, ScreenCapabilityRequirement>();\n\n for (const screen of Object.values(manifest.screens)) {\n screen.requires?.permissions?.forEach((requirement) => {\n permissionsByName.set(requirement.permission, requirement);\n });\n screen.requires?.capabilities?.forEach((requirement) => {\n capabilitiesByName.set(requirement.capability, requirement);\n });\n }\n\n const capabilityRegistry: Readonly<\n Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>\n > = options.capabilityRegistry ?? EXPO_CAPABILITY_RUNTIME_REGISTRY;\n\n for (const capabilityRequirement of capabilitiesByName.values()) {\n capabilityRegistry[capabilityRequirement.capability]?.impliedPermissions?.forEach(\n (permissionRequirement: ScreenPermissionRequirement) => {\n if (!permissionsByName.has(permissionRequirement.permission)) {\n permissionsByName.set(permissionRequirement.permission, permissionRequirement);\n impliedPermissionsByName.set(permissionRequirement.permission, permissionRequirement);\n }\n },\n );\n }\n\n const diagnostics: ExpoRuntimeDiagnostic[] = [];\n const dependencies = new Map<string, ExpoRuntimeDependency>();\n const pluginOptions = new Map<string, Record<string, boolean | string>>();\n const configHints = new Set<string>();\n const androidPermissions = new Set<string>();\n const providers = new Set<ExpoRuntimeProviderId>();\n const runtimeAdapters = new Set<ExpoRuntimeAdapterId>();\n const dependencyVersions: Readonly<Record<string, string>> =\n options.dependencyVersions ?? GENERATED_EXPO_DEPENDENCY_VERSIONS;\n const permissionSupport = options.permissionSupport ?? EXPO_PERMISSION_SUPPORT;\n const configHintRegistry: Readonly<Record<string, ExpoRuntimeHintMetadata>> =\n EXPO_RUNTIME_CONFIG_HINTS;\n\n const addDependency = (name: string, reason: string) => {\n const version = dependencyVersions[name];\n if (version === undefined) {\n diagnostics.push({\n severity: 'warning',\n requirementType: 'package',\n requirement: name,\n message: `No generated-app dependency version is registered for '${name}'.`,\n });\n return;\n }\n\n const existing = dependencies.get(name);\n if (existing) {\n dependencies.set(name, {\n ...existing,\n reasons: Array.from(new Set([...existing.reasons, reason])),\n });\n return;\n }\n\n dependencies.set(name, {\n name,\n version,\n reasons: [reason],\n });\n };\n\n const addProvider = (provider: ExpoRuntimeProviderId, reason: string) => {\n providers.add(provider);\n addDependency(EXPO_RUNTIME_PROVIDER_PACKAGES[provider], reason);\n };\n\n const addPlugin = (plugin: ExpoRuntimeConfigPlugin) => {\n const existingOptions = pluginOptions.get(plugin.name) ?? {};\n pluginOptions.set(plugin.name, {\n ...existingOptions,\n ...(plugin.options ?? {}),\n });\n };\n\n for (const permissionRequirement of permissionsByName.values()) {\n if (!isPermission(permissionRequirement.permission)) {\n diagnostics.push({\n severity: 'error',\n requirementType: 'permission',\n requirement: permissionRequirement.permission,\n message: `Unknown permission '${permissionRequirement.permission}' cannot be resolved for Expo runtime generation.`,\n });\n continue;\n }\n\n const supportMetadata = permissionSupport[permissionRequirement.permission];\n if (\n supportMetadata.support === 'unsupported' ||\n supportMetadata.support === 'notImplemented' ||\n supportMetadata.support === 'limited'\n ) {\n diagnostics.push({\n severity: supportMetadata.support === 'limited' ? 'warning' : 'error',\n requirementType: 'permission',\n requirement: permissionRequirement.permission,\n message: `Expo runtime support for '${permissionRequirement.permission}' is '${supportMetadata.support}'.`,\n support: supportMetadata.support,\n });\n continue;\n }\n\n if (supportMetadata.support === 'notRequired') {\n continue;\n }\n\n addProvider('permissions', `permission:${permissionRequirement.permission}`);\n supportMetadata.requiredPackages.forEach((packageName) => {\n addDependency(packageName, `permission:${permissionRequirement.permission}`);\n });\n\n supportMetadata.configHints.forEach((configHint) => {\n configHints.add(configHint);\n const configHintMetadata = configHintRegistry[configHint];\n if (!configHintMetadata) {\n diagnostics.push({\n severity: 'warning',\n requirementType: 'configHint',\n requirement: configHint,\n message: `Config hint '${configHint}' is not translated into generated Expo config yet.`,\n });\n return;\n }\n\n configHintMetadata.androidPermissions?.forEach((permissionName) => {\n androidPermissions.add(permissionName);\n });\n if (configHintMetadata.plugin) {\n addPlugin(configHintMetadata.plugin);\n }\n });\n }\n\n for (const capabilityRequirement of capabilitiesByName.values()) {\n const capabilityMetadata = capabilityRegistry[capabilityRequirement.capability];\n if (!capabilityMetadata) {\n diagnostics.push({\n severity: 'warning',\n requirementType: 'capability',\n requirement: capabilityRequirement.capability,\n message: `No Expo runtime metadata is registered for capability '${capabilityRequirement.capability}'.`,\n });\n continue;\n }\n\n capabilityMetadata.requiredPackages?.forEach((packageName) => {\n addDependency(packageName, `capability:${capabilityRequirement.capability}`);\n });\n capabilityMetadata.providers?.forEach((provider) => {\n addProvider(provider, `capability:${capabilityRequirement.capability}`);\n });\n capabilityMetadata.runtimeAdapters?.forEach((runtimeAdapter) => {\n runtimeAdapters.add(runtimeAdapter);\n });\n capabilityMetadata.androidPermissions?.forEach((permissionName) => {\n androidPermissions.add(permissionName);\n });\n capabilityMetadata.plugins?.forEach(addPlugin);\n }\n\n if (providers.size > 0 || runtimeAdapters.size > 0) {\n addDependency(EXPO_RUNTIME_PACKAGE_NAME, 'runtime:expo');\n }\n\n const plugins = Array.from(pluginOptions.entries())\n .map(([name, pluginOptions]) => ({\n name,\n options: Object.keys(pluginOptions).length > 0 ? pluginOptions : undefined,\n }))\n .sort((left, right) => left.name.localeCompare(right.name));\n\n return {\n permissions: Array.from(permissionsByName.values()).sort(comparePermissionRequirements),\n capabilities: Array.from(capabilitiesByName.values()).sort(compareCapabilityRequirements),\n impliedPermissions: Array.from(impliedPermissionsByName.values()).sort(\n comparePermissionRequirements,\n ),\n dependencies: Array.from(dependencies.values()).sort((left, right) =>\n left.name.localeCompare(right.name),\n ),\n nativeConfig: {\n androidPermissions: Array.from(androidPermissions).sort(),\n configHints: Array.from(configHints).sort(),\n plugins,\n },\n providers: Array.from(providers).sort(),\n runtimeAdapters: Array.from(runtimeAdapters).sort(),\n usesExpoRuntimeRegistry: runtimeAdapters.size > 0,\n needsPermissionsProvider: providers.has('permissions'),\n diagnostics,\n };\n}\n\nfunction compareCapabilityRequirements(\n left: ScreenCapabilityRequirement,\n right: ScreenCapabilityRequirement,\n): number {\n return left.capability.localeCompare(right.capability);\n}\n\nfunction comparePermissionRequirements(\n left: ScreenPermissionRequirement,\n right: ScreenPermissionRequirement,\n): number {\n return left.permission.localeCompare(right.permission);\n}\n"]}
1
+ {"version":3,"file":"resolveExpoRuntimePlan.js","sourceRoot":"","sources":["../src/resolveExpoRuntimePlan.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AnkhorageCapabilityName,\n ScreenCapabilityRequirement,\n ScreenPermissionRequirement,\n} from '@ankhorage/contracts';\nimport type { Permission } from '@ankhorage/permissions';\nimport { isPermission } from '@ankhorage/permissions';\nimport {\n EXPO_PERMISSION_SUPPORT,\n type ExpoPermissionMetadata,\n type PermissionSupport,\n} from '@ankhorage/permissions/expo/manifest';\n\nimport {\n EXPO_CAPABILITY_RUNTIME_REGISTRY,\n EXPO_RUNTIME_PROVIDER_PACKAGES,\n type ExpoRuntimeAdapterId,\n type ExpoRuntimeCapabilityMetadata,\n type ExpoRuntimeConfigPlugin,\n type ExpoRuntimeDiagnostic,\n type ExpoRuntimeProviderId,\n findCapabilityMetadata,\n findConfigHintMetadata,\n GENERATED_RUNTIME_DEPENDENCY_VERSIONS,\n unknownCapabilityDiagnostic,\n unknownPermissionDiagnostic,\n unsupportedPermissionDiagnostic,\n} from './expoRuntimePlanningMetadata';\n\nexport type { ExpoRuntimeAdapterId, ExpoRuntimeProviderId };\n\nexport interface ExpoRuntimePlanningScreen {\n readonly requires?: {\n readonly capabilities?: readonly ScreenCapabilityRequirement[];\n readonly permissions?: readonly ScreenPermissionRequirement[];\n };\n}\n\nexport interface ExpoRuntimePlanningManifest {\n readonly screens: Readonly<Record<string, ExpoRuntimePlanningScreen>>;\n}\n\ninterface ExpoRuntimeDependency {\n readonly name: string;\n readonly version: string;\n readonly reasons: readonly string[];\n}\n\nexport interface ExpoRuntimePlan {\n readonly permissions: readonly ScreenPermissionRequirement[];\n readonly capabilities: readonly ScreenCapabilityRequirement[];\n readonly impliedPermissions: readonly ScreenPermissionRequirement[];\n readonly dependencies: readonly ExpoRuntimeDependency[];\n readonly nativeConfig: {\n readonly androidPermissions: readonly string[];\n readonly configHints: readonly string[];\n readonly plugins: readonly ExpoRuntimeConfigPlugin[];\n };\n readonly providers: readonly ExpoRuntimeProviderId[];\n readonly runtimeAdapters: readonly ExpoRuntimeAdapterId[];\n readonly usesExpoRuntimeRegistry: boolean;\n readonly needsPermissionsProvider: boolean;\n readonly diagnostics: readonly ExpoRuntimeDiagnostic[];\n}\n\ninterface ResolveExpoRuntimePlanOptions {\n readonly capabilityRegistry?: Readonly<\n Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>\n >;\n readonly dependencyVersions?: Readonly<Record<string, string>>;\n readonly permissionSupport?: Readonly<Record<Permission, ExpoPermissionMetadata>>;\n}\n\ninterface PlanningState {\n readonly permissions: Map<string, ScreenPermissionRequirement>;\n readonly impliedPermissions: Map<string, ScreenPermissionRequirement>;\n readonly capabilities: Map<string, ScreenCapabilityRequirement>;\n readonly diagnostics: ExpoRuntimeDiagnostic[];\n readonly dependencies: Map<string, ExpoRuntimeDependency>;\n readonly pluginOptions: Map<string, Record<string, boolean | string>>;\n readonly configHints: Set<string>;\n readonly androidPermissions: Set<string>;\n readonly providers: Set<ExpoRuntimeProviderId>;\n readonly runtimeAdapters: Set<ExpoRuntimeAdapterId>;\n}\n\ninterface PlanningContext {\n readonly state: PlanningState;\n readonly capabilityRegistry: Readonly<\n Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>\n >;\n readonly dependencyVersions: Readonly<Record<string, string>>;\n readonly permissionSupport: Readonly<Record<Permission, ExpoPermissionMetadata>>;\n}\n\nconst EXPO_RUNTIME_PACKAGE_NAME = '@ankhorage/expo-runtime';\n\nexport function resolveExpoRuntimePlan(\n manifest: ExpoRuntimePlanningManifest,\n options: ResolveExpoRuntimePlanOptions = {},\n): ExpoRuntimePlan {\n const state = createPlanningState(manifest);\n const context: PlanningContext = {\n state,\n capabilityRegistry: options.capabilityRegistry ?? EXPO_CAPABILITY_RUNTIME_REGISTRY,\n dependencyVersions: options.dependencyVersions ?? GENERATED_RUNTIME_DEPENDENCY_VERSIONS,\n permissionSupport: options.permissionSupport ?? EXPO_PERMISSION_SUPPORT,\n };\n addImpliedPermissions(context);\n planPermissions(context);\n planCapabilities(context);\n if (state.providers.size > 0 || state.runtimeAdapters.size > 0) {\n addDependency(context, EXPO_RUNTIME_PACKAGE_NAME, 'runtime:expo');\n }\n return buildPlan(state);\n}\n\nfunction createPlanningState(manifest: ExpoRuntimePlanningManifest): PlanningState {\n const permissions = new Map<string, ScreenPermissionRequirement>();\n const capabilities = new Map<string, ScreenCapabilityRequirement>();\n for (const screen of Object.values(manifest.screens)) {\n for (const requirement of screen.requires?.permissions ?? []) {\n permissions.set(requirement.permission, requirement);\n }\n for (const requirement of screen.requires?.capabilities ?? []) {\n capabilities.set(requirement.capability, requirement);\n }\n }\n return {\n permissions,\n capabilities,\n impliedPermissions: new Map(),\n diagnostics: [],\n dependencies: new Map(),\n pluginOptions: new Map(),\n configHints: new Set(),\n androidPermissions: new Set(),\n providers: new Set(),\n runtimeAdapters: new Set(),\n };\n}\n\nfunction addImpliedPermissions(context: PlanningContext): void {\n const { state } = context;\n for (const capability of state.capabilities.values()) {\n const metadata = findCapabilityMetadata(context.capabilityRegistry, capability);\n for (const permission of metadata?.impliedPermissions ?? []) {\n if (!state.permissions.has(permission.permission)) {\n state.permissions.set(permission.permission, permission);\n state.impliedPermissions.set(permission.permission, permission);\n }\n }\n }\n}\n\nfunction planPermissions(context: PlanningContext): void {\n for (const requirement of context.state.permissions.values()) {\n planPermission(context, requirement);\n }\n}\n\nfunction planPermission(context: PlanningContext, requirement: ScreenPermissionRequirement): void {\n if (!isPermission(requirement.permission)) {\n context.state.diagnostics.push(unknownPermissionDiagnostic(requirement.permission));\n return;\n }\n const metadata = findPermissionSupport(context.permissionSupport, requirement.permission);\n if (isUnsupported(metadata.support)) {\n context.state.diagnostics.push(\n unsupportedPermissionDiagnostic(requirement.permission, metadata.support),\n );\n return;\n }\n if (metadata.support === 'notRequired') {\n return;\n }\n const reason = `permission:${requirement.permission}`;\n addProvider(context, 'permissions', reason);\n metadata.requiredPackages.forEach((name) => addDependency(context, name, reason));\n metadata.configHints.forEach((hint) => applyConfigHint(context.state, hint));\n}\n\nfunction planCapabilities(context: PlanningContext): void {\n for (const requirement of context.state.capabilities.values()) {\n const metadata = findCapabilityMetadata(context.capabilityRegistry, requirement);\n if (metadata === undefined) {\n context.state.diagnostics.push(unknownCapabilityDiagnostic(requirement.capability));\n continue;\n }\n const reason = `capability:${requirement.capability}`;\n metadata.requiredPackages?.forEach((name) => addDependency(context, name, reason));\n metadata.providers?.forEach((provider) => addProvider(context, provider, reason));\n metadata.runtimeAdapters?.forEach((adapter) => context.state.runtimeAdapters.add(adapter));\n metadata.androidPermissions?.forEach((permission) =>\n context.state.androidPermissions.add(permission),\n );\n metadata.plugins?.forEach((plugin) => addPlugin(context.state, plugin));\n }\n}\n\nfunction applyConfigHint(state: PlanningState, configHint: string): void {\n state.configHints.add(configHint);\n const metadata = findConfigHintMetadata(configHint);\n if (metadata === undefined) {\n state.diagnostics.push({\n severity: 'warning',\n requirementType: 'configHint',\n requirement: configHint,\n message: `Config hint '${configHint}' is not translated into generated Expo config yet.`,\n });\n return;\n }\n metadata.androidPermissions?.forEach((permission) => state.androidPermissions.add(permission));\n if (metadata.plugin !== undefined) {\n addPlugin(state, metadata.plugin);\n }\n}\n\nfunction addDependency(context: PlanningContext, name: string, reason: string): void {\n const version = findDependencyVersion(context.dependencyVersions, name);\n if (version === undefined) {\n context.state.diagnostics.push({\n severity: 'warning',\n requirementType: 'package',\n requirement: name,\n message: `No generated-app dependency version is registered for '${name}'.`,\n });\n return;\n }\n const existing = context.state.dependencies.get(name);\n context.state.dependencies.set(name, {\n name,\n version,\n reasons: existing === undefined ? [reason] : Array.from(new Set([...existing.reasons, reason])),\n });\n}\n\nfunction addProvider(\n context: PlanningContext,\n provider: ExpoRuntimeProviderId,\n reason: string,\n): void {\n context.state.providers.add(provider);\n const packageName = Object.entries(EXPO_RUNTIME_PROVIDER_PACKAGES).find(\n ([name]) => name === String(provider),\n )?.[1];\n if (packageName === undefined) {\n throw new Error(`Runtime package metadata is missing for provider '${provider}'.`);\n }\n addDependency(context, packageName, reason);\n}\n\nfunction addPlugin(state: PlanningState, plugin: ExpoRuntimeConfigPlugin): void {\n const existingOptions = state.pluginOptions.get(plugin.name) ?? {};\n state.pluginOptions.set(plugin.name, { ...existingOptions, ...(plugin.options ?? {}) });\n}\n\nfunction buildPlan(state: PlanningState): ExpoRuntimePlan {\n const plugins = Array.from(state.pluginOptions, ([name, options]) => ({\n name,\n options: Object.keys(options).length > 0 ? options : undefined,\n })).sort((left, right) => left.name.localeCompare(right.name));\n return {\n permissions: Array.from(state.permissions.values()).sort(comparePermissions),\n capabilities: Array.from(state.capabilities.values()).sort(compareCapabilities),\n impliedPermissions: Array.from(state.impliedPermissions.values()).sort(comparePermissions),\n dependencies: Array.from(state.dependencies.values()).sort((left, right) =>\n left.name.localeCompare(right.name),\n ),\n nativeConfig: {\n androidPermissions: Array.from(state.androidPermissions).sort(),\n configHints: Array.from(state.configHints).sort(),\n plugins,\n },\n providers: Array.from(state.providers).sort(),\n runtimeAdapters: Array.from(state.runtimeAdapters).sort(),\n usesExpoRuntimeRegistry: state.runtimeAdapters.size > 0,\n needsPermissionsProvider: state.providers.has('permissions'),\n diagnostics: state.diagnostics,\n };\n}\n\nfunction findPermissionSupport(\n registry: Readonly<Record<Permission, ExpoPermissionMetadata>>,\n permission: Permission,\n): ExpoPermissionMetadata {\n const metadata = Object.entries(registry).find(([name]) => name === String(permission))?.[1];\n if (metadata === undefined) {\n throw new Error(`Permission metadata is missing for '${permission}'.`);\n }\n return metadata;\n}\n\nfunction findDependencyVersion(\n versions: Readonly<Record<string, string>>,\n name: string,\n): string | undefined {\n return Object.entries(versions).find(([candidate]) => candidate === name)?.[1];\n}\n\nfunction isUnsupported(support: PermissionSupport): boolean {\n return support === 'unsupported' || support === 'notImplemented' || support === 'limited';\n}\n\nfunction compareCapabilities(\n left: ScreenCapabilityRequirement,\n right: ScreenCapabilityRequirement,\n): number {\n return left.capability.localeCompare(right.capability);\n}\n\nfunction comparePermissions(\n left: ScreenPermissionRequirement,\n right: ScreenPermissionRequirement,\n): number {\n return left.permission.localeCompare(right.permission);\n}\n"]}
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "@ankhorage/expo-runtime",
3
3
  "type": "module",
4
- "version": "2.6.0",
4
+ "version": "2.7.0",
5
5
  "description": "Declarative runtime integration for Expo apps: maps app capabilities to permissions, packages, config plugins, providers, and adapters",
6
6
  "homepage": "https://github.com/ankhorage/expo-runtime#readme",
7
7
  "bugs": {
8
8
  "url": "https://github.com/ankhorage/expo-runtime/issues"
9
9
  },
10
10
  "license": "MIT",
11
+ "engines": {
12
+ "node": "24.x"
13
+ },
11
14
  "main": "./dist/index.js",
12
15
  "sideEffects": false,
13
16
  "types": "./src/index.ts",
@@ -22,8 +25,8 @@
22
25
  "runtime"
23
26
  ],
24
27
  "dependencies": {
25
- "@ankhorage/contracts": "^7.8.0",
26
- "@ankhorage/permissions": "^0.2.1"
28
+ "@ankhorage/contracts": "^8.0.0",
29
+ "@ankhorage/permissions": "^0.2.2"
27
30
  },
28
31
  "files": [
29
32
  "dist",
@@ -48,6 +51,13 @@
48
51
  "import": "./dist/planning.js",
49
52
  "default": "./dist/planning.js"
50
53
  },
54
+ "./platform": {
55
+ "react-native": "./src/platform.ts",
56
+ "browser": "./src/platform.ts",
57
+ "types": "./src/platform.ts",
58
+ "import": "./dist/platform.js",
59
+ "default": "./dist/platform.js"
60
+ },
51
61
  "./oauth-browser": {
52
62
  "react-native": "./src/oauthBrowserTransport.ts",
53
63
  "browser": "./src/oauthBrowserTransport.ts",
@@ -92,19 +102,21 @@
92
102
  "format:check": "ankhorage-prettier --check .",
93
103
  "prepack": "bun run build",
94
104
  "test": "bun test src",
95
- "typecheck": "bun x tsc --noEmit -p tsconfig.json",
105
+ "typecheck": "bun x tsc --noEmit -p tsconfig.json && bun x tsc --noEmit -p tsconfig.scripts.json",
106
+ "validate:expo-platform": "bun scripts/validateExpoPlatform.ts",
107
+ "validate:web-barcode": "bun scripts/webBarcodeAcceptance.ts",
96
108
  "version-packages": "changeset version"
97
109
  },
98
110
  "peerDependencies": {
99
- "@ankhorage/zora": "^2.8.7",
100
- "expo": "~54.0.34",
101
- "expo-camera": "~17.0.10",
102
- "expo-constants": "~18.0.13",
103
- "expo-document-picker": "~14.0.8",
104
- "expo-file-system": "~19.0.23",
105
- "expo-image-picker": "~17.0.11",
106
- "react": "19.1.0",
107
- "react-native": "0.81.5"
111
+ "@ankhorage/zora": "^2.13.2",
112
+ "expo": "~57.0.15",
113
+ "expo-camera": "~57.0.4",
114
+ "expo-constants": "~57.0.13",
115
+ "expo-document-picker": "~57.0.1",
116
+ "expo-file-system": "~57.0.5",
117
+ "expo-image-picker": "~57.0.12",
118
+ "react": "19.2.3",
119
+ "react-native": "0.86.2"
108
120
  },
109
121
  "peerDependenciesMeta": {
110
122
  "expo-constants": {
@@ -121,22 +133,26 @@
121
133
  }
122
134
  },
123
135
  "devDependencies": {
124
- "@ankhorage/devtools": "^1.0.6",
125
- "@ankhorage/paradox": "^0.1.10",
126
- "@ankhorage/zora": "^2.8.7",
136
+ "@ankhorage/devtools": "^1.6.0",
137
+ "@ankhorage/paradox": "^0.1.21",
138
+ "@ankhorage/zora": "^2.13.2",
127
139
  "@changesets/cli": "^2.31.0",
128
- "@types/bun": "^1.3.13",
129
- "@types/node": "^25.6.0",
130
- "@types/react": "^19.2.14",
131
- "expo": "~54.0.34",
132
- "expo-camera": "~17.0.10",
133
- "expo-constants": "~18.0.13",
134
- "expo-document-picker": "~14.0.8",
135
- "expo-file-system": "~19.0.23",
136
- "expo-image-picker": "~17.0.11",
137
- "react": "19.1.0",
138
- "react-native": "0.81.5",
139
- "typescript": "^5.9.3"
140
+ "@types/bun": "^1.3.14",
141
+ "@types/node": "^24.13.3",
142
+ "@types/pngjs": "^6.0.5",
143
+ "@types/react": "^19.2.18",
144
+ "bwip-js": "^4.11.4",
145
+ "expo": "~57.0.15",
146
+ "expo-camera": "~57.0.4",
147
+ "expo-constants": "~57.0.13",
148
+ "expo-document-picker": "~57.0.1",
149
+ "expo-file-system": "~57.0.5",
150
+ "expo-image-picker": "~57.0.12",
151
+ "react": "19.2.3",
152
+ "react-native": "0.86.2",
153
+ "playwright-core": "^1.62.1",
154
+ "pngjs": "^7.0.0",
155
+ "typescript": "~6.0.3"
140
156
  },
141
- "packageManager": "bun@1.3.13"
157
+ "packageManager": "bun@1.3.14"
142
158
  }
@@ -3,12 +3,13 @@ import { describe, expect, it } from 'bun:test';
3
3
  import {
4
4
  BARCODE_SCAN_DEDUPE_WINDOW_MS,
5
5
  BARCODE_SCANNER_TYPES,
6
+ dispatchExpoBarcodeScan,
6
7
  mapPermissionStatusToCameraPermissionStatus,
7
8
  normalizeExpoBarcodeScanResult,
8
9
  shouldIgnoreBarcodeScan,
9
10
  } from './barcodeScanRuntime';
10
11
 
11
- describe('ExpoBarcodeScannerAdapter helpers', () => {
12
+ describe('Expo barcode event helpers', () => {
12
13
  it('normalizes Expo barcode scan payloads for the runtime event pipeline', () => {
13
14
  expect(
14
15
  normalizeExpoBarcodeScanResult({
@@ -29,7 +30,9 @@ describe('ExpoBarcodeScannerAdapter helpers', () => {
29
30
  }),
30
31
  ).toBeNull();
31
32
  });
33
+ });
32
34
 
35
+ describe('Expo barcode event deduplication', () => {
33
36
  it('suppresses repeated scans inside the dedupe window', () => {
34
37
  expect(
35
38
  shouldIgnoreBarcodeScan(
@@ -60,7 +63,9 @@ describe('ExpoBarcodeScannerAdapter helpers', () => {
60
63
  ),
61
64
  ).toBe(false);
62
65
  });
66
+ });
63
67
 
68
+ describe('Expo barcode adapter configuration', () => {
64
69
  it('maps permission states into the ZORA camera permission surface', () => {
65
70
  expect(mapPermissionStatusToCameraPermissionStatus('unknown', false)).toBe('unknown');
66
71
  expect(mapPermissionStatusToCameraPermissionStatus('granted', false)).toBe('granted');
@@ -68,8 +73,46 @@ describe('ExpoBarcodeScannerAdapter helpers', () => {
68
73
  expect(mapPermissionStatusToCameraPermissionStatus('blocked', true)).toBe('requesting');
69
74
  });
70
75
 
71
- it('keeps the exported scanner barcode type allowlist intact', () => {
72
- expect(BARCODE_SCANNER_TYPES).toContain('qr');
73
- expect(BARCODE_SCANNER_TYPES).toContain('ean13');
76
+ it('configures the Expo camera for the capability-supported barcode formats', () => {
77
+ expect(BARCODE_SCANNER_TYPES).toEqual([
78
+ 'aztec',
79
+ 'codabar',
80
+ 'code39',
81
+ 'code93',
82
+ 'code128',
83
+ 'datamatrix',
84
+ 'ean13',
85
+ 'ean8',
86
+ 'itf14',
87
+ 'pdf417',
88
+ 'qr',
89
+ 'upc_a',
90
+ 'upc_e',
91
+ ]);
92
+ });
93
+
94
+ it.each([
95
+ ['qr', 'https://ankhorage.dev'],
96
+ ['ean13', '4006381333931'],
97
+ ['ean8', '96385074'],
98
+ ])('normalizes and forwards an accepted %s event', async (type, data) => {
99
+ const forwarded: { value: string; type?: string }[] = [];
100
+ let acceptedRecord: { value: string; type?: string; timestamp: number } | undefined;
101
+
102
+ expect(
103
+ await dispatchExpoBarcodeScan(
104
+ { data, type },
105
+ null,
106
+ 1_000,
107
+ (result) => {
108
+ forwarded.push(result);
109
+ },
110
+ (record) => {
111
+ acceptedRecord = record;
112
+ },
113
+ ),
114
+ ).toBe(true);
115
+ expect(forwarded).toEqual([{ value: data, type }]);
116
+ expect(acceptedRecord).toEqual({ value: data, type, timestamp: 1_000 });
74
117
  });
75
118
  });
@@ -7,9 +7,8 @@ import { StyleSheet } from 'react-native';
7
7
  import {
8
8
  BARCODE_SCANNER_TYPES,
9
9
  type BarcodeScanRecord,
10
+ dispatchExpoBarcodeScan,
10
11
  mapPermissionStatusToCameraPermissionStatus,
11
- normalizeExpoBarcodeScanResult,
12
- shouldIgnoreBarcodeScan,
13
12
  } from './barcodeScanRuntime';
14
13
 
15
14
  const CAMERA_BARCODE_TYPES: BarcodeType[] = [...BARCODE_SCANNER_TYPES];
@@ -37,23 +36,15 @@ export function ExpoBarcodeScannerAdapter(props: BarcodeScannerViewProps) {
37
36
 
38
37
  const handleBarcodeScanned = React.useCallback(
39
38
  (result: BarcodeScanningResult) => {
40
- void (async () => {
41
- const normalizedResult = normalizeExpoBarcodeScanResult(result);
42
- if (normalizedResult === null) {
43
- return;
44
- }
45
-
46
- const now = Date.now();
47
- if (shouldIgnoreBarcodeScan(lastScanRef.current, normalizedResult, now)) {
48
- return;
49
- }
50
-
51
- lastScanRef.current = {
52
- ...normalizedResult,
53
- timestamp: now,
54
- };
55
- await onBarcodeScanned?.(normalizedResult);
56
- })();
39
+ void dispatchExpoBarcodeScan(
40
+ result,
41
+ lastScanRef.current,
42
+ Date.now(),
43
+ onBarcodeScanned,
44
+ (record) => {
45
+ lastScanRef.current = record;
46
+ },
47
+ );
57
48
  },
58
49
  [onBarcodeScanned],
59
50
  );
@@ -1,13 +1,15 @@
1
1
  import type { PermissionStatus } from '@ankhorage/permissions';
2
2
  import type { BarcodeScanResult, CameraPermissionStatus } from '@ankhorage/zora';
3
+ import type { BarcodeType } from 'expo-camera';
3
4
 
4
5
  export const BARCODE_SCAN_DEDUPE_WINDOW_MS = 1500;
5
6
 
6
7
  export const BARCODE_SCANNER_TYPES = [
7
8
  'aztec',
8
- 'code128',
9
+ 'codabar',
9
10
  'code39',
10
11
  'code93',
12
+ 'code128',
11
13
  'datamatrix',
12
14
  'ean13',
13
15
  'ean8',
@@ -16,7 +18,7 @@ export const BARCODE_SCANNER_TYPES = [
16
18
  'qr',
17
19
  'upc_a',
18
20
  'upc_e',
19
- ] as const;
21
+ ] as const satisfies readonly BarcodeType[];
20
22
 
21
23
  export interface BarcodeScanRecord extends BarcodeScanResult {
22
24
  readonly timestamp: number;
@@ -27,6 +29,8 @@ export interface ExpoBarcodeScanResultLike {
27
29
  readonly type?: string;
28
30
  }
29
31
 
32
+ type ExpoBarcodeScanCallback = (result: BarcodeScanResult) => Promise<void> | void;
33
+
30
34
  export function mapPermissionStatusToCameraPermissionStatus(
31
35
  status: PermissionStatus,
32
36
  isRequestingPermission: boolean,
@@ -76,3 +80,24 @@ export function shouldIgnoreBarcodeScan(
76
80
  now - previous.timestamp < BARCODE_SCAN_DEDUPE_WINDOW_MS
77
81
  );
78
82
  }
83
+
84
+ export async function dispatchExpoBarcodeScan(
85
+ result: ExpoBarcodeScanResultLike,
86
+ previous: BarcodeScanRecord | null,
87
+ now: number,
88
+ onBarcodeScanned: ExpoBarcodeScanCallback | undefined,
89
+ onAccepted: (record: BarcodeScanRecord) => void,
90
+ ): Promise<boolean> {
91
+ const normalizedResult = normalizeExpoBarcodeScanResult(result);
92
+ if (normalizedResult === null || shouldIgnoreBarcodeScan(previous, normalizedResult, now)) {
93
+ return false;
94
+ }
95
+
96
+ const record = {
97
+ ...normalizedResult,
98
+ timestamp: now,
99
+ };
100
+ onAccepted(record);
101
+ await onBarcodeScanned?.(normalizedResult);
102
+ return true;
103
+ }
@@ -0,0 +1,190 @@
1
+ import type {
2
+ AnkhorageCapabilityName,
3
+ ScreenCapabilityRequirement,
4
+ ScreenPermissionRequirement,
5
+ } from '@ankhorage/contracts';
6
+ import type { PermissionSupport } from '@ankhorage/permissions/expo/manifest';
7
+
8
+ import { EXPO_PLATFORM, type ExpoPlatformPackage } from './platform';
9
+
10
+ export interface ExpoRuntimeConfigPlugin {
11
+ readonly name: string;
12
+ readonly options?: Readonly<Record<string, boolean | string>>;
13
+ }
14
+
15
+ export type ExpoRuntimeProviderId = 'permissions';
16
+ export type ExpoRuntimeAdapterId = 'ExpoBarcodeScannerAdapter';
17
+
18
+ export interface ExpoRuntimeDiagnostic {
19
+ readonly severity: 'error' | 'warning';
20
+ readonly requirementType: 'capability' | 'configHint' | 'package' | 'permission';
21
+ readonly requirement: string;
22
+ readonly message: string;
23
+ readonly support?: PermissionSupport;
24
+ }
25
+
26
+ export interface ExpoRuntimeCapabilityMetadata {
27
+ readonly impliedPermissions?: readonly ScreenPermissionRequirement[];
28
+ readonly requiredPackages?: readonly string[];
29
+ readonly providers?: readonly ExpoRuntimeProviderId[];
30
+ readonly runtimeAdapters?: readonly ExpoRuntimeAdapterId[];
31
+ readonly androidPermissions?: readonly string[];
32
+ readonly plugins?: readonly ExpoRuntimeConfigPlugin[];
33
+ }
34
+
35
+ export interface ExpoRuntimeHintMetadata {
36
+ readonly androidPermissions?: readonly string[];
37
+ readonly plugin?: ExpoRuntimeConfigPlugin;
38
+ }
39
+
40
+ const GENERATED_ANKHORAGE_DEPENDENCY_VERSIONS = {
41
+ '@ankhorage/permissions': '^0.2.2',
42
+ '@ankhorage/expo-runtime': '^2.7.0',
43
+ } as const satisfies Record<string, string>;
44
+
45
+ const GENERATED_EXPO_DEPENDENCY_VERSIONS = Object.fromEntries(
46
+ Object.values(EXPO_PLATFORM.packages).map((dependency: ExpoPlatformPackage) => [
47
+ dependency.name,
48
+ dependency.version,
49
+ ]),
50
+ ) as Readonly<Record<string, string>>;
51
+
52
+ export const GENERATED_RUNTIME_DEPENDENCY_VERSIONS = {
53
+ ...GENERATED_ANKHORAGE_DEPENDENCY_VERSIONS,
54
+ ...GENERATED_EXPO_DEPENDENCY_VERSIONS,
55
+ } as const satisfies Readonly<Record<string, string>>;
56
+
57
+ export const EXPO_RUNTIME_PROVIDER_PACKAGES = {
58
+ permissions: '@ankhorage/permissions',
59
+ } as const satisfies Record<ExpoRuntimeProviderId, string>;
60
+
61
+ const EXPO_RUNTIME_CONFIG_HINTS = {
62
+ cameraPermission: {
63
+ plugin: {
64
+ name: EXPO_PLATFORM.packages.camera.name,
65
+ options: {
66
+ barcodeScannerEnabled: false,
67
+ cameraPermission: 'Allow camera access.',
68
+ microphonePermission: false,
69
+ recordAudioAndroid: false,
70
+ },
71
+ },
72
+ },
73
+ microphonePermission: {
74
+ plugin: {
75
+ name: EXPO_PLATFORM.packages.audio.name,
76
+ options: {
77
+ enableBackgroundPlayback: false,
78
+ enableBackgroundRecording: false,
79
+ microphonePermission: 'Allow microphone access.',
80
+ },
81
+ },
82
+ },
83
+ recordAudioAndroid: {
84
+ plugin: {
85
+ name: EXPO_PLATFORM.packages.audio.name,
86
+ options: {
87
+ enableBackgroundPlayback: false,
88
+ enableBackgroundRecording: false,
89
+ recordAudioAndroid: true,
90
+ },
91
+ },
92
+ },
93
+ mediaLibraryPermission: {
94
+ plugin: {
95
+ name: EXPO_PLATFORM.packages.mediaLibrary.name,
96
+ options: {
97
+ photosPermission: 'Allow photo library access.',
98
+ savePhotosPermission: 'Allow saving to the photo library.',
99
+ },
100
+ },
101
+ },
102
+ locationWhenInUsePermission: {
103
+ plugin: {
104
+ name: EXPO_PLATFORM.packages.location.name,
105
+ options: {
106
+ locationWhenInUsePermission: 'Allow location access while using the app.',
107
+ },
108
+ },
109
+ },
110
+ locationAlwaysAndWhenInUsePermission: {
111
+ plugin: {
112
+ name: EXPO_PLATFORM.packages.location.name,
113
+ options: {
114
+ locationAlwaysAndWhenInUsePermission: 'Allow location access.',
115
+ isAndroidBackgroundLocationEnabled: true,
116
+ isAndroidForegroundServiceEnabled: true,
117
+ isIosBackgroundLocationEnabled: true,
118
+ },
119
+ },
120
+ },
121
+ notificationsPermission: {
122
+ plugin: {
123
+ name: EXPO_PLATFORM.packages.notifications.name,
124
+ },
125
+ },
126
+ } as const satisfies Readonly<Record<string, ExpoRuntimeHintMetadata>>;
127
+
128
+ export const EXPO_CAPABILITY_RUNTIME_REGISTRY = {
129
+ barcodeScanner: {
130
+ impliedPermissions: [{ permission: 'camera' }],
131
+ requiredPackages: [EXPO_PLATFORM.packages.camera.name],
132
+ providers: ['permissions'],
133
+ runtimeAdapters: ['ExpoBarcodeScannerAdapter'],
134
+ plugins: [
135
+ {
136
+ name: EXPO_PLATFORM.packages.camera.name,
137
+ options: {
138
+ cameraPermission: 'Allow camera access to scan barcodes.',
139
+ barcodeScannerEnabled: true,
140
+ microphonePermission: false,
141
+ recordAudioAndroid: false,
142
+ },
143
+ },
144
+ ],
145
+ },
146
+ } as const satisfies Readonly<
147
+ Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>
148
+ >;
149
+
150
+ export function findCapabilityMetadata(
151
+ registry: Readonly<Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>>,
152
+ requirement: ScreenCapabilityRequirement,
153
+ ): ExpoRuntimeCapabilityMetadata | undefined {
154
+ return Object.entries(registry).find(([name]) => name === requirement.capability)?.[1];
155
+ }
156
+
157
+ export function findConfigHintMetadata(configHint: string): ExpoRuntimeHintMetadata | undefined {
158
+ return Object.entries(EXPO_RUNTIME_CONFIG_HINTS).find(([name]) => name === configHint)?.[1];
159
+ }
160
+
161
+ export function unknownPermissionDiagnostic(permission: string): ExpoRuntimeDiagnostic {
162
+ return {
163
+ severity: 'error',
164
+ requirementType: 'permission',
165
+ requirement: permission,
166
+ message: `Unknown permission '${permission}' cannot be resolved for Expo runtime generation.`,
167
+ };
168
+ }
169
+
170
+ export function unsupportedPermissionDiagnostic(
171
+ permission: string,
172
+ support: PermissionSupport,
173
+ ): ExpoRuntimeDiagnostic {
174
+ return {
175
+ severity: support === 'limited' ? 'warning' : 'error',
176
+ requirementType: 'permission',
177
+ requirement: permission,
178
+ message: `Expo runtime support for '${permission}' is '${support}'.`,
179
+ support,
180
+ };
181
+ }
182
+
183
+ export function unknownCapabilityDiagnostic(capability: string): ExpoRuntimeDiagnostic {
184
+ return {
185
+ severity: 'warning',
186
+ requirementType: 'capability',
187
+ requirement: capability,
188
+ message: `No Expo runtime metadata is registered for capability '${capability}'.`,
189
+ };
190
+ }