@expo/cli 55.0.30 → 55.0.32
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/build/bin/cli +1 -1
- package/build/src/api/rest/client.js +27 -12
- package/build/src/api/rest/client.js.map +1 -1
- package/build/src/api/user/UserSettings.js +4 -2
- package/build/src/api/user/UserSettings.js.map +1 -1
- package/build/src/events/index.js +1 -1
- package/build/src/export/embed/exportEmbedAsync.js +3 -3
- package/build/src/export/embed/exportEmbedAsync.js.map +1 -1
- package/build/src/export/embed/exportServer.js +1 -1
- package/build/src/export/embed/exportServer.js.map +1 -1
- package/build/src/export/exportApp.js +1 -1
- package/build/src/export/exportApp.js.map +1 -1
- package/build/src/export/publicFolder.js +19 -1
- package/build/src/export/publicFolder.js.map +1 -1
- package/build/src/prebuild/resolveTemplate.js +10 -5
- package/build/src/prebuild/resolveTemplate.js.map +1 -1
- package/build/src/run/android/resolveLaunchProps.js +4 -1
- package/build/src/run/android/resolveLaunchProps.js.map +1 -1
- package/build/src/start/platforms/android/adb.js +16 -15
- package/build/src/start/platforms/android/adb.js.map +1 -1
- package/build/src/start/server/DevToolsPlugin.js +26 -1
- package/build/src/start/server/DevToolsPlugin.js.map +1 -1
- package/build/src/start/server/DevToolsPluginCliExtensionExecutor.js +57 -22
- package/build/src/start/server/DevToolsPluginCliExtensionExecutor.js.map +1 -1
- package/build/src/start/server/DevToolsPluginCliExtensionResults.js +29 -0
- package/build/src/start/server/DevToolsPluginCliExtensionResults.js.map +1 -1
- package/build/src/start/server/MCPDevToolsPluginCLIExtensions.js +15 -5
- package/build/src/start/server/MCPDevToolsPluginCLIExtensions.js.map +1 -1
- package/build/src/start/server/createMCPDevToolsExtensionSchema.js +13 -1
- package/build/src/start/server/createMCPDevToolsExtensionSchema.js.map +1 -1
- package/build/src/start/server/getStaticRenderFunctions.js +2 -1
- package/build/src/start/server/getStaticRenderFunctions.js.map +1 -1
- package/build/src/start/server/metro/createServerComponentsMiddleware.js +5 -12
- package/build/src/start/server/metro/createServerComponentsMiddleware.js.map +1 -1
- package/build/src/start/server/metro/debugging/createDebugMiddleware.js +6 -5
- package/build/src/start/server/metro/debugging/createDebugMiddleware.js.map +1 -1
- package/build/src/start/server/metro/debugging/messageHandlers/NetworkResponse.js +17 -1
- package/build/src/start/server/metro/debugging/messageHandlers/NetworkResponse.js.map +1 -1
- package/build/src/start/server/metro/dev-server/createMessageSocket.js +13 -2
- package/build/src/start/server/metro/dev-server/createMessageSocket.js.map +1 -1
- package/build/src/start/server/metro/dev-server/createMetroMiddleware.js +9 -2
- package/build/src/start/server/metro/dev-server/createMetroMiddleware.js.map +1 -1
- package/build/src/start/server/metro/instantiateMetro.js +8 -5
- package/build/src/start/server/metro/instantiateMetro.js.map +1 -1
- package/build/src/start/server/metro/metroErrorInterface.js +5 -2
- package/build/src/start/server/metro/metroErrorInterface.js.map +1 -1
- package/build/src/start/server/metro/router.js +10 -1
- package/build/src/start/server/metro/router.js.map +1 -1
- package/build/src/start/server/middleware/InterstitialPageMiddleware.js +7 -4
- package/build/src/start/server/middleware/InterstitialPageMiddleware.js.map +1 -1
- package/build/src/start/server/middleware/ServeStaticMiddleware.js +2 -9
- package/build/src/start/server/middleware/ServeStaticMiddleware.js.map +1 -1
- package/build/src/start/server/middleware/inspector/createJsInspectorMiddleware.js +14 -24
- package/build/src/start/server/middleware/inspector/createJsInspectorMiddleware.js.map +1 -1
- package/build/src/start/server/webTemplate.js +3 -5
- package/build/src/start/server/webTemplate.js.map +1 -1
- package/build/src/utils/codesigning.js +6 -0
- package/build/src/utils/codesigning.js.map +1 -1
- package/build/src/utils/net.js +13 -0
- package/build/src/utils/net.js.map +1 -1
- package/build/src/utils/tar.js +2 -2
- package/build/src/utils/tar.js.map +1 -1
- package/build/src/utils/telemetry/clients/FetchClient.js +1 -1
- package/build/src/utils/telemetry/utils/context.js +1 -1
- package/build/src/utils/url.js +0 -12
- package/build/src/utils/url.js.map +1 -1
- package/package.json +9 -9
- package/static/loading-page/index.html +10 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/export/exportApp.ts"],"sourcesContent":["import { getConfig } from '@expo/config';\nimport type { Platform } from '@expo/config';\nimport { resolveRelativeEntryPoint } from '@expo/config/paths';\nimport { SerialAsset } from '@expo/metro-config/build/serializer/serializerAssets';\nimport assert from 'assert';\nimport chalk from 'chalk';\nimport fs from 'fs';\nimport path from 'path';\n\nimport { type PlatformMetadata, createMetadataJson } from './createMetadataJson';\nimport { exportAssetsAsync } from './exportAssets';\nimport {\n addDomBundleToMetadataAsync,\n exportDomComponentAsync,\n transformNativeBundleForMd5Filename,\n transformDomEntryForMd5Filename,\n} from './exportDomComponents';\nimport { assertEngineMismatchAsync, isEnableHermesManaged } from './exportHermes';\nimport { exportApiRoutesStandaloneAsync, exportFromServerAsync } from './exportStaticAsync';\nimport { getVirtualFaviconAssetsAsync } from './favicon';\nimport { getPublicExpoManifestAsync } from './getPublicExpoManifest';\nimport { copyPublicFolderAsync } from './publicFolder';\nimport { Options } from './resolveOptions';\nimport {\n ExportAssetMap,\n BundleOutput,\n getFilesFromSerialAssets,\n persistMetroFilesAsync,\n BundleAssetWithFileHashes,\n} from './saveAssets';\nimport { createAssetMap } from './writeContents';\nimport * as Log from '../log';\nimport { WebSupportProjectPrerequisite } from '../start/doctor/web/WebSupportProjectPrerequisite';\nimport { DevServerManager } from '../start/server/DevServerManager';\nimport { MetroBundlerDevServer } from '../start/server/metro/MetroBundlerDevServer';\nimport { getRouterDirectoryModuleIdWithManifest } from '../start/server/metro/router';\nimport { serializeHtmlWithAssets } from '../start/server/metro/serializeHtml';\nimport { getBaseUrlFromExpoConfig } from '../start/server/middleware/metroOptions';\nimport { createTemplateHtmlFromExpoConfigAsync } from '../start/server/webTemplate';\nimport { env } from '../utils/env';\nimport { CommandError } from '../utils/errors';\nimport { setNodeEnv, loadEnvFiles } from '../utils/nodeEnv';\n\nexport async function exportAppAsync(\n projectRoot: string,\n {\n platforms,\n outputDir,\n clear,\n dev,\n dumpAssetmap,\n sourceMaps,\n inlineSourceMaps,\n minify,\n bytecode,\n maxWorkers,\n skipSSG,\n hostedNative,\n }: Pick<\n Options,\n | 'dumpAssetmap'\n | 'sourceMaps'\n | 'inlineSourceMaps'\n | 'dev'\n | 'clear'\n | 'outputDir'\n | 'platforms'\n | 'minify'\n | 'bytecode'\n | 'maxWorkers'\n | 'skipSSG'\n | 'hostedNative'\n >\n): Promise<void> {\n // Force the environment during export and do not allow overriding it.\n const environment = dev ? 'development' : 'production';\n process.env.NODE_ENV = environment;\n setNodeEnv(environment);\n loadEnvFiles(projectRoot);\n\n const projectConfig = getConfig(projectRoot);\n const exp = await getPublicExpoManifestAsync(projectRoot, {\n // Web doesn't require validation.\n skipValidation: platforms.length === 1 && platforms[0] === 'web',\n });\n\n if (platforms.includes('web')) {\n await new WebSupportProjectPrerequisite(projectRoot).assertAsync();\n }\n\n const useServerRendering = ['static', 'server'].includes(exp.web?.output ?? '');\n\n if (skipSSG && exp.web?.output !== 'server') {\n throw new CommandError('--no-ssg can only be used with `web.output: server`');\n }\n\n const baseUrl = getBaseUrlFromExpoConfig(exp);\n\n if (!bytecode && (platforms.includes('ios') || platforms.includes('android'))) {\n Log.warn(\n `Bytecode makes the app startup faster, disabling bytecode is highly discouraged and should only be used for debugging purposes.`\n );\n }\n\n // Print out logs\n if (baseUrl) {\n Log.log();\n Log.log(chalk.gray`Using (experimental) base path: ${baseUrl}`);\n // Warn if not using an absolute path.\n if (!baseUrl.startsWith('/')) {\n Log.log(\n chalk.yellow` Base path does not start with a slash. Requests will not be absolute.`\n );\n }\n }\n\n const mode = dev ? 'development' : 'production';\n const publicPath = path.resolve(projectRoot, env.EXPO_PUBLIC_FOLDER);\n const outputPath = path.resolve(projectRoot, outputDir);\n\n // Write the JS bundles to disk, and get the bundle file names (this could change with async chunk loading support).\n\n const files: ExportAssetMap = new Map();\n\n const devServerManager = await DevServerManager.startMetroAsync(projectRoot, {\n minify,\n mode,\n port: 8081,\n isExporting: true,\n location: {},\n resetDevServer: clear,\n maxWorkers,\n });\n\n const devServer = devServerManager.getDefaultDevServer();\n assert(devServer instanceof MetroBundlerDevServer);\n\n const bundles: Partial<Record<Platform, BundleOutput>> = {};\n const domComponentAssetsMetadata: Partial<Record<Platform, PlatformMetadata['assets']>> = {};\n\n const spaPlatforms =\n // TODO: Support server and static rendering for server component exports.\n useServerRendering && !devServer.isReactServerComponentsEnabled\n ? platforms.filter((platform) => platform !== 'web')\n : platforms;\n\n try {\n if (devServer.isReactServerComponentsEnabled) {\n // In RSC mode, we only need these to be in the client dir.\n // TODO: Merge back with other copy after we add SSR.\n try {\n await copyPublicFolderAsync(publicPath, path.join(outputPath, 'client'));\n } catch (error) {\n Log.error('Failed to copy public directory to dist directory');\n throw error;\n }\n } else {\n // NOTE(kitten): The public folder is currently always copied, regardless of targetDomain\n // split. Hence, there's another separate `copyPublicFolderAsync` call below for `web`\n await copyPublicFolderAsync(publicPath, outputPath);\n }\n\n let templateHtml: string | undefined;\n // Can be empty during web-only SSG.\n if (spaPlatforms.length) {\n await Promise.all(\n spaPlatforms.map(async (platform) => {\n // Assert early so the user doesn't have to wait until bundling is complete to find out that\n // Hermes won't be available.\n const isHermes = isEnableHermesManaged(exp, platform);\n if (isHermes) {\n await assertEngineMismatchAsync(projectRoot, exp, platform);\n }\n\n let bundle: {\n artifacts: SerialAsset[];\n assets: readonly BundleAssetWithFileHashes[];\n files?: ExportAssetMap;\n };\n\n try {\n // Run metro bundler and create the JS bundles/source maps.\n bundle = await devServer.nativeExportBundleAsync(\n exp,\n {\n platform,\n splitChunks:\n !env.EXPO_NO_BUNDLE_SPLITTING &&\n ((devServer.isReactServerComponentsEnabled && !bytecode) || platform === 'web'),\n mainModuleName: resolveRelativeEntryPoint(projectRoot, {\n platform,\n pkg: projectConfig.pkg,\n }),\n mode: dev ? 'development' : 'production',\n engine: isHermes ? 'hermes' : undefined,\n serializerIncludeMaps: sourceMaps || inlineSourceMaps,\n inlineSourceMap: inlineSourceMaps,\n bytecode: bytecode && isHermes,\n reactCompiler: !!exp.experiments?.reactCompiler,\n hosted: hostedNative,\n },\n files\n );\n } catch (error) {\n Log.log('');\n if (error instanceof Error) {\n Log.exception(error);\n } else {\n Log.error('Failed to bundle the app');\n Log.log(error as any);\n }\n process.exit(1);\n }\n\n bundles[platform] = bundle;\n\n getFilesFromSerialAssets(bundle.artifacts, {\n includeSourceMaps: sourceMaps,\n files,\n isServerHosted: devServer.isReactServerComponentsEnabled || hostedNative,\n });\n\n const expoDomComponentReferences = [\n ...new Set(\n bundle.artifacts\n .map((artifact) =>\n Array.isArray(artifact.metadata.expoDomComponentReferences)\n ? artifact.metadata.expoDomComponentReferences\n : []\n )\n .flat()\n ),\n ];\n await Promise.all(\n // TODO: Make a version of this which uses `this.metro.getBundler().buildGraphForEntries([])` to bundle all the DOM components at once.\n expoDomComponentReferences.map(async (filePath) => {\n const { bundle: platformDomComponentsBundle, htmlOutputName } =\n await exportDomComponentAsync({\n filePath,\n projectRoot,\n dev,\n devServer,\n isHermes,\n includeSourceMaps: sourceMaps,\n exp,\n files,\n useMd5Filename: true,\n });\n\n // Merge the assets from the DOM component into the output assets, deduplicating by hash.\n const existingHashes = new Set(bundle.assets.map((a) => a.hash));\n (bundle.assets as (typeof bundle.assets)[0][]).push(\n ...platformDomComponentsBundle.assets.filter((a) => !existingHashes.has(a.hash))\n );\n\n transformNativeBundleForMd5Filename({\n domComponentReference: filePath,\n nativeBundle: bundle,\n files,\n htmlOutputName,\n });\n domComponentAssetsMetadata[platform] = [\n ...(domComponentAssetsMetadata[platform] || []),\n ...(await addDomBundleToMetadataAsync(platformDomComponentsBundle)),\n ...transformDomEntryForMd5Filename({\n files,\n htmlOutputName,\n }),\n ];\n })\n );\n\n if (platform === 'web') {\n // TODO: Unify with exportStaticAsync\n // TODO: Maybe move to the serializer.\n let html = await serializeHtmlWithAssets({\n isExporting: true,\n resources: bundle.artifacts,\n template: await createTemplateHtmlFromExpoConfigAsync(projectRoot, {\n scripts: [],\n cssLinks: [],\n exp: projectConfig.exp,\n }),\n baseUrl,\n });\n\n // Add the favicon assets to the HTML.\n const modifyHtml = await getVirtualFaviconAssetsAsync(projectRoot, {\n outputDir,\n baseUrl,\n files,\n exp: projectConfig.exp,\n });\n if (modifyHtml) {\n html = modifyHtml(html);\n }\n\n // HACK: This is used for adding SSR shims in React Server Components.\n templateHtml = html;\n\n // Generate SPA-styled HTML file.\n // If web exists, then write the template HTML file.\n files.set('index.html', {\n contents: html,\n targetDomain: devServer.isReactServerComponentsEnabled ? 'server' : 'client',\n });\n }\n })\n );\n\n if (devServer.isReactServerComponentsEnabled) {\n const isWeb = platforms.includes('web');\n\n await exportApiRoutesStandaloneAsync(devServer, {\n files,\n platform: 'web',\n apiRoutesOnly: !isWeb,\n templateHtml,\n });\n }\n\n // TODO: Use same asset system across platforms again.\n const { assets, embeddedHashSet } = await exportAssetsAsync(projectRoot, {\n files,\n exp,\n outputDir: outputPath,\n bundles,\n baseUrl,\n hostedNative,\n });\n\n if (dumpAssetmap) {\n Log.log('Creating asset map');\n files.set('assetmap.json', { contents: JSON.stringify(createAssetMap({ assets })) });\n }\n\n const targetDomain = devServer.isReactServerComponentsEnabled ? 'client/' : '';\n const fileNames = Object.fromEntries(\n Object.entries(bundles).map(([platform, bundle]) => [\n platform,\n bundle.artifacts\n .filter((asset) => asset.type === 'js')\n .map((asset) => targetDomain + asset.filename),\n ])\n );\n\n // Generate a `metadata.json` for EAS Update.\n const contents = createMetadataJson({\n bundles,\n fileNames,\n embeddedHashSet,\n domComponentAssetsMetadata,\n });\n files.set('metadata.json', { contents: JSON.stringify(contents) });\n }\n\n // Additional web-only steps...\n\n if (platforms.includes('web') && useServerRendering) {\n const exportServer = exp.web?.output === 'server';\n\n if (exportServer) {\n // TODO: Remove when this is abstracted into the files map\n await copyPublicFolderAsync(publicPath, path.resolve(outputPath, 'client'));\n }\n\n if (skipSSG) {\n Log.log('Skipping static site generation');\n await exportApiRoutesStandaloneAsync(devServer, {\n files,\n platform: 'web',\n apiRoutesOnly: true,\n });\n\n // Output a placeholder index.html if one doesn't exist in the public directory.\n // This ensures native + API routes have some content at the root URL.\n const placeholderIndex = path.resolve(outputPath, 'client/index.html');\n if (!fs.existsSync(placeholderIndex)) {\n files.set('index.html', {\n contents: `<html><body></body></html>`,\n targetDomain: 'client',\n });\n }\n } else if (\n // TODO: Support static export with RSC.\n !devServer.isReactServerComponentsEnabled\n ) {\n await exportFromServerAsync(projectRoot, devServer, {\n mode,\n files,\n clear: !!clear,\n outputDir: outputPath,\n minify,\n baseUrl,\n includeSourceMaps: sourceMaps,\n routerRoot: getRouterDirectoryModuleIdWithManifest(projectRoot, exp),\n reactCompiler: !!exp.experiments?.reactCompiler,\n exportServer,\n maxWorkers,\n isExporting: true,\n exp: projectConfig.exp,\n });\n }\n }\n } finally {\n await devServerManager.stopAsync();\n }\n\n // Write all files at the end for unified logging.\n await persistMetroFilesAsync(files, outputPath);\n}\n"],"names":["exportAppAsync","projectRoot","platforms","outputDir","clear","dev","dumpAssetmap","sourceMaps","inlineSourceMaps","minify","bytecode","maxWorkers","skipSSG","hostedNative","exp","environment","process","env","NODE_ENV","setNodeEnv","loadEnvFiles","projectConfig","getConfig","getPublicExpoManifestAsync","skipValidation","length","includes","WebSupportProjectPrerequisite","assertAsync","useServerRendering","web","output","CommandError","baseUrl","getBaseUrlFromExpoConfig","Log","warn","log","chalk","gray","startsWith","yellow","mode","publicPath","path","resolve","EXPO_PUBLIC_FOLDER","outputPath","files","Map","devServerManager","DevServerManager","startMetroAsync","port","isExporting","location","resetDevServer","devServer","getDefaultDevServer","assert","MetroBundlerDevServer","bundles","domComponentAssetsMetadata","spaPlatforms","isReactServerComponentsEnabled","filter","platform","copyPublicFolderAsync","join","error","templateHtml","Promise","all","map","isHermes","isEnableHermesManaged","assertEngineMismatchAsync","bundle","nativeExportBundleAsync","splitChunks","EXPO_NO_BUNDLE_SPLITTING","mainModuleName","resolveRelativeEntryPoint","pkg","engine","undefined","serializerIncludeMaps","inlineSourceMap","reactCompiler","experiments","hosted","Error","exception","exit","getFilesFromSerialAssets","artifacts","includeSourceMaps","isServerHosted","expoDomComponentReferences","Set","artifact","Array","isArray","metadata","flat","filePath","platformDomComponentsBundle","htmlOutputName","exportDomComponentAsync","useMd5Filename","existingHashes","assets","a","hash","push","has","transformNativeBundleForMd5Filename","domComponentReference","nativeBundle","addDomBundleToMetadataAsync","transformDomEntryForMd5Filename","html","serializeHtmlWithAssets","resources","template","createTemplateHtmlFromExpoConfigAsync","scripts","cssLinks","modifyHtml","getVirtualFaviconAssetsAsync","set","contents","targetDomain","isWeb","exportApiRoutesStandaloneAsync","apiRoutesOnly","embeddedHashSet","exportAssetsAsync","JSON","stringify","createAssetMap","fileNames","Object","fromEntries","entries","asset","type","filename","createMetadataJson","exportServer","placeholderIndex","fs","existsSync","exportFromServerAsync","routerRoot","getRouterDirectoryModuleIdWithManifest","stopAsync","persistMetroFilesAsync"],"mappings":";;;;+BA2CsBA;;;eAAAA;;;;yBA3CI;;;;;;;yBAEgB;;;;;;;gEAEvB;;;;;;;gEACD;;;;;;;gEACH;;;;;;;gEACE;;;;;;oCAEyC;8BACxB;qCAM3B;8BAC0D;mCACK;yBACzB;uCACF;8BACL;4BAQ/B;+BACwB;6DACV;+CACyB;kCACb;uCACK;wBACiB;+BACf;8BACC;6BACa;qBAClC;wBACS;yBACY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAElC,eAAeA,eACpBC,WAAmB,EACnB,EACEC,SAAS,EACTC,SAAS,EACTC,KAAK,EACLC,GAAG,EACHC,YAAY,EACZC,UAAU,EACVC,gBAAgB,EAChBC,MAAM,EACNC,QAAQ,EACRC,UAAU,EACVC,OAAO,EACPC,YAAY,EAeb;QAkBwDC,UAE1CA;IAlBf,sEAAsE;IACtE,MAAMC,cAAcV,MAAM,gBAAgB;IAC1CW,QAAQC,GAAG,CAACC,QAAQ,GAAGH;IACvBI,IAAAA,mBAAU,EAACJ;IACXK,IAAAA,qBAAY,EAACnB;IAEb,MAAMoB,gBAAgBC,IAAAA,mBAAS,EAACrB;IAChC,MAAMa,MAAM,MAAMS,IAAAA,iDAA0B,EAACtB,aAAa;QACxD,kCAAkC;QAClCuB,gBAAgBtB,UAAUuB,MAAM,KAAK,KAAKvB,SAAS,CAAC,EAAE,KAAK;IAC7D;IAEA,IAAIA,UAAUwB,QAAQ,CAAC,QAAQ;QAC7B,MAAM,IAAIC,4DAA6B,CAAC1B,aAAa2B,WAAW;IAClE;IAEA,MAAMC,qBAAqB;QAAC;QAAU;KAAS,CAACH,QAAQ,CAACZ,EAAAA,WAAAA,IAAIgB,GAAG,qBAAPhB,SAASiB,MAAM,KAAI;IAE5E,IAAInB,WAAWE,EAAAA,YAAAA,IAAIgB,GAAG,qBAAPhB,UAASiB,MAAM,MAAK,UAAU;QAC3C,MAAM,IAAIC,oBAAY,CAAC;IACzB;IAEA,MAAMC,UAAUC,IAAAA,sCAAwB,EAACpB;IAEzC,IAAI,CAACJ,YAAaR,CAAAA,UAAUwB,QAAQ,CAAC,UAAUxB,UAAUwB,QAAQ,CAAC,UAAS,GAAI;QAC7ES,KAAIC,IAAI,CACN,CAAC,+HAA+H,CAAC;IAErI;IAEA,iBAAiB;IACjB,IAAIH,SAAS;QACXE,KAAIE,GAAG;QACPF,KAAIE,GAAG,CAACC,gBAAK,CAACC,IAAI,CAAC,gCAAgC,EAAEN,QAAQ,CAAC;QAC9D,sCAAsC;QACtC,IAAI,CAACA,QAAQO,UAAU,CAAC,MAAM;YAC5BL,KAAIE,GAAG,CACLC,gBAAK,CAACG,MAAM,CAAC,uEAAuE,CAAC;QAEzF;IACF;IAEA,MAAMC,OAAOrC,MAAM,gBAAgB;IACnC,MAAMsC,aAAaC,eAAI,CAACC,OAAO,CAAC5C,aAAagB,QAAG,CAAC6B,kBAAkB;IACnE,MAAMC,aAAaH,eAAI,CAACC,OAAO,CAAC5C,aAAaE;IAE7C,oHAAoH;IAEpH,MAAM6C,QAAwB,IAAIC;IAElC,MAAMC,mBAAmB,MAAMC,kCAAgB,CAACC,eAAe,CAACnD,aAAa;QAC3EQ;QACAiC;QACAW,MAAM;QACNC,aAAa;QACbC,UAAU,CAAC;QACXC,gBAAgBpD;QAChBO;IACF;IAEA,MAAM8C,YAAYP,iBAAiBQ,mBAAmB;IACtDC,IAAAA,iBAAM,EAACF,qBAAqBG,4CAAqB;IAEjD,MAAMC,UAAmD,CAAC;IAC1D,MAAMC,6BAAoF,CAAC;IAE3F,MAAMC,eACJ,0EAA0E;IAC1ElC,sBAAsB,CAAC4B,UAAUO,8BAA8B,GAC3D9D,UAAU+D,MAAM,CAAC,CAACC,WAAaA,aAAa,SAC5ChE;IAEN,IAAI;QACF,IAAIuD,UAAUO,8BAA8B,EAAE;YAC5C,2DAA2D;YAC3D,qDAAqD;YACrD,IAAI;gBACF,MAAMG,IAAAA,mCAAqB,EAACxB,YAAYC,eAAI,CAACwB,IAAI,CAACrB,YAAY;YAChE,EAAE,OAAOsB,OAAO;gBACdlC,KAAIkC,KAAK,CAAC;gBACV,MAAMA;YACR;QACF,OAAO;YACL,yFAAyF;YACzF,sFAAsF;YACtF,MAAMF,IAAAA,mCAAqB,EAACxB,YAAYI;QAC1C;QAEA,IAAIuB;QACJ,oCAAoC;QACpC,IAAIP,aAAatC,MAAM,EAAE;YACvB,MAAM8C,QAAQC,GAAG,CACfT,aAAaU,GAAG,CAAC,OAAOP;gBACtB,4FAA4F;gBAC5F,6BAA6B;gBAC7B,MAAMQ,WAAWC,IAAAA,mCAAqB,EAAC7D,KAAKoD;gBAC5C,IAAIQ,UAAU;oBACZ,MAAME,IAAAA,uCAAyB,EAAC3E,aAAaa,KAAKoD;gBACpD;gBAEA,IAAIW;gBAMJ,IAAI;wBAkBmB/D;oBAjBrB,2DAA2D;oBAC3D+D,SAAS,MAAMpB,UAAUqB,uBAAuB,CAC9ChE,KACA;wBACEoD;wBACAa,aACE,CAAC9D,QAAG,CAAC+D,wBAAwB,IAC5B,CAAA,AAACvB,UAAUO,8BAA8B,IAAI,CAACtD,YAAawD,aAAa,KAAI;wBAC/Ee,gBAAgBC,IAAAA,kCAAyB,EAACjF,aAAa;4BACrDiE;4BACAiB,KAAK9D,cAAc8D,GAAG;wBACxB;wBACAzC,MAAMrC,MAAM,gBAAgB;wBAC5B+E,QAAQV,WAAW,WAAWW;wBAC9BC,uBAAuB/E,cAAcC;wBACrC+E,iBAAiB/E;wBACjBE,UAAUA,YAAYgE;wBACtBc,eAAe,CAAC,GAAC1E,mBAAAA,IAAI2E,WAAW,qBAAf3E,iBAAiB0E,aAAa;wBAC/CE,QAAQ7E;oBACV,GACAmC;gBAEJ,EAAE,OAAOqB,OAAO;oBACdlC,KAAIE,GAAG,CAAC;oBACR,IAAIgC,iBAAiBsB,OAAO;wBAC1BxD,KAAIyD,SAAS,CAACvB;oBAChB,OAAO;wBACLlC,KAAIkC,KAAK,CAAC;wBACVlC,KAAIE,GAAG,CAACgC;oBACV;oBACArD,QAAQ6E,IAAI,CAAC;gBACf;gBAEAhC,OAAO,CAACK,SAAS,GAAGW;gBAEpBiB,IAAAA,oCAAwB,EAACjB,OAAOkB,SAAS,EAAE;oBACzCC,mBAAmBzF;oBACnByC;oBACAiD,gBAAgBxC,UAAUO,8BAA8B,IAAInD;gBAC9D;gBAEA,MAAMqF,6BAA6B;uBAC9B,IAAIC,IACLtB,OAAOkB,SAAS,CACbtB,GAAG,CAAC,CAAC2B,WACJC,MAAMC,OAAO,CAACF,SAASG,QAAQ,CAACL,0BAA0B,IACtDE,SAASG,QAAQ,CAACL,0BAA0B,GAC5C,EAAE,EAEPM,IAAI;iBAEV;gBACD,MAAMjC,QAAQC,GAAG,CACf,uIAAuI;gBACvI0B,2BAA2BzB,GAAG,CAAC,OAAOgC;oBACpC,MAAM,EAAE5B,QAAQ6B,2BAA2B,EAAEC,cAAc,EAAE,GAC3D,MAAMC,IAAAA,4CAAuB,EAAC;wBAC5BH;wBACAxG;wBACAI;wBACAoD;wBACAiB;wBACAsB,mBAAmBzF;wBACnBO;wBACAkC;wBACA6D,gBAAgB;oBAClB;oBAEF,yFAAyF;oBACzF,MAAMC,iBAAiB,IAAIX,IAAItB,OAAOkC,MAAM,CAACtC,GAAG,CAAC,CAACuC,IAAMA,EAAEC,IAAI;oBAC7DpC,OAAOkC,MAAM,CAAiCG,IAAI,IAC9CR,4BAA4BK,MAAM,CAAC9C,MAAM,CAAC,CAAC+C,IAAM,CAACF,eAAeK,GAAG,CAACH,EAAEC,IAAI;oBAGhFG,IAAAA,wDAAmC,EAAC;wBAClCC,uBAAuBZ;wBACvBa,cAAczC;wBACd7B;wBACA2D;oBACF;oBACA7C,0BAA0B,CAACI,SAAS,GAAG;2BACjCJ,0BAA0B,CAACI,SAAS,IAAI,EAAE;2BAC1C,MAAMqD,IAAAA,gDAA2B,EAACb;2BACnCc,IAAAA,oDAA+B,EAAC;4BACjCxE;4BACA2D;wBACF;qBACD;gBACH;gBAGF,IAAIzC,aAAa,OAAO;oBACtB,qCAAqC;oBACrC,sCAAsC;oBACtC,IAAIuD,OAAO,MAAMC,IAAAA,sCAAuB,EAAC;wBACvCpE,aAAa;wBACbqE,WAAW9C,OAAOkB,SAAS;wBAC3B6B,UAAU,MAAMC,IAAAA,kDAAqC,EAAC5H,aAAa;4BACjE6H,SAAS,EAAE;4BACXC,UAAU,EAAE;4BACZjH,KAAKO,cAAcP,GAAG;wBACxB;wBACAmB;oBACF;oBAEA,sCAAsC;oBACtC,MAAM+F,aAAa,MAAMC,IAAAA,qCAA4B,EAAChI,aAAa;wBACjEE;wBACA8B;wBACAe;wBACAlC,KAAKO,cAAcP,GAAG;oBACxB;oBACA,IAAIkH,YAAY;wBACdP,OAAOO,WAAWP;oBACpB;oBAEA,sEAAsE;oBACtEnD,eAAemD;oBAEf,iCAAiC;oBACjC,oDAAoD;oBACpDzE,MAAMkF,GAAG,CAAC,cAAc;wBACtBC,UAAUV;wBACVW,cAAc3E,UAAUO,8BAA8B,GAAG,WAAW;oBACtE;gBACF;YACF;YAGF,IAAIP,UAAUO,8BAA8B,EAAE;gBAC5C,MAAMqE,QAAQnI,UAAUwB,QAAQ,CAAC;gBAEjC,MAAM4G,IAAAA,iDAA8B,EAAC7E,WAAW;oBAC9CT;oBACAkB,UAAU;oBACVqE,eAAe,CAACF;oBAChB/D;gBACF;YACF;YAEA,sDAAsD;YACtD,MAAM,EAAEyC,MAAM,EAAEyB,eAAe,EAAE,GAAG,MAAMC,IAAAA,+BAAiB,EAACxI,aAAa;gBACvE+C;gBACAlC;gBACAX,WAAW4C;gBACXc;gBACA5B;gBACApB;YACF;YAEA,IAAIP,cAAc;gBAChB6B,KAAIE,GAAG,CAAC;gBACRW,MAAMkF,GAAG,CAAC,iBAAiB;oBAAEC,UAAUO,KAAKC,SAAS,CAACC,IAAAA,6BAAc,EAAC;wBAAE7B;oBAAO;gBAAI;YACpF;YAEA,MAAMqB,eAAe3E,UAAUO,8BAA8B,GAAG,YAAY;YAC5E,MAAM6E,YAAYC,OAAOC,WAAW,CAClCD,OAAOE,OAAO,CAACnF,SAASY,GAAG,CAAC,CAAC,CAACP,UAAUW,OAAO,GAAK;oBAClDX;oBACAW,OAAOkB,SAAS,CACb9B,MAAM,CAAC,CAACgF,QAAUA,MAAMC,IAAI,KAAK,MACjCzE,GAAG,CAAC,CAACwE,QAAUb,eAAea,MAAME,QAAQ;iBAChD;YAGH,6CAA6C;YAC7C,MAAMhB,WAAWiB,IAAAA,sCAAkB,EAAC;gBAClCvF;gBACAgF;gBACAL;gBACA1E;YACF;YACAd,MAAMkF,GAAG,CAAC,iBAAiB;gBAAEC,UAAUO,KAAKC,SAAS,CAACR;YAAU;QAClE;QAEA,+BAA+B;QAE/B,IAAIjI,UAAUwB,QAAQ,CAAC,UAAUG,oBAAoB;gBAC9Bf;YAArB,MAAMuI,eAAevI,EAAAA,YAAAA,IAAIgB,GAAG,qBAAPhB,UAASiB,MAAM,MAAK;YAEzC,IAAIsH,cAAc;gBAChB,0DAA0D;gBAC1D,MAAMlF,IAAAA,mCAAqB,EAACxB,YAAYC,eAAI,CAACC,OAAO,CAACE,YAAY;YACnE;YAEA,IAAInC,SAAS;gBACXuB,KAAIE,GAAG,CAAC;gBACR,MAAMiG,IAAAA,iDAA8B,EAAC7E,WAAW;oBAC9CT;oBACAkB,UAAU;oBACVqE,eAAe;gBACjB;gBAEA,gFAAgF;gBAChF,sEAAsE;gBACtE,MAAMe,mBAAmB1G,eAAI,CAACC,OAAO,CAACE,YAAY;gBAClD,IAAI,CAACwG,aAAE,CAACC,UAAU,CAACF,mBAAmB;oBACpCtG,MAAMkF,GAAG,CAAC,cAAc;wBACtBC,UAAU,CAAC,0BAA0B,CAAC;wBACtCC,cAAc;oBAChB;gBACF;YACF,OAAO,IACL,wCAAwC;YACxC,CAAC3E,UAAUO,8BAA8B,EACzC;oBAUmBlD;gBATnB,MAAM2I,IAAAA,wCAAqB,EAACxJ,aAAawD,WAAW;oBAClDf;oBACAM;oBACA5C,OAAO,CAAC,CAACA;oBACTD,WAAW4C;oBACXtC;oBACAwB;oBACA+D,mBAAmBzF;oBACnBmJ,YAAYC,IAAAA,8CAAsC,EAAC1J,aAAaa;oBAChE0E,eAAe,CAAC,GAAC1E,mBAAAA,IAAI2E,WAAW,qBAAf3E,iBAAiB0E,aAAa;oBAC/C6D;oBACA1I;oBACA2C,aAAa;oBACbxC,KAAKO,cAAcP,GAAG;gBACxB;YACF;QACF;IACF,SAAU;QACR,MAAMoC,iBAAiB0G,SAAS;IAClC;IAEA,kDAAkD;IAClD,MAAMC,IAAAA,kCAAsB,EAAC7G,OAAOD;AACtC"}
|
|
1
|
+
{"version":3,"sources":["../../../src/export/exportApp.ts"],"sourcesContent":["import { getConfig } from '@expo/config';\nimport type { Platform } from '@expo/config';\nimport { resolveRelativeEntryPoint } from '@expo/config/paths';\nimport { SerialAsset } from '@expo/metro-config/build/serializer/serializerAssets';\nimport assert from 'assert';\nimport chalk from 'chalk';\nimport fs from 'fs';\nimport path from 'path';\n\nimport { type PlatformMetadata, createMetadataJson } from './createMetadataJson';\nimport { exportAssetsAsync } from './exportAssets';\nimport {\n addDomBundleToMetadataAsync,\n exportDomComponentAsync,\n transformNativeBundleForMd5Filename,\n transformDomEntryForMd5Filename,\n} from './exportDomComponents';\nimport { assertEngineMismatchAsync, isEnableHermesManaged } from './exportHermes';\nimport { exportApiRoutesStandaloneAsync, exportFromServerAsync } from './exportStaticAsync';\nimport { getVirtualFaviconAssetsAsync } from './favicon';\nimport { getPublicExpoManifestAsync } from './getPublicExpoManifest';\nimport { copyPublicFolderAsync, getPublicFolderPath } from './publicFolder';\nimport type { Options } from './resolveOptions';\nimport type { ExportAssetMap, BundleOutput, BundleAssetWithFileHashes } from './saveAssets';\nimport { getFilesFromSerialAssets, persistMetroFilesAsync } from './saveAssets';\nimport { createAssetMap } from './writeContents';\nimport * as Log from '../log';\nimport { WebSupportProjectPrerequisite } from '../start/doctor/web/WebSupportProjectPrerequisite';\nimport { DevServerManager } from '../start/server/DevServerManager';\nimport { MetroBundlerDevServer } from '../start/server/metro/MetroBundlerDevServer';\nimport { getRouterDirectoryModuleIdWithManifest } from '../start/server/metro/router';\nimport { serializeHtmlWithAssets } from '../start/server/metro/serializeHtml';\nimport { getBaseUrlFromExpoConfig } from '../start/server/middleware/metroOptions';\nimport { createTemplateHtmlFromExpoConfigAsync } from '../start/server/webTemplate';\nimport { env } from '../utils/env';\nimport { CommandError } from '../utils/errors';\nimport { setNodeEnv, loadEnvFiles } from '../utils/nodeEnv';\n\nexport async function exportAppAsync(\n projectRoot: string,\n {\n platforms,\n outputDir,\n clear,\n dev,\n dumpAssetmap,\n sourceMaps,\n inlineSourceMaps,\n minify,\n bytecode,\n maxWorkers,\n skipSSG,\n hostedNative,\n }: Pick<\n Options,\n | 'dumpAssetmap'\n | 'sourceMaps'\n | 'inlineSourceMaps'\n | 'dev'\n | 'clear'\n | 'outputDir'\n | 'platforms'\n | 'minify'\n | 'bytecode'\n | 'maxWorkers'\n | 'skipSSG'\n | 'hostedNative'\n >\n): Promise<void> {\n // Force the environment during export and do not allow overriding it.\n const environment = dev ? 'development' : 'production';\n process.env.NODE_ENV = environment;\n setNodeEnv(environment);\n loadEnvFiles(projectRoot);\n\n const projectConfig = getConfig(projectRoot);\n const exp = await getPublicExpoManifestAsync(projectRoot, {\n // Web doesn't require validation.\n skipValidation: platforms.length === 1 && platforms[0] === 'web',\n });\n\n if (platforms.includes('web')) {\n await new WebSupportProjectPrerequisite(projectRoot).assertAsync();\n }\n\n const useServerRendering = ['static', 'server'].includes(exp.web?.output ?? '');\n\n if (skipSSG && exp.web?.output !== 'server') {\n throw new CommandError('--no-ssg can only be used with `web.output: server`');\n }\n\n const baseUrl = getBaseUrlFromExpoConfig(exp);\n\n if (!bytecode && (platforms.includes('ios') || platforms.includes('android'))) {\n Log.warn(\n `Bytecode makes the app startup faster, disabling bytecode is highly discouraged and should only be used for debugging purposes.`\n );\n }\n\n // Print out logs\n if (baseUrl) {\n Log.log();\n Log.log(chalk.gray`Using (experimental) base path: ${baseUrl}`);\n // Warn if not using an absolute path.\n if (!baseUrl.startsWith('/')) {\n Log.log(\n chalk.yellow` Base path does not start with a slash. Requests will not be absolute.`\n );\n }\n }\n\n const mode = dev ? 'development' : 'production';\n const publicPath = getPublicFolderPath(projectRoot);\n const outputPath = path.resolve(projectRoot, outputDir);\n\n // Write the JS bundles to disk, and get the bundle file names (this could change with async chunk loading support).\n\n const files: ExportAssetMap = new Map();\n\n const devServerManager = await DevServerManager.startMetroAsync(projectRoot, {\n minify,\n mode,\n port: 8081,\n isExporting: true,\n location: {},\n resetDevServer: clear,\n maxWorkers,\n });\n\n const devServer = devServerManager.getDefaultDevServer();\n assert(devServer instanceof MetroBundlerDevServer);\n\n const bundles: Partial<Record<Platform, BundleOutput>> = {};\n const domComponentAssetsMetadata: Partial<Record<Platform, PlatformMetadata['assets']>> = {};\n\n const spaPlatforms =\n // TODO: Support server and static rendering for server component exports.\n useServerRendering && !devServer.isReactServerComponentsEnabled\n ? platforms.filter((platform) => platform !== 'web')\n : platforms;\n\n try {\n if (devServer.isReactServerComponentsEnabled) {\n // In RSC mode, we only need these to be in the client dir.\n // TODO: Merge back with other copy after we add SSR.\n try {\n await copyPublicFolderAsync(publicPath, path.join(outputPath, 'client'));\n } catch (error) {\n Log.error('Failed to copy public directory to dist directory');\n throw error;\n }\n } else {\n // NOTE(kitten): The public folder is currently always copied, regardless of targetDomain\n // split. Hence, there's another separate `copyPublicFolderAsync` call below for `web`\n await copyPublicFolderAsync(publicPath, outputPath);\n }\n\n let templateHtml: string | undefined;\n // Can be empty during web-only SSG.\n if (spaPlatforms.length) {\n await Promise.all(\n spaPlatforms.map(async (platform) => {\n // Assert early so the user doesn't have to wait until bundling is complete to find out that\n // Hermes won't be available.\n const isHermes = isEnableHermesManaged(exp, platform);\n if (isHermes) {\n await assertEngineMismatchAsync(projectRoot, exp, platform);\n }\n\n let bundle: {\n artifacts: SerialAsset[];\n assets: readonly BundleAssetWithFileHashes[];\n files?: ExportAssetMap;\n };\n\n try {\n // Run metro bundler and create the JS bundles/source maps.\n bundle = await devServer.nativeExportBundleAsync(\n exp,\n {\n platform,\n splitChunks:\n !env.EXPO_NO_BUNDLE_SPLITTING &&\n ((devServer.isReactServerComponentsEnabled && !bytecode) || platform === 'web'),\n mainModuleName: resolveRelativeEntryPoint(projectRoot, {\n platform,\n pkg: projectConfig.pkg,\n }),\n mode: dev ? 'development' : 'production',\n engine: isHermes ? 'hermes' : undefined,\n serializerIncludeMaps: sourceMaps || inlineSourceMaps,\n inlineSourceMap: inlineSourceMaps,\n bytecode: bytecode && isHermes,\n reactCompiler: !!exp.experiments?.reactCompiler,\n hosted: hostedNative,\n },\n files\n );\n } catch (error) {\n Log.log('');\n if (error instanceof Error) {\n Log.exception(error);\n } else {\n Log.error('Failed to bundle the app');\n Log.log(error as any);\n }\n process.exit(1);\n }\n\n bundles[platform] = bundle;\n\n getFilesFromSerialAssets(bundle.artifacts, {\n includeSourceMaps: sourceMaps,\n files,\n isServerHosted: devServer.isReactServerComponentsEnabled || hostedNative,\n });\n\n const expoDomComponentReferences = [\n ...new Set(\n bundle.artifacts\n .map((artifact) =>\n Array.isArray(artifact.metadata.expoDomComponentReferences)\n ? artifact.metadata.expoDomComponentReferences\n : []\n )\n .flat()\n ),\n ];\n await Promise.all(\n // TODO: Make a version of this which uses `this.metro.getBundler().buildGraphForEntries([])` to bundle all the DOM components at once.\n expoDomComponentReferences.map(async (filePath) => {\n const { bundle: platformDomComponentsBundle, htmlOutputName } =\n await exportDomComponentAsync({\n filePath,\n projectRoot,\n dev,\n devServer,\n isHermes,\n includeSourceMaps: sourceMaps,\n exp,\n files,\n useMd5Filename: true,\n });\n\n // Merge the assets from the DOM component into the output assets, deduplicating by hash.\n const existingHashes = new Set(bundle.assets.map((a) => a.hash));\n (bundle.assets as (typeof bundle.assets)[0][]).push(\n ...platformDomComponentsBundle.assets.filter((a) => !existingHashes.has(a.hash))\n );\n\n transformNativeBundleForMd5Filename({\n domComponentReference: filePath,\n nativeBundle: bundle,\n files,\n htmlOutputName,\n });\n domComponentAssetsMetadata[platform] = [\n ...(domComponentAssetsMetadata[platform] || []),\n ...(await addDomBundleToMetadataAsync(platformDomComponentsBundle)),\n ...transformDomEntryForMd5Filename({\n files,\n htmlOutputName,\n }),\n ];\n })\n );\n\n if (platform === 'web') {\n // TODO: Unify with exportStaticAsync\n // TODO: Maybe move to the serializer.\n let html = await serializeHtmlWithAssets({\n isExporting: true,\n resources: bundle.artifacts,\n template: await createTemplateHtmlFromExpoConfigAsync(projectRoot, {\n scripts: [],\n cssLinks: [],\n exp: projectConfig.exp,\n }),\n baseUrl,\n });\n\n // Add the favicon assets to the HTML.\n const modifyHtml = await getVirtualFaviconAssetsAsync(projectRoot, {\n outputDir,\n baseUrl,\n files,\n exp: projectConfig.exp,\n });\n if (modifyHtml) {\n html = modifyHtml(html);\n }\n\n // HACK: This is used for adding SSR shims in React Server Components.\n templateHtml = html;\n\n // Generate SPA-styled HTML file.\n // If web exists, then write the template HTML file.\n files.set('index.html', {\n contents: html,\n targetDomain: devServer.isReactServerComponentsEnabled ? 'server' : 'client',\n });\n }\n })\n );\n\n if (devServer.isReactServerComponentsEnabled) {\n const isWeb = platforms.includes('web');\n\n await exportApiRoutesStandaloneAsync(devServer, {\n files,\n platform: 'web',\n apiRoutesOnly: !isWeb,\n templateHtml,\n });\n }\n\n // TODO: Use same asset system across platforms again.\n const { assets, embeddedHashSet } = await exportAssetsAsync(projectRoot, {\n files,\n exp,\n outputDir: outputPath,\n bundles,\n baseUrl,\n hostedNative,\n });\n\n if (dumpAssetmap) {\n Log.log('Creating asset map');\n files.set('assetmap.json', { contents: JSON.stringify(createAssetMap({ assets })) });\n }\n\n const targetDomain = devServer.isReactServerComponentsEnabled ? 'client/' : '';\n const fileNames = Object.fromEntries(\n Object.entries(bundles).map(([platform, bundle]) => [\n platform,\n bundle.artifacts\n .filter((asset) => asset.type === 'js')\n .map((asset) => targetDomain + asset.filename),\n ])\n );\n\n // Generate a `metadata.json` for EAS Update.\n const contents = createMetadataJson({\n bundles,\n fileNames,\n embeddedHashSet,\n domComponentAssetsMetadata,\n });\n files.set('metadata.json', { contents: JSON.stringify(contents) });\n }\n\n // Additional web-only steps...\n\n if (platforms.includes('web') && useServerRendering) {\n const exportServer = exp.web?.output === 'server';\n\n if (exportServer) {\n // TODO: Remove when this is abstracted into the files map\n await copyPublicFolderAsync(publicPath, path.resolve(outputPath, 'client'));\n }\n\n if (skipSSG) {\n Log.log('Skipping static site generation');\n await exportApiRoutesStandaloneAsync(devServer, {\n files,\n platform: 'web',\n apiRoutesOnly: true,\n });\n\n // Output a placeholder index.html if one doesn't exist in the public directory.\n // This ensures native + API routes have some content at the root URL.\n const placeholderIndex = path.resolve(outputPath, 'client/index.html');\n if (!fs.existsSync(placeholderIndex)) {\n files.set('index.html', {\n contents: `<html><body></body></html>`,\n targetDomain: 'client',\n });\n }\n } else if (\n // TODO: Support static export with RSC.\n !devServer.isReactServerComponentsEnabled\n ) {\n await exportFromServerAsync(projectRoot, devServer, {\n mode,\n files,\n clear: !!clear,\n outputDir: outputPath,\n minify,\n baseUrl,\n includeSourceMaps: sourceMaps,\n routerRoot: getRouterDirectoryModuleIdWithManifest(projectRoot, exp),\n reactCompiler: !!exp.experiments?.reactCompiler,\n exportServer,\n maxWorkers,\n isExporting: true,\n exp: projectConfig.exp,\n });\n }\n }\n } finally {\n await devServerManager.stopAsync();\n }\n\n // Write all files at the end for unified logging.\n await persistMetroFilesAsync(files, outputPath);\n}\n"],"names":["exportAppAsync","projectRoot","platforms","outputDir","clear","dev","dumpAssetmap","sourceMaps","inlineSourceMaps","minify","bytecode","maxWorkers","skipSSG","hostedNative","exp","environment","process","env","NODE_ENV","setNodeEnv","loadEnvFiles","projectConfig","getConfig","getPublicExpoManifestAsync","skipValidation","length","includes","WebSupportProjectPrerequisite","assertAsync","useServerRendering","web","output","CommandError","baseUrl","getBaseUrlFromExpoConfig","Log","warn","log","chalk","gray","startsWith","yellow","mode","publicPath","getPublicFolderPath","outputPath","path","resolve","files","Map","devServerManager","DevServerManager","startMetroAsync","port","isExporting","location","resetDevServer","devServer","getDefaultDevServer","assert","MetroBundlerDevServer","bundles","domComponentAssetsMetadata","spaPlatforms","isReactServerComponentsEnabled","filter","platform","copyPublicFolderAsync","join","error","templateHtml","Promise","all","map","isHermes","isEnableHermesManaged","assertEngineMismatchAsync","bundle","nativeExportBundleAsync","splitChunks","EXPO_NO_BUNDLE_SPLITTING","mainModuleName","resolveRelativeEntryPoint","pkg","engine","undefined","serializerIncludeMaps","inlineSourceMap","reactCompiler","experiments","hosted","Error","exception","exit","getFilesFromSerialAssets","artifacts","includeSourceMaps","isServerHosted","expoDomComponentReferences","Set","artifact","Array","isArray","metadata","flat","filePath","platformDomComponentsBundle","htmlOutputName","exportDomComponentAsync","useMd5Filename","existingHashes","assets","a","hash","push","has","transformNativeBundleForMd5Filename","domComponentReference","nativeBundle","addDomBundleToMetadataAsync","transformDomEntryForMd5Filename","html","serializeHtmlWithAssets","resources","template","createTemplateHtmlFromExpoConfigAsync","scripts","cssLinks","modifyHtml","getVirtualFaviconAssetsAsync","set","contents","targetDomain","isWeb","exportApiRoutesStandaloneAsync","apiRoutesOnly","embeddedHashSet","exportAssetsAsync","JSON","stringify","createAssetMap","fileNames","Object","fromEntries","entries","asset","type","filename","createMetadataJson","exportServer","placeholderIndex","fs","existsSync","exportFromServerAsync","routerRoot","getRouterDirectoryModuleIdWithManifest","stopAsync","persistMetroFilesAsync"],"mappings":"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"}
|
|
@@ -12,6 +12,9 @@ _export(exports, {
|
|
|
12
12
|
copyPublicFolderAsync: function() {
|
|
13
13
|
return copyPublicFolderAsync;
|
|
14
14
|
},
|
|
15
|
+
getPublicFolderPath: function() {
|
|
16
|
+
return getPublicFolderPath;
|
|
17
|
+
},
|
|
15
18
|
getUserDefinedFile: function() {
|
|
16
19
|
return getUserDefinedFile;
|
|
17
20
|
}
|
|
@@ -32,14 +35,29 @@ function _path() {
|
|
|
32
35
|
}
|
|
33
36
|
const _dir = require("../utils/dir");
|
|
34
37
|
const _env = require("../utils/env");
|
|
38
|
+
const _errors = require("../utils/errors");
|
|
35
39
|
function _interop_require_default(obj) {
|
|
36
40
|
return obj && obj.__esModule ? obj : {
|
|
37
41
|
default: obj
|
|
38
42
|
};
|
|
39
43
|
}
|
|
40
44
|
const debug = require('debug')('expo:public-folder');
|
|
45
|
+
const maybeRealpath = (target)=>{
|
|
46
|
+
try {
|
|
47
|
+
return _fs().default.realpathSync(target);
|
|
48
|
+
} catch {
|
|
49
|
+
return target;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
function getPublicFolderPath(projectRoot) {
|
|
53
|
+
const publicPath = maybeRealpath(_path().default.resolve(projectRoot, _env.env.EXPO_PUBLIC_FOLDER));
|
|
54
|
+
if (!(0, _dir.isPathInside)(publicPath, projectRoot)) {
|
|
55
|
+
throw new _errors.CommandError('EXPO_PUBLIC_FOLDER', `EXPO_PUBLIC_FOLDER ("${_env.env.EXPO_PUBLIC_FOLDER}") resolves to "${publicPath}", which is outside the project root "${projectRoot}". Set EXPO_PUBLIC_FOLDER to a path inside your project (e.g. "public").`);
|
|
56
|
+
}
|
|
57
|
+
return publicPath;
|
|
58
|
+
}
|
|
41
59
|
function getUserDefinedFile(projectRoot, possiblePaths) {
|
|
42
|
-
const publicPath =
|
|
60
|
+
const publicPath = getPublicFolderPath(projectRoot);
|
|
43
61
|
for (const possiblePath of possiblePaths){
|
|
44
62
|
const fullPath = _path().default.join(publicPath, possiblePath);
|
|
45
63
|
if (_fs().default.existsSync(fullPath)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/export/publicFolder.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\nimport { copyAsync } from '../utils/dir';\nimport { env } from '../utils/env';\n\nconst debug = require('debug')('expo:public-folder') as typeof console.log;\n\n/** @returns the file system path for a user-defined file in the public folder. */\nexport function getUserDefinedFile(projectRoot: string, possiblePaths: string[]): string | null {\n const publicPath =
|
|
1
|
+
{"version":3,"sources":["../../../src/export/publicFolder.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\nimport { copyAsync, isPathInside } from '../utils/dir';\nimport { env } from '../utils/env';\nimport { CommandError } from '../utils/errors';\n\nconst debug = require('debug')('expo:public-folder') as typeof console.log;\n\nconst maybeRealpath = (target: string) => {\n try {\n return fs.realpathSync(target);\n } catch {\n return target;\n }\n};\n\n/**\n * Resolve `EXPO_PUBLIC_FOLDER` against the project root and ensure the result\n * stays inside the project. An `EXPO_PUBLIC_FOLDER` value that escapes\n * (e.g. `../etc`, `/absolute/path`) almost always indicates a misconfigured\n * environment, and if honored would expose unrelated files via every consumer\n * that serves or copies the public folder.\n */\nexport function getPublicFolderPath(projectRoot: string): string {\n const publicPath = maybeRealpath(path.resolve(projectRoot, env.EXPO_PUBLIC_FOLDER));\n if (!isPathInside(publicPath, projectRoot)) {\n throw new CommandError(\n 'EXPO_PUBLIC_FOLDER',\n `EXPO_PUBLIC_FOLDER (\"${env.EXPO_PUBLIC_FOLDER}\") resolves to \"${publicPath}\", which is outside the project root \"${projectRoot}\". Set EXPO_PUBLIC_FOLDER to a path inside your project (e.g. \"public\").`\n );\n }\n return publicPath;\n}\n\n/** @returns the file system path for a user-defined file in the public folder. */\nexport function getUserDefinedFile(projectRoot: string, possiblePaths: string[]): string | null {\n const publicPath = getPublicFolderPath(projectRoot);\n\n for (const possiblePath of possiblePaths) {\n const fullPath = path.join(publicPath, possiblePath);\n if (fs.existsSync(fullPath)) {\n debug(`Found user-defined public file: ` + possiblePath);\n return fullPath;\n }\n }\n\n return null;\n}\n\n/**\n * Copy the contents of the public folder into the output folder.\n * This enables users to add static files like `favicon.ico`.\n *\n * The contents of this folder are completely universal since they refer to\n * static network requests which fall outside the scope of React Native's magic\n * platform resolution patterns.\n */\nexport async function copyPublicFolderAsync(publicFolder: string, outputFolder: string) {\n if (fs.existsSync(publicFolder)) {\n await fs.promises.mkdir(outputFolder, { recursive: true });\n await copyAsync(publicFolder, outputFolder);\n }\n}\n"],"names":["copyPublicFolderAsync","getPublicFolderPath","getUserDefinedFile","debug","require","maybeRealpath","target","fs","realpathSync","projectRoot","publicPath","path","resolve","env","EXPO_PUBLIC_FOLDER","isPathInside","CommandError","possiblePaths","possiblePath","fullPath","join","existsSync","publicFolder","outputFolder","promises","mkdir","recursive","copyAsync"],"mappings":";;;;;;;;;;;IA0DsBA,qBAAqB;eAArBA;;IAlCNC,mBAAmB;eAAnBA;;IAYAC,kBAAkB;eAAlBA;;;;gEApCD;;;;;;;gEACE;;;;;;qBAEuB;qBACpB;wBACS;;;;;;AAE7B,MAAMC,QAAQC,QAAQ,SAAS;AAE/B,MAAMC,gBAAgB,CAACC;IACrB,IAAI;QACF,OAAOC,aAAE,CAACC,YAAY,CAACF;IACzB,EAAE,OAAM;QACN,OAAOA;IACT;AACF;AASO,SAASL,oBAAoBQ,WAAmB;IACrD,MAAMC,aAAaL,cAAcM,eAAI,CAACC,OAAO,CAACH,aAAaI,QAAG,CAACC,kBAAkB;IACjF,IAAI,CAACC,IAAAA,iBAAY,EAACL,YAAYD,cAAc;QAC1C,MAAM,IAAIO,oBAAY,CACpB,sBACA,CAAC,qBAAqB,EAAEH,QAAG,CAACC,kBAAkB,CAAC,gBAAgB,EAAEJ,WAAW,sCAAsC,EAAED,YAAY,wEAAwE,CAAC;IAE7M;IACA,OAAOC;AACT;AAGO,SAASR,mBAAmBO,WAAmB,EAAEQ,aAAuB;IAC7E,MAAMP,aAAaT,oBAAoBQ;IAEvC,KAAK,MAAMS,gBAAgBD,cAAe;QACxC,MAAME,WAAWR,eAAI,CAACS,IAAI,CAACV,YAAYQ;QACvC,IAAIX,aAAE,CAACc,UAAU,CAACF,WAAW;YAC3BhB,MAAM,CAAC,gCAAgC,CAAC,GAAGe;YAC3C,OAAOC;QACT;IACF;IAEA,OAAO;AACT;AAUO,eAAenB,sBAAsBsB,YAAoB,EAAEC,YAAoB;IACpF,IAAIhB,aAAE,CAACc,UAAU,CAACC,eAAe;QAC/B,MAAMf,aAAE,CAACiB,QAAQ,CAACC,KAAK,CAACF,cAAc;YAAEG,WAAW;QAAK;QACxD,MAAMC,IAAAA,cAAS,EAACL,cAAcC;IAChC;AACF"}
|
|
@@ -22,13 +22,12 @@ function _semver() {
|
|
|
22
22
|
};
|
|
23
23
|
return data;
|
|
24
24
|
}
|
|
25
|
-
const _client = require("../api/rest/client");
|
|
26
25
|
const _log = /*#__PURE__*/ _interop_require_wildcard(require("../log"));
|
|
27
26
|
const _resolveLocalTemplate = require("./resolveLocalTemplate");
|
|
28
27
|
const _createFileTransform = require("../utils/createFileTransform");
|
|
29
28
|
const _errors = require("../utils/errors");
|
|
29
|
+
const _fetch = require("../utils/fetch");
|
|
30
30
|
const _npm = require("../utils/npm");
|
|
31
|
-
const _url = require("../utils/url");
|
|
32
31
|
function _interop_require_default(obj) {
|
|
33
32
|
return obj && obj.__esModule ? obj : {
|
|
34
33
|
default: obj
|
|
@@ -122,8 +121,9 @@ async function getRepoInfo(url, examplePath) {
|
|
|
122
121
|
const filePath = examplePath ? examplePath.replace(/^\//, '') : file.join('/');
|
|
123
122
|
// Support repos whose entire purpose is to be an example, e.g.
|
|
124
123
|
// https://github.com/:username/:my-cool-example-repo-name.
|
|
124
|
+
// Use the plain unauthenticated `fetch` so Expo credentials aren't forwarded to GitHub.
|
|
125
125
|
if (t === undefined) {
|
|
126
|
-
const infoResponse = await (0,
|
|
126
|
+
const infoResponse = await (0, _fetch.fetch)(`https://api.github.com/repos/${username}/${name}`);
|
|
127
127
|
if (infoResponse.status !== 200) {
|
|
128
128
|
return;
|
|
129
129
|
}
|
|
@@ -147,10 +147,15 @@ async function getRepoInfo(url, examplePath) {
|
|
|
147
147
|
}
|
|
148
148
|
return undefined;
|
|
149
149
|
}
|
|
150
|
-
function hasRepo({ username, name, branch, filePath }) {
|
|
150
|
+
async function hasRepo({ username, name, branch, filePath }) {
|
|
151
151
|
const contentsUrl = `https://api.github.com/repos/${username}/${name}/contents`;
|
|
152
152
|
const packagePath = `${filePath ? `/${filePath}` : ''}/package.json`;
|
|
153
|
-
|
|
153
|
+
try {
|
|
154
|
+
const response = await (0, _fetch.fetch)(contentsUrl + packagePath + `?ref=${branch}`);
|
|
155
|
+
return response.ok;
|
|
156
|
+
} catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
154
159
|
}
|
|
155
160
|
async function downloadAndExtractRepoAsync({ username, name, branch, filePath }, output, props) {
|
|
156
161
|
const url = `https://codeload.github.com/${username}/${name}/tar.gz/${branch}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/prebuild/resolveTemplate.ts"],"sourcesContent":["import { ExpoConfig } from '@expo/config';\nimport chalk from 'chalk';\nimport { Ora } from 'ora';\nimport semver from 'semver';\n\nimport { type ResolvedTemplateOption } from './resolveOptions';\nimport { fetchAsync } from '../api/rest/client';\nimport * as Log from '../log';\nimport { resolveLocalTemplateAsync } from './resolveLocalTemplate';\nimport { createGlobFilter } from '../utils/createFileTransform';\nimport { AbortCommandError } from '../utils/errors';\nimport {\n downloadAndExtractNpmModuleAsync,\n extractLocalNpmTarballAsync,\n extractNpmTarballFromUrlAsync,\n} from '../utils/npm';\nimport { isUrlOk } from '../utils/url';\n\nconst debug = require('debug')('expo:prebuild:resolveTemplate') as typeof console.log;\n\ntype RepoInfo = {\n username: string;\n name: string;\n branch: string;\n filePath: string;\n};\n\nexport async function cloneTemplateAsync({\n templateDirectory,\n projectRoot,\n template,\n exp,\n ora,\n}: {\n templateDirectory: string;\n projectRoot: string;\n template?: ResolvedTemplateOption;\n exp: Pick<ExpoConfig, 'name' | 'sdkVersion'>;\n ora: Ora;\n}): Promise<string> {\n if (template) {\n const expName = exp.name;\n const { type, uri } = template;\n if (type === 'file') {\n return await extractLocalNpmTarballAsync(uri, templateDirectory, {\n expName,\n });\n } else if (type === 'npm') {\n return await downloadAndExtractNpmModuleAsync(uri, templateDirectory, {\n expName,\n });\n } else if (type === 'repository') {\n return await resolveAndDownloadRepoTemplateAsync(templateDirectory, ora, expName, uri);\n } else {\n throw new Error(`Unknown template type: ${type}`);\n }\n } else {\n try {\n return await resolveLocalTemplateAsync({ templateDirectory, projectRoot, exp });\n } catch (error: any) {\n const templatePackageName = getTemplateNpmPackageNameFromSdkVersion(exp.sdkVersion);\n debug('Fallback to SDK template:', templatePackageName);\n return await downloadAndExtractNpmModuleAsync(templatePackageName, templateDirectory, {\n expName: exp.name,\n });\n }\n }\n}\n\n/** Given an `sdkVersion` like `44.0.0` return a fully qualified NPM package name like: `expo-template-bare-minimum@sdk-44` */\nfunction getTemplateNpmPackageNameFromSdkVersion(sdkVersion?: string): string {\n // When undefined or UNVERSIONED, we use the latest version.\n if (!sdkVersion || sdkVersion === 'UNVERSIONED') {\n Log.log('Using an unspecified Expo SDK version. The latest template will be used.');\n return `expo-template-bare-minimum@latest`;\n }\n return `expo-template-bare-minimum@sdk-${semver.major(sdkVersion)}`;\n}\n\nasync function getRepoInfo(url: any, examplePath?: string): Promise<RepoInfo | undefined> {\n const [, username, name, t, _branch, ...file] = url.pathname.split('/');\n const filePath = examplePath ? examplePath.replace(/^\\//, '') : file.join('/');\n\n // Support repos whose entire purpose is to be an example, e.g.\n // https://github.com/:username/:my-cool-example-repo-name.\n if (t === undefined) {\n const infoResponse = await fetchAsync(`https://api.github.com/repos/${username}/${name}`);\n if (infoResponse.status !== 200) {\n return;\n }\n const info: any = await infoResponse.json();\n return { username, name, branch: info['default_branch'], filePath };\n }\n\n // If examplePath is available, the branch name takes the entire path\n const branch = examplePath\n ? `${_branch}/${file.join('/')}`.replace(new RegExp(`/${filePath}|/$`), '')\n : _branch;\n\n if (username && name && branch && t === 'tree') {\n return { username, name, branch, filePath };\n }\n return undefined;\n}\n\nfunction hasRepo({ username, name, branch, filePath }: RepoInfo) {\n const contentsUrl = `https://api.github.com/repos/${username}/${name}/contents`;\n const packagePath = `${filePath ? `/${filePath}` : ''}/package.json`;\n\n return isUrlOk(contentsUrl + packagePath + `?ref=${branch}`);\n}\n\nasync function downloadAndExtractRepoAsync(\n { username, name, branch, filePath }: RepoInfo,\n output: string,\n props: { expName?: string }\n): Promise<string> {\n const url = `https://codeload.github.com/${username}/${name}/tar.gz/${branch}`;\n\n debug('Downloading tarball from:', url);\n\n // Extract the (sub)directory into non-empty path segments\n const directory = filePath.replace(/^\\//, '').split('/').filter(Boolean);\n // Remove the (sub)directory paths, and the root folder added by GitHub\n const strip = directory.length + 1;\n // Only extract the relevant (sub)directories, ignoring irrelevant files\n // The filder auto-ignores dotfiles, unless explicitly included\n const filter = createGlobFilter(\n !directory.length\n ? ['*/**', '*/ios/.xcode.env']\n : [`*/${directory.join('/')}/**`, `*/${directory.join('/')}/ios/.xcode.env`],\n {\n // Always ignore the `.xcworkspace` folder\n ignore: ['**/ios/*.xcworkspace/**'],\n }\n );\n\n return await extractNpmTarballFromUrlAsync(url, output, {\n ...props,\n strip,\n filter,\n });\n}\n\nasync function resolveAndDownloadRepoTemplateAsync(\n templateDirectory: string,\n oraInstance: Ora,\n expName: string,\n template: string,\n templatePath?: string\n) {\n let repoUrl: URL | undefined;\n\n try {\n repoUrl = new URL(template);\n } catch (error: any) {\n if (error.code !== 'ERR_INVALID_URL') {\n oraInstance.fail(error);\n throw error;\n }\n }\n if (!repoUrl) {\n oraInstance.fail(`Invalid URL: ${chalk.red(`\"${template}\"`)}. Try again with a valid URL.`);\n throw new AbortCommandError();\n }\n\n if (repoUrl.origin !== 'https://github.com') {\n oraInstance.fail(\n `Invalid URL: ${chalk.red(\n `\"${template}\"`\n )}. Only GitHub repositories are supported. Try again with a valid GitHub URL.`\n );\n throw new AbortCommandError();\n }\n\n const repoInfo = await getRepoInfo(repoUrl, templatePath);\n\n if (!repoInfo) {\n oraInstance.fail(\n `Found invalid GitHub URL: ${chalk.red(`\"${template}\"`)}. Fix the URL and try again.`\n );\n throw new AbortCommandError();\n }\n\n const found = await hasRepo(repoInfo);\n\n if (!found) {\n oraInstance.fail(\n `Could not locate the repository for ${chalk.red(\n `\"${template}\"`\n )}. Check that the repository exists and try again.`\n );\n throw new AbortCommandError();\n }\n\n oraInstance.text = chalk.bold(\n `Downloading files from repo ${chalk.cyan(template)}. This might take a moment.`\n );\n\n return await downloadAndExtractRepoAsync(repoInfo, templateDirectory, { expName });\n}\n"],"names":["cloneTemplateAsync","debug","require","templateDirectory","projectRoot","template","exp","ora","expName","name","type","uri","extractLocalNpmTarballAsync","downloadAndExtractNpmModuleAsync","resolveAndDownloadRepoTemplateAsync","Error","resolveLocalTemplateAsync","error","templatePackageName","getTemplateNpmPackageNameFromSdkVersion","sdkVersion","Log","log","semver","major","getRepoInfo","url","examplePath","username","t","_branch","file","pathname","split","filePath","replace","join","undefined","infoResponse","fetchAsync","status","info","json","branch","RegExp","hasRepo","contentsUrl","packagePath","isUrlOk","downloadAndExtractRepoAsync","output","props","directory","filter","Boolean","strip","length","createGlobFilter","ignore","extractNpmTarballFromUrlAsync","oraInstance","templatePath","repoUrl","URL","code","fail","chalk","red","AbortCommandError","origin","repoInfo","found","text","bold","cyan"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/prebuild/resolveTemplate.ts"],"sourcesContent":["import type { ExpoConfig } from '@expo/config';\nimport chalk from 'chalk';\nimport type { Ora } from 'ora';\nimport semver from 'semver';\n\nimport type { ResolvedTemplateOption } from './resolveOptions';\nimport * as Log from '../log';\nimport { resolveLocalTemplateAsync } from './resolveLocalTemplate';\nimport { createGlobFilter } from '../utils/createFileTransform';\nimport { AbortCommandError } from '../utils/errors';\nimport { fetch } from '../utils/fetch';\nimport {\n downloadAndExtractNpmModuleAsync,\n extractLocalNpmTarballAsync,\n extractNpmTarballFromUrlAsync,\n} from '../utils/npm';\n\nconst debug = require('debug')('expo:prebuild:resolveTemplate') as typeof console.log;\n\ntype RepoInfo = {\n username: string;\n name: string;\n branch: string;\n filePath: string;\n};\n\nexport async function cloneTemplateAsync({\n templateDirectory,\n projectRoot,\n template,\n exp,\n ora,\n}: {\n templateDirectory: string;\n projectRoot: string;\n template?: ResolvedTemplateOption;\n exp: Pick<ExpoConfig, 'name' | 'sdkVersion'>;\n ora: Ora;\n}): Promise<string> {\n if (template) {\n const expName = exp.name;\n const { type, uri } = template;\n if (type === 'file') {\n return await extractLocalNpmTarballAsync(uri, templateDirectory, {\n expName,\n });\n } else if (type === 'npm') {\n return await downloadAndExtractNpmModuleAsync(uri, templateDirectory, {\n expName,\n });\n } else if (type === 'repository') {\n return await resolveAndDownloadRepoTemplateAsync(templateDirectory, ora, expName, uri);\n } else {\n throw new Error(`Unknown template type: ${type}`);\n }\n } else {\n try {\n return await resolveLocalTemplateAsync({ templateDirectory, projectRoot, exp });\n } catch (error: any) {\n const templatePackageName = getTemplateNpmPackageNameFromSdkVersion(exp.sdkVersion);\n debug('Fallback to SDK template:', templatePackageName);\n return await downloadAndExtractNpmModuleAsync(templatePackageName, templateDirectory, {\n expName: exp.name,\n });\n }\n }\n}\n\n/** Given an `sdkVersion` like `44.0.0` return a fully qualified NPM package name like: `expo-template-bare-minimum@sdk-44` */\nfunction getTemplateNpmPackageNameFromSdkVersion(sdkVersion?: string): string {\n // When undefined or UNVERSIONED, we use the latest version.\n if (!sdkVersion || sdkVersion === 'UNVERSIONED') {\n Log.log('Using an unspecified Expo SDK version. The latest template will be used.');\n return `expo-template-bare-minimum@latest`;\n }\n return `expo-template-bare-minimum@sdk-${semver.major(sdkVersion)}`;\n}\n\nasync function getRepoInfo(url: any, examplePath?: string): Promise<RepoInfo | undefined> {\n const [, username, name, t, _branch, ...file] = url.pathname.split('/');\n const filePath = examplePath ? examplePath.replace(/^\\//, '') : file.join('/');\n\n // Support repos whose entire purpose is to be an example, e.g.\n // https://github.com/:username/:my-cool-example-repo-name.\n // Use the plain unauthenticated `fetch` so Expo credentials aren't forwarded to GitHub.\n if (t === undefined) {\n const infoResponse = await fetch(`https://api.github.com/repos/${username}/${name}`);\n if (infoResponse.status !== 200) {\n return;\n }\n const info: any = await infoResponse.json();\n return { username, name, branch: info['default_branch'], filePath };\n }\n\n // If examplePath is available, the branch name takes the entire path\n const branch = examplePath\n ? `${_branch}/${file.join('/')}`.replace(new RegExp(`/${filePath}|/$`), '')\n : _branch;\n\n if (username && name && branch && t === 'tree') {\n return { username, name, branch, filePath };\n }\n return undefined;\n}\n\nasync function hasRepo({ username, name, branch, filePath }: RepoInfo): Promise<boolean> {\n const contentsUrl = `https://api.github.com/repos/${username}/${name}/contents`;\n const packagePath = `${filePath ? `/${filePath}` : ''}/package.json`;\n\n try {\n const response = await fetch(contentsUrl + packagePath + `?ref=${branch}`);\n return response.ok;\n } catch {\n return false;\n }\n}\n\nasync function downloadAndExtractRepoAsync(\n { username, name, branch, filePath }: RepoInfo,\n output: string,\n props: { expName?: string }\n): Promise<string> {\n const url = `https://codeload.github.com/${username}/${name}/tar.gz/${branch}`;\n\n debug('Downloading tarball from:', url);\n\n // Extract the (sub)directory into non-empty path segments\n const directory = filePath.replace(/^\\//, '').split('/').filter(Boolean);\n // Remove the (sub)directory paths, and the root folder added by GitHub\n const strip = directory.length + 1;\n // Only extract the relevant (sub)directories, ignoring irrelevant files\n // The filder auto-ignores dotfiles, unless explicitly included\n const filter = createGlobFilter(\n !directory.length\n ? ['*/**', '*/ios/.xcode.env']\n : [`*/${directory.join('/')}/**`, `*/${directory.join('/')}/ios/.xcode.env`],\n {\n // Always ignore the `.xcworkspace` folder\n ignore: ['**/ios/*.xcworkspace/**'],\n }\n );\n\n return await extractNpmTarballFromUrlAsync(url, output, {\n ...props,\n strip,\n filter,\n });\n}\n\nasync function resolveAndDownloadRepoTemplateAsync(\n templateDirectory: string,\n oraInstance: Ora,\n expName: string,\n template: string,\n templatePath?: string\n) {\n let repoUrl: URL | undefined;\n\n try {\n repoUrl = new URL(template);\n } catch (error: any) {\n if (error.code !== 'ERR_INVALID_URL') {\n oraInstance.fail(error);\n throw error;\n }\n }\n if (!repoUrl) {\n oraInstance.fail(`Invalid URL: ${chalk.red(`\"${template}\"`)}. Try again with a valid URL.`);\n throw new AbortCommandError();\n }\n\n if (repoUrl.origin !== 'https://github.com') {\n oraInstance.fail(\n `Invalid URL: ${chalk.red(\n `\"${template}\"`\n )}. Only GitHub repositories are supported. Try again with a valid GitHub URL.`\n );\n throw new AbortCommandError();\n }\n\n const repoInfo = await getRepoInfo(repoUrl, templatePath);\n\n if (!repoInfo) {\n oraInstance.fail(\n `Found invalid GitHub URL: ${chalk.red(`\"${template}\"`)}. Fix the URL and try again.`\n );\n throw new AbortCommandError();\n }\n\n const found = await hasRepo(repoInfo);\n\n if (!found) {\n oraInstance.fail(\n `Could not locate the repository for ${chalk.red(\n `\"${template}\"`\n )}. Check that the repository exists and try again.`\n );\n throw new AbortCommandError();\n }\n\n oraInstance.text = chalk.bold(\n `Downloading files from repo ${chalk.cyan(template)}. This might take a moment.`\n );\n\n return await downloadAndExtractRepoAsync(repoInfo, templateDirectory, { expName });\n}\n"],"names":["cloneTemplateAsync","debug","require","templateDirectory","projectRoot","template","exp","ora","expName","name","type","uri","extractLocalNpmTarballAsync","downloadAndExtractNpmModuleAsync","resolveAndDownloadRepoTemplateAsync","Error","resolveLocalTemplateAsync","error","templatePackageName","getTemplateNpmPackageNameFromSdkVersion","sdkVersion","Log","log","semver","major","getRepoInfo","url","examplePath","username","t","_branch","file","pathname","split","filePath","replace","join","undefined","infoResponse","fetch","status","info","json","branch","RegExp","hasRepo","contentsUrl","packagePath","response","ok","downloadAndExtractRepoAsync","output","props","directory","filter","Boolean","strip","length","createGlobFilter","ignore","extractNpmTarballFromUrlAsync","oraInstance","templatePath","repoUrl","URL","code","fail","chalk","red","AbortCommandError","origin","repoInfo","found","text","bold","cyan"],"mappings":"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"}
|
|
@@ -17,6 +17,9 @@ function _configplugins() {
|
|
|
17
17
|
}
|
|
18
18
|
const _AndroidAppIdResolver = require("../../start/platforms/android/AndroidAppIdResolver");
|
|
19
19
|
const _errors = require("../../utils/errors");
|
|
20
|
+
function resolveCustomLaunchActivity(packageName, mainActivity) {
|
|
21
|
+
return mainActivity.startsWith('.') ? `${packageName}${mainActivity}` : mainActivity;
|
|
22
|
+
}
|
|
20
23
|
async function getMainActivityAsync(projectRoot) {
|
|
21
24
|
const filePath = await _configplugins().AndroidConfig.Paths.getAndroidManifestAsync(projectRoot);
|
|
22
25
|
const androidManifest = await _configplugins().AndroidConfig.Manifest.readAndroidManifestAsync(filePath);
|
|
@@ -34,7 +37,7 @@ async function resolveLaunchPropsAsync(projectRoot, options) {
|
|
|
34
37
|
const mainActivity = await getMainActivityAsync(projectRoot);
|
|
35
38
|
const packageName = await new _AndroidAppIdResolver.AndroidAppIdResolver(projectRoot).getAppIdFromNativeAsync();
|
|
36
39
|
const customAppId = options.appId;
|
|
37
|
-
const launchActivity = customAppId && customAppId !== packageName ? `${customAppId}/${packageName
|
|
40
|
+
const launchActivity = customAppId && customAppId !== packageName ? `${customAppId}/${resolveCustomLaunchActivity(packageName, mainActivity)}` : `${packageName}/${mainActivity}`;
|
|
38
41
|
return {
|
|
39
42
|
mainActivity,
|
|
40
43
|
launchActivity,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/run/android/resolveLaunchProps.ts"],"sourcesContent":["import { AndroidConfig } from '@expo/config-plugins';\n\nimport { AndroidAppIdResolver } from '../../start/platforms/android/AndroidAppIdResolver';\nimport { CommandError } from '../../utils/errors';\n\nexport interface LaunchProps {\n /**\n * The \"common\" Android package name, configured through the app manifest.\n * @see https://source.android.com/docs/core/architecture/hidl/code-style#package-names\n */\n packageName: string;\n /**\n * Optional customized application ID, used in product flavors.\n * @see https://developer.android.com/build/build-variants#change-app-id\n */\n customAppId?: string;\n /**\n * The main activity to launch, by default this is `.MainActivity`.\n * @see https://github.com/expo/expo/blob/c0aec226a43c0f186258a063a6145c3e52246f8a/templates/expo-template-bare-minimum/android/app/src/main/AndroidManifest.xml#L22\n */\n mainActivity: string;\n /**\n * The full launch activity reference used in the app intent to launch the app with `adb am start -n <launchActivity>`.\n * Usually, this is structured as `<package-name>/.<activity-name>`.\n * For product flavors, this is structured as `<custom-app-id>/<package-name>.<activity-name>`.\n * @see https://developer.android.com/studio/command-line/adb#IntentSpec\n */\n launchActivity: string;\n}\n\nasync function getMainActivityAsync(projectRoot: string): Promise<string> {\n const filePath = await AndroidConfig.Paths.getAndroidManifestAsync(projectRoot);\n const androidManifest = await AndroidConfig.Manifest.readAndroidManifestAsync(filePath);\n const runnableActivity = AndroidConfig.Manifest.getRunnableActivity(androidManifest);\n if (runnableActivity) {\n return runnableActivity.$['android:name'];\n }\n const mainActivity = AndroidConfig.Manifest.getMainActivity(androidManifest);\n if (!mainActivity) {\n throw new CommandError(\n 'ANDROID_MALFORMED',\n `${filePath} is missing a runnable activity element.`\n );\n }\n return mainActivity.$['android:name'];\n}\n\nexport async function resolveLaunchPropsAsync(\n projectRoot: string,\n options: { appId?: string }\n): Promise<LaunchProps> {\n const mainActivity = await getMainActivityAsync(projectRoot);\n const packageName = await new AndroidAppIdResolver(projectRoot).getAppIdFromNativeAsync();\n const customAppId = options.appId;\n\n const launchActivity =\n customAppId && customAppId !== packageName\n ? `${customAppId}/${packageName
|
|
1
|
+
{"version":3,"sources":["../../../../src/run/android/resolveLaunchProps.ts"],"sourcesContent":["import { AndroidConfig } from '@expo/config-plugins';\n\nimport { AndroidAppIdResolver } from '../../start/platforms/android/AndroidAppIdResolver';\nimport { CommandError } from '../../utils/errors';\n\nexport interface LaunchProps {\n /**\n * The \"common\" Android package name, configured through the app manifest.\n * @see https://source.android.com/docs/core/architecture/hidl/code-style#package-names\n */\n packageName: string;\n /**\n * Optional customized application ID, used in product flavors.\n * @see https://developer.android.com/build/build-variants#change-app-id\n */\n customAppId?: string;\n /**\n * The main activity to launch, by default this is `.MainActivity`.\n * @see https://github.com/expo/expo/blob/c0aec226a43c0f186258a063a6145c3e52246f8a/templates/expo-template-bare-minimum/android/app/src/main/AndroidManifest.xml#L22\n */\n mainActivity: string;\n /**\n * The full launch activity reference used in the app intent to launch the app with `adb am start -n <launchActivity>`.\n * Usually, this is structured as `<package-name>/.<activity-name>`.\n * For product flavors, this is structured as `<custom-app-id>/<package-name>.<activity-name>`.\n * @see https://developer.android.com/studio/command-line/adb#IntentSpec\n */\n launchActivity: string;\n}\n\nfunction resolveCustomLaunchActivity(packageName: string, mainActivity: string): string {\n return mainActivity.startsWith('.') ? `${packageName}${mainActivity}` : mainActivity;\n}\n\nasync function getMainActivityAsync(projectRoot: string): Promise<string> {\n const filePath = await AndroidConfig.Paths.getAndroidManifestAsync(projectRoot);\n const androidManifest = await AndroidConfig.Manifest.readAndroidManifestAsync(filePath);\n const runnableActivity = AndroidConfig.Manifest.getRunnableActivity(androidManifest);\n if (runnableActivity) {\n return runnableActivity.$['android:name'];\n }\n const mainActivity = AndroidConfig.Manifest.getMainActivity(androidManifest);\n if (!mainActivity) {\n throw new CommandError(\n 'ANDROID_MALFORMED',\n `${filePath} is missing a runnable activity element.`\n );\n }\n return mainActivity.$['android:name'];\n}\n\nexport async function resolveLaunchPropsAsync(\n projectRoot: string,\n options: { appId?: string }\n): Promise<LaunchProps> {\n const mainActivity = await getMainActivityAsync(projectRoot);\n const packageName = await new AndroidAppIdResolver(projectRoot).getAppIdFromNativeAsync();\n const customAppId = options.appId;\n\n const launchActivity =\n customAppId && customAppId !== packageName\n ? `${customAppId}/${resolveCustomLaunchActivity(packageName, mainActivity)}`\n : `${packageName}/${mainActivity}`;\n\n return {\n mainActivity,\n launchActivity,\n packageName,\n customAppId,\n };\n}\n"],"names":["resolveLaunchPropsAsync","resolveCustomLaunchActivity","packageName","mainActivity","startsWith","getMainActivityAsync","projectRoot","filePath","AndroidConfig","Paths","getAndroidManifestAsync","androidManifest","Manifest","readAndroidManifestAsync","runnableActivity","getRunnableActivity","$","getMainActivity","CommandError","options","AndroidAppIdResolver","getAppIdFromNativeAsync","customAppId","appId","launchActivity"],"mappings":";;;;+BAmDsBA;;;eAAAA;;;;yBAnDQ;;;;;;sCAEO;wBACR;AA2B7B,SAASC,4BAA4BC,WAAmB,EAAEC,YAAoB;IAC5E,OAAOA,aAAaC,UAAU,CAAC,OAAO,GAAGF,cAAcC,cAAc,GAAGA;AAC1E;AAEA,eAAeE,qBAAqBC,WAAmB;IACrD,MAAMC,WAAW,MAAMC,8BAAa,CAACC,KAAK,CAACC,uBAAuB,CAACJ;IACnE,MAAMK,kBAAkB,MAAMH,8BAAa,CAACI,QAAQ,CAACC,wBAAwB,CAACN;IAC9E,MAAMO,mBAAmBN,8BAAa,CAACI,QAAQ,CAACG,mBAAmB,CAACJ;IACpE,IAAIG,kBAAkB;QACpB,OAAOA,iBAAiBE,CAAC,CAAC,eAAe;IAC3C;IACA,MAAMb,eAAeK,8BAAa,CAACI,QAAQ,CAACK,eAAe,CAACN;IAC5D,IAAI,CAACR,cAAc;QACjB,MAAM,IAAIe,oBAAY,CACpB,qBACA,GAAGX,SAAS,wCAAwC,CAAC;IAEzD;IACA,OAAOJ,aAAaa,CAAC,CAAC,eAAe;AACvC;AAEO,eAAehB,wBACpBM,WAAmB,EACnBa,OAA2B;IAE3B,MAAMhB,eAAe,MAAME,qBAAqBC;IAChD,MAAMJ,cAAc,MAAM,IAAIkB,0CAAoB,CAACd,aAAae,uBAAuB;IACvF,MAAMC,cAAcH,QAAQI,KAAK;IAEjC,MAAMC,iBACJF,eAAeA,gBAAgBpB,cAC3B,GAAGoB,YAAY,CAAC,EAAErB,4BAA4BC,aAAaC,eAAe,GAC1E,GAAGD,YAAY,CAAC,EAAEC,cAAc;IAEtC,OAAO;QACLA;QACAqB;QACAtB;QACAoB;IACF;AACF"}
|
|
@@ -15,6 +15,9 @@ _export(exports, {
|
|
|
15
15
|
adbArgs: function() {
|
|
16
16
|
return adbArgs;
|
|
17
17
|
},
|
|
18
|
+
adbShellArgs: function() {
|
|
19
|
+
return adbShellArgs;
|
|
20
|
+
},
|
|
18
21
|
getAdbNameForDeviceIdAsync: function() {
|
|
19
22
|
return getAdbNameForDeviceIdAsync;
|
|
20
23
|
},
|
|
@@ -159,7 +162,7 @@ function logUnauthorized(device) {
|
|
|
159
162
|
_log.warn(`\nThis computer is not authorized for developing on ${_chalk().default.bold(device.name)}. ${_chalk().default.dim((0, _link.learnMore)('https://expo.fyi/authorize-android-device'))}`);
|
|
160
163
|
}
|
|
161
164
|
async function isPackageInstalledAsync(device, androidPackage) {
|
|
162
|
-
const packages = await getServer().runAsync(
|
|
165
|
+
const packages = await getServer().runAsync(adbShellArgs(device.pid, 'pm', 'list', 'packages', '--user', _env.env.EXPO_ADB_USER, androidPackage));
|
|
163
166
|
const lines = packages.split(/\r?\n/);
|
|
164
167
|
for(let i = 0; i < lines.length; i++){
|
|
165
168
|
const line = lines[i].trim();
|
|
@@ -170,8 +173,7 @@ async function isPackageInstalledAsync(device, androidPackage) {
|
|
|
170
173
|
return false;
|
|
171
174
|
}
|
|
172
175
|
async function launchActivityAsync(device, { launchActivity, url }) {
|
|
173
|
-
const
|
|
174
|
-
'shell',
|
|
176
|
+
const command = [
|
|
175
177
|
'am',
|
|
176
178
|
'start',
|
|
177
179
|
// FLAG_ACTIVITY_SINGLE_TOP -- If set, the activity will not be launched if it is already running at the top of the history stack.
|
|
@@ -182,13 +184,12 @@ async function launchActivityAsync(device, { launchActivity, url }) {
|
|
|
182
184
|
launchActivity
|
|
183
185
|
];
|
|
184
186
|
if (url) {
|
|
185
|
-
|
|
187
|
+
command.push('-d', url);
|
|
186
188
|
}
|
|
187
|
-
return openAsync(
|
|
189
|
+
return openAsync(adbShellArgs(device.pid, ...command));
|
|
188
190
|
}
|
|
189
191
|
async function openUrlAsync(device, { url }) {
|
|
190
|
-
return openAsync(
|
|
191
|
-
url.replace(/&/g, String.raw`\&`)));
|
|
192
|
+
return openAsync(adbShellArgs(device.pid, 'am', 'start', '-a', 'android.intent.action.VIEW', '-d', url));
|
|
192
193
|
}
|
|
193
194
|
/** Runs a generic command watches for common errors in order to throw with an expected code. */ async function openAsync(args) {
|
|
194
195
|
const results = await getServer().runAsync(args);
|
|
@@ -201,7 +202,7 @@ async function uninstallAsync(device, { appId }) {
|
|
|
201
202
|
return await getServer().runAsync(adbArgs(device.pid, 'uninstall', '--user', _env.env.EXPO_ADB_USER, appId));
|
|
202
203
|
}
|
|
203
204
|
async function getPackageInfoAsync(device, { appId }) {
|
|
204
|
-
return await getServer().runAsync(
|
|
205
|
+
return await getServer().runAsync(adbShellArgs(device.pid, 'dumpsys', 'package', appId));
|
|
205
206
|
}
|
|
206
207
|
async function installAsync(device, { filePath }) {
|
|
207
208
|
// TODO: Handle the `INSTALL_FAILED_INSUFFICIENT_STORAGE` error.
|
|
@@ -214,6 +215,12 @@ function adbArgs(pid, ...options) {
|
|
|
214
215
|
}
|
|
215
216
|
return args.concat(options);
|
|
216
217
|
}
|
|
218
|
+
function adbShellArgs(pid, ...command) {
|
|
219
|
+
return adbArgs(pid, 'shell', ...command.map(shellQuote));
|
|
220
|
+
}
|
|
221
|
+
function shellQuote(value) {
|
|
222
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
223
|
+
}
|
|
217
224
|
async function getAttachedDevicesAsync() {
|
|
218
225
|
const output = await getServer().runAsync([
|
|
219
226
|
'devices',
|
|
@@ -325,13 +332,7 @@ async function getDeviceABIsAsync(device) {
|
|
|
325
332
|
];
|
|
326
333
|
}
|
|
327
334
|
async function getPropertyDataForDeviceAsync(device, prop) {
|
|
328
|
-
|
|
329
|
-
const propCommand = adbArgs(...[
|
|
330
|
-
device.pid,
|
|
331
|
-
'shell',
|
|
332
|
-
'getprop',
|
|
333
|
-
prop
|
|
334
|
-
].filter(Boolean));
|
|
335
|
+
const propCommand = prop ? adbShellArgs(device.pid, 'getprop', prop) : adbShellArgs(device.pid, 'getprop');
|
|
335
336
|
try {
|
|
336
337
|
// Prevent reading as UTF8.
|
|
337
338
|
const results = await getServer().getFileOutputAsync(propCommand);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/start/platforms/android/adb.ts"],"sourcesContent":["import chalk from 'chalk';\nimport os from 'os';\n\nimport { ADBServer } from './ADBServer';\nimport * as Log from '../../../log';\nimport { env } from '../../../utils/env';\nimport { CommandError } from '../../../utils/errors';\nimport { learnMore } from '../../../utils/link';\n\nconst debug = require('debug')('expo:start:platforms:android:adb') as typeof console.log;\n\nexport enum DeviceABI {\n // The arch specific android target platforms are soft-deprecated.\n // Instead of using TargetPlatform as a combination arch + platform\n // the code will be updated to carry arch information in [DarwinArch]\n // and [AndroidArch].\n arm = 'arm',\n arm64 = 'arm64',\n x64 = 'x64',\n x86 = 'x86',\n x8664 = 'x86_64',\n arm64v8a = 'arm64-v8a',\n armeabiV7a = 'armeabi-v7a',\n armeabi = 'armeabi',\n universal = 'universal',\n}\n\n/** Represents a connected Android device. */\nexport type Device = {\n /** Process ID. */\n pid?: string;\n /** Name of the device, also used as the ID for opening devices. */\n name: string;\n /** Is emulator or connected device. */\n type: 'emulator' | 'device';\n /** Is the device booted (emulator). */\n isBooted: boolean;\n /** Is device authorized for developing. https://expo.fyi/authorize-android-device */\n isAuthorized: boolean;\n /** The connection type to ADB, only available when `type: device` */\n connectionType?: 'USB' | 'Network';\n};\n\ntype DeviceContext = Pick<Device, 'pid'>;\n\ntype DeviceProperties = Record<string, string>;\n\nconst CANT_START_ACTIVITY_ERROR = 'Activity not started, unable to resolve Intent';\n// http://developer.android.com/ndk/guides/abis.html\nconst PROP_CPU_NAME = 'ro.product.cpu.abi';\n\nconst PROP_CPU_ABI_LIST_NAME = 'ro.product.cpu.abilist';\n\n// Can sometimes be null\n// http://developer.android.com/ndk/guides/abis.html\nconst PROP_BOOT_ANIMATION_STATE = 'init.svc.bootanim';\n\nlet _server: ADBServer | null;\n\n/** Return the lazily loaded ADB server instance. */\nexport function getServer() {\n _server ??= new ADBServer();\n return _server;\n}\n\n/** Logs an FYI message about authorizing your device. */\nexport function logUnauthorized(device: Device) {\n Log.warn(\n `\\nThis computer is not authorized for developing on ${chalk.bold(device.name)}. ${chalk.dim(\n learnMore('https://expo.fyi/authorize-android-device')\n )}`\n );\n}\n\n/** Returns true if the provided package name is installed on the provided Android device. */\nexport async function isPackageInstalledAsync(\n device: DeviceContext,\n androidPackage: string\n): Promise<boolean> {\n const packages = await getServer().runAsync(\n adbArgs(\n device.pid,\n 'shell',\n 'pm',\n 'list',\n 'packages',\n '--user',\n env.EXPO_ADB_USER,\n androidPackage\n )\n );\n\n const lines = packages.split(/\\r?\\n/);\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line === `package:${androidPackage}`) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * @param device.pid Process ID of the Android device to launch.\n * @param props.launchActivity Activity to launch `[application identifier]/.[main activity name]`, ex: `com.bacon.app/.MainActivity`\n * @param props.url Optional (dev client) URL to launch\n */\nexport async function launchActivityAsync(\n device: DeviceContext,\n {\n launchActivity,\n url,\n }: {\n launchActivity: string;\n url?: string;\n }\n) {\n const args: string[] = [\n 'shell',\n 'am',\n 'start',\n // FLAG_ACTIVITY_SINGLE_TOP -- If set, the activity will not be launched if it is already running at the top of the history stack.\n '-f',\n '0x20000000',\n // Activity to open first: com.bacon.app/.MainActivity\n '-n',\n launchActivity,\n ];\n\n if (url) {\n args.push('-d', url);\n }\n\n return openAsync(adbArgs(device.pid, ...args));\n}\n\n/**\n * @param device.pid Process ID of the Android device to launch.\n * @param props.url URL to launch.\n */\nexport async function openUrlAsync(\n device: DeviceContext,\n {\n url,\n }: {\n url: string;\n }\n) {\n return openAsync(\n adbArgs(\n device.pid,\n 'shell',\n 'am',\n 'start',\n '-a',\n 'android.intent.action.VIEW',\n '-d',\n // ADB requires ampersands to be escaped.\n url.replace(/&/g, String.raw`\\&`)\n )\n );\n}\n\n/** Runs a generic command watches for common errors in order to throw with an expected code. */\nasync function openAsync(args: string[]): Promise<string> {\n const results = await getServer().runAsync(args);\n if (\n results.includes(CANT_START_ACTIVITY_ERROR) ||\n results.match(/Error: Activity class .* does not exist\\./g)\n ) {\n throw new CommandError('APP_NOT_INSTALLED', results.substring(results.indexOf('Error: ')));\n }\n return results;\n}\n\n/** Uninstall an app given its Android package name. */\nexport async function uninstallAsync(\n device: DeviceContext,\n { appId }: { appId: string }\n): Promise<string> {\n return await getServer().runAsync(\n adbArgs(device.pid, 'uninstall', '--user', env.EXPO_ADB_USER, appId)\n );\n}\n\n/** Get package info from an app based on its Android package name. */\nexport async function getPackageInfoAsync(\n device: DeviceContext,\n { appId }: { appId: string }\n): Promise<string> {\n return await getServer().runAsync(adbArgs(device.pid, 'shell', 'dumpsys', 'package', appId));\n}\n\n/** Install an app on a connected device. */\nexport async function installAsync(device: DeviceContext, { filePath }: { filePath: string }) {\n // TODO: Handle the `INSTALL_FAILED_INSUFFICIENT_STORAGE` error.\n return await getServer().runAsync(\n adbArgs(device.pid, 'install', '-r', '-d', '--user', env.EXPO_ADB_USER, filePath)\n );\n}\n\n/** Format ADB args with process ID. */\nexport function adbArgs(pid: Device['pid'], ...options: string[]): string[] {\n const args = [];\n if (pid) {\n args.push('-s', pid);\n }\n\n return args.concat(options);\n}\n\n// TODO: This is very expensive for some operations.\nexport async function getAttachedDevicesAsync(): Promise<Device[]> {\n const output = await getServer().runAsync(['devices', '-l']);\n\n const splitItems = output\n .trim()\n .replace(/\\n$/, '')\n .split(os.EOL)\n // Filter ADB trace logs from the output, e.g.\n // adb D 03-06 15:25:53 63677 4018815 adb_client.cpp:393] adb_query: host:devices-l\n // 03-04 12:29:44.557 16415 16415 D adb : commandline.cpp:1646 Using server socket: tcp:172.27.192.1:5037\n // 03-04 12:29:44.557 16415 16415 D adb : adb_client.cpp:160 _adb_connect: host:version\n .filter((line) => !line.match(/\\.cpp:[0-9]+/));\n\n // First line is `\"List of devices attached\"`, remove it\n // @ts-ignore: todo\n const attachedDevices: {\n props: string[];\n type: Device['type'];\n isAuthorized: Device['isAuthorized'];\n isBooted: Device['isBooted'];\n connectionType?: Device['connectionType'];\n }[] = splitItems\n .slice(1, splitItems.length)\n .map((line) => {\n // unauthorized: ['FA8251A00719', 'unauthorized', 'usb:338690048X', 'transport_id:5']\n // authorized: ['FA8251A00719', 'device', 'usb:336592896X', 'product:walleye', 'model:Pixel_2', 'device:walleye', 'transport_id:4']\n // emulator: ['emulator-5554', 'offline', 'transport_id:1']\n const props = line.split(' ').filter(Boolean);\n const type = line.includes('emulator') ? 'emulator' : 'device';\n\n let connectionType;\n if (type === 'device' && line.includes('usb:')) {\n connectionType = 'USB';\n } else if (type === 'device' && line.includes('_adb-tls-connect.')) {\n connectionType = 'Network';\n }\n\n const isBooted = type === 'emulator' || props[1] !== 'offline';\n const isAuthorized =\n connectionType === 'Network'\n ? line.includes('model:') // Network connected devices show `model:<name>` when authorized\n : props[1] !== 'unauthorized';\n\n return { props, type, isAuthorized, isBooted, connectionType };\n })\n .filter(({ props: [pid] }) => !!pid);\n\n const devicePromises = attachedDevices.map<Promise<Device>>(async (props) => {\n const {\n type,\n props: [pid, ...deviceInfo],\n isAuthorized,\n isBooted,\n } = props;\n\n let name: string | null = null;\n\n if (type === 'device') {\n if (isAuthorized) {\n // Possibly formatted like `model:Pixel_2`\n // Transform to `Pixel_2`\n const modelItem = deviceInfo.find((info) => info.includes('model:'));\n if (modelItem) {\n name = modelItem.replace('model:', '');\n }\n }\n // unauthorized devices don't have a name available to read\n if (!name) {\n // Device FA8251A00719\n name = `Device ${pid}`;\n }\n } else {\n // Given an emulator pid, get the emulator name which can be used to start the emulator later.\n name = (await getAdbNameForDeviceIdAsync({ pid })) ?? '';\n }\n\n return props.connectionType\n ? { pid, name, type, isAuthorized, isBooted, connectionType: props.connectionType }\n : { pid, name, type, isAuthorized, isBooted };\n });\n\n return Promise.all(devicePromises);\n}\n\n/**\n * Return the Emulator name for an emulator ID, this can be used to determine if an emulator is booted.\n *\n * @param device.pid a value like `emulator-5554` from `abd devices`\n */\nexport async function getAdbNameForDeviceIdAsync(device: DeviceContext): Promise<string | null> {\n const results = await getServer().runAsync(adbArgs(device.pid, 'emu', 'avd', 'name'));\n\n if (results.match(/could not connect to TCP port .*: Connection refused/)) {\n // Can also occur when the emulator does not exist.\n throw new CommandError('EMULATOR_NOT_FOUND', results);\n }\n\n return sanitizeAdbDeviceName(results) ?? null;\n}\n\nexport async function isDeviceBootedAsync({\n name,\n}: { name?: string } = {}): Promise<Device | null> {\n const devices = await getAttachedDevicesAsync();\n\n if (!name) {\n return devices[0] ?? null;\n }\n\n return devices.find((device) => device.name === name) ?? null;\n}\n\n/**\n * Returns true when a device's splash screen animation has stopped.\n * This can be used to detect when a device is fully booted and ready to use.\n *\n * @param pid\n */\nexport async function isBootAnimationCompleteAsync(pid?: string): Promise<boolean> {\n try {\n const props = await getPropertyDataForDeviceAsync({ pid }, PROP_BOOT_ANIMATION_STATE);\n return !!props[PROP_BOOT_ANIMATION_STATE].match(/stopped/);\n } catch {\n return false;\n }\n}\n\n/** Get a list of ABIs for the provided device. */\nexport async function getDeviceABIsAsync(\n device: Pick<Device, 'name' | 'pid'>\n): Promise<DeviceABI[]> {\n const cpuAbiList = (await getPropertyDataForDeviceAsync(device, PROP_CPU_ABI_LIST_NAME))[\n PROP_CPU_ABI_LIST_NAME\n ];\n\n if (cpuAbiList) {\n return cpuAbiList.trim().split(',') as DeviceABI[];\n }\n\n const abi = (await getPropertyDataForDeviceAsync(device, PROP_CPU_NAME))[\n PROP_CPU_NAME\n ] as DeviceABI;\n return [abi];\n}\n\nexport async function getPropertyDataForDeviceAsync(\n device: DeviceContext,\n prop?: string\n): Promise<DeviceProperties> {\n // @ts-ignore\n const propCommand = adbArgs(...[device.pid, 'shell', 'getprop', prop].filter(Boolean));\n try {\n // Prevent reading as UTF8.\n const results = await getServer().getFileOutputAsync(propCommand);\n // Like:\n // [wifi.direct.interface]: [p2p-dev-wlan0]\n // [wifi.interface]: [wlan0]\n\n if (prop) {\n debug(`Property data: (device pid: ${device.pid}, prop: ${prop}, data: ${results})`);\n return {\n [prop]: results,\n };\n }\n const props = parseAdbDeviceProperties(results);\n\n debug(`Parsed data:`, props);\n\n return props;\n } catch (error: any) {\n // TODO: Ensure error has message and not stderr\n throw new CommandError(`Failed to get properties for device (${device.pid}): ${error.message}`);\n }\n}\n\nfunction parseAdbDeviceProperties(devicePropertiesString: string) {\n const properties: DeviceProperties = {};\n const propertyExp = /\\[(.*?)\\]: \\[(.*?)\\]/gm;\n for (const match of devicePropertiesString.matchAll(propertyExp)) {\n properties[match[1]] = match[2];\n }\n return properties;\n}\n\n/**\n * Sanitize the ADB device name to only get the actual device name.\n * On Windows, we need to do \\r, \\n, and \\r\\n filtering to get the name.\n */\nexport function sanitizeAdbDeviceName(deviceName: string) {\n return deviceName\n .trim()\n .split(/[\\r\\n]+/)\n .shift();\n}\n"],"names":["DeviceABI","adbArgs","getAdbNameForDeviceIdAsync","getAttachedDevicesAsync","getDeviceABIsAsync","getPackageInfoAsync","getPropertyDataForDeviceAsync","getServer","installAsync","isBootAnimationCompleteAsync","isDeviceBootedAsync","isPackageInstalledAsync","launchActivityAsync","logUnauthorized","openUrlAsync","sanitizeAdbDeviceName","uninstallAsync","debug","require","CANT_START_ACTIVITY_ERROR","PROP_CPU_NAME","PROP_CPU_ABI_LIST_NAME","PROP_BOOT_ANIMATION_STATE","_server","ADBServer","device","Log","warn","chalk","bold","name","dim","learnMore","androidPackage","packages","runAsync","pid","env","EXPO_ADB_USER","lines","split","i","length","line","trim","launchActivity","url","args","push","openAsync","replace","String","raw","results","includes","match","CommandError","substring","indexOf","appId","filePath","options","concat","output","splitItems","os","EOL","filter","attachedDevices","slice","map","props","Boolean","type","connectionType","isBooted","isAuthorized","devicePromises","deviceInfo","modelItem","find","info","Promise","all","devices","cpuAbiList","abi","prop","propCommand","getFileOutputAsync","parseAdbDeviceProperties","error","message","devicePropertiesString","properties","propertyExp","matchAll","deviceName","shift"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/start/platforms/android/adb.ts"],"sourcesContent":["import chalk from 'chalk';\nimport os from 'os';\n\nimport { ADBServer } from './ADBServer';\nimport * as Log from '../../../log';\nimport { env } from '../../../utils/env';\nimport { CommandError } from '../../../utils/errors';\nimport { learnMore } from '../../../utils/link';\n\nconst debug = require('debug')('expo:start:platforms:android:adb') as typeof console.log;\n\nexport enum DeviceABI {\n // The arch specific android target platforms are soft-deprecated.\n // Instead of using TargetPlatform as a combination arch + platform\n // the code will be updated to carry arch information in [DarwinArch]\n // and [AndroidArch].\n arm = 'arm',\n arm64 = 'arm64',\n x64 = 'x64',\n x86 = 'x86',\n x8664 = 'x86_64',\n arm64v8a = 'arm64-v8a',\n armeabiV7a = 'armeabi-v7a',\n armeabi = 'armeabi',\n universal = 'universal',\n}\n\n/** Represents a connected Android device. */\nexport type Device = {\n /** Process ID. */\n pid?: string;\n /** Name of the device, also used as the ID for opening devices. */\n name: string;\n /** Is emulator or connected device. */\n type: 'emulator' | 'device';\n /** Is the device booted (emulator). */\n isBooted: boolean;\n /** Is device authorized for developing. https://expo.fyi/authorize-android-device */\n isAuthorized: boolean;\n /** The connection type to ADB, only available when `type: device` */\n connectionType?: 'USB' | 'Network';\n};\n\ntype DeviceContext = Pick<Device, 'pid'>;\n\ntype DeviceProperties = Record<string, string>;\n\nconst CANT_START_ACTIVITY_ERROR = 'Activity not started, unable to resolve Intent';\n// http://developer.android.com/ndk/guides/abis.html\nconst PROP_CPU_NAME = 'ro.product.cpu.abi';\n\nconst PROP_CPU_ABI_LIST_NAME = 'ro.product.cpu.abilist';\n\n// Can sometimes be null\n// http://developer.android.com/ndk/guides/abis.html\nconst PROP_BOOT_ANIMATION_STATE = 'init.svc.bootanim';\n\nlet _server: ADBServer | null;\n\n/** Return the lazily loaded ADB server instance. */\nexport function getServer() {\n _server ??= new ADBServer();\n return _server;\n}\n\n/** Logs an FYI message about authorizing your device. */\nexport function logUnauthorized(device: Device) {\n Log.warn(\n `\\nThis computer is not authorized for developing on ${chalk.bold(device.name)}. ${chalk.dim(\n learnMore('https://expo.fyi/authorize-android-device')\n )}`\n );\n}\n\n/** Returns true if the provided package name is installed on the provided Android device. */\nexport async function isPackageInstalledAsync(\n device: DeviceContext,\n androidPackage: string\n): Promise<boolean> {\n const packages = await getServer().runAsync(\n adbShellArgs(device.pid, 'pm', 'list', 'packages', '--user', env.EXPO_ADB_USER, androidPackage)\n );\n\n const lines = packages.split(/\\r?\\n/);\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line === `package:${androidPackage}`) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * @param device.pid Process ID of the Android device to launch.\n * @param props.launchActivity Activity to launch `[application identifier]/.[main activity name]`, ex: `com.bacon.app/.MainActivity`\n * @param props.url Optional (dev client) URL to launch\n */\nexport async function launchActivityAsync(\n device: DeviceContext,\n {\n launchActivity,\n url,\n }: {\n launchActivity: string;\n url?: string;\n }\n) {\n const command: string[] = [\n 'am',\n 'start',\n // FLAG_ACTIVITY_SINGLE_TOP -- If set, the activity will not be launched if it is already running at the top of the history stack.\n '-f',\n '0x20000000',\n // Activity to open first: com.bacon.app/.MainActivity\n '-n',\n launchActivity,\n ];\n\n if (url) {\n command.push('-d', url);\n }\n\n return openAsync(adbShellArgs(device.pid, ...command));\n}\n\n/**\n * @param device.pid Process ID of the Android device to launch.\n * @param props.url URL to launch.\n */\nexport async function openUrlAsync(\n device: DeviceContext,\n {\n url,\n }: {\n url: string;\n }\n) {\n return openAsync(\n adbShellArgs(device.pid, 'am', 'start', '-a', 'android.intent.action.VIEW', '-d', url)\n );\n}\n\n/** Runs a generic command watches for common errors in order to throw with an expected code. */\nasync function openAsync(args: string[]): Promise<string> {\n const results = await getServer().runAsync(args);\n if (\n results.includes(CANT_START_ACTIVITY_ERROR) ||\n results.match(/Error: Activity class .* does not exist\\./g)\n ) {\n throw new CommandError('APP_NOT_INSTALLED', results.substring(results.indexOf('Error: ')));\n }\n return results;\n}\n\n/** Uninstall an app given its Android package name. */\nexport async function uninstallAsync(\n device: DeviceContext,\n { appId }: { appId: string }\n): Promise<string> {\n return await getServer().runAsync(\n adbArgs(device.pid, 'uninstall', '--user', env.EXPO_ADB_USER, appId)\n );\n}\n\n/** Get package info from an app based on its Android package name. */\nexport async function getPackageInfoAsync(\n device: DeviceContext,\n { appId }: { appId: string }\n): Promise<string> {\n return await getServer().runAsync(adbShellArgs(device.pid, 'dumpsys', 'package', appId));\n}\n\n/** Install an app on a connected device. */\nexport async function installAsync(device: DeviceContext, { filePath }: { filePath: string }) {\n // TODO: Handle the `INSTALL_FAILED_INSUFFICIENT_STORAGE` error.\n return await getServer().runAsync(\n adbArgs(device.pid, 'install', '-r', '-d', '--user', env.EXPO_ADB_USER, filePath)\n );\n}\n\n/** Format ADB args with process ID. */\nexport function adbArgs(pid: Device['pid'], ...options: string[]): string[] {\n const args = [];\n if (pid) {\n args.push('-s', pid);\n }\n\n return args.concat(options);\n}\n\n/**\n * `adb shell` concatenates trailing args and runs the result through `sh -c` on\n * the device, so unquoted metacharacters in tainted tokens execute on-device.\n */\nexport function adbShellArgs(pid: Device['pid'], ...command: string[]): string[] {\n return adbArgs(pid, 'shell', ...command.map(shellQuote));\n}\n\nfunction shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\n// TODO: This is very expensive for some operations.\nexport async function getAttachedDevicesAsync(): Promise<Device[]> {\n const output = await getServer().runAsync(['devices', '-l']);\n\n const splitItems = output\n .trim()\n .replace(/\\n$/, '')\n .split(os.EOL)\n // Filter ADB trace logs from the output, e.g.\n // adb D 03-06 15:25:53 63677 4018815 adb_client.cpp:393] adb_query: host:devices-l\n // 03-04 12:29:44.557 16415 16415 D adb : commandline.cpp:1646 Using server socket: tcp:172.27.192.1:5037\n // 03-04 12:29:44.557 16415 16415 D adb : adb_client.cpp:160 _adb_connect: host:version\n .filter((line) => !line.match(/\\.cpp:[0-9]+/));\n\n // First line is `\"List of devices attached\"`, remove it\n // @ts-ignore: todo\n const attachedDevices: {\n props: string[];\n type: Device['type'];\n isAuthorized: Device['isAuthorized'];\n isBooted: Device['isBooted'];\n connectionType?: Device['connectionType'];\n }[] = splitItems\n .slice(1, splitItems.length)\n .map((line) => {\n // unauthorized: ['FA8251A00719', 'unauthorized', 'usb:338690048X', 'transport_id:5']\n // authorized: ['FA8251A00719', 'device', 'usb:336592896X', 'product:walleye', 'model:Pixel_2', 'device:walleye', 'transport_id:4']\n // emulator: ['emulator-5554', 'offline', 'transport_id:1']\n const props = line.split(' ').filter(Boolean);\n const type = line.includes('emulator') ? 'emulator' : 'device';\n\n let connectionType;\n if (type === 'device' && line.includes('usb:')) {\n connectionType = 'USB';\n } else if (type === 'device' && line.includes('_adb-tls-connect.')) {\n connectionType = 'Network';\n }\n\n const isBooted = type === 'emulator' || props[1] !== 'offline';\n const isAuthorized =\n connectionType === 'Network'\n ? line.includes('model:') // Network connected devices show `model:<name>` when authorized\n : props[1] !== 'unauthorized';\n\n return { props, type, isAuthorized, isBooted, connectionType };\n })\n .filter(({ props: [pid] }) => !!pid);\n\n const devicePromises = attachedDevices.map<Promise<Device>>(async (props) => {\n const {\n type,\n props: [pid, ...deviceInfo],\n isAuthorized,\n isBooted,\n } = props;\n\n let name: string | null = null;\n\n if (type === 'device') {\n if (isAuthorized) {\n // Possibly formatted like `model:Pixel_2`\n // Transform to `Pixel_2`\n const modelItem = deviceInfo.find((info) => info.includes('model:'));\n if (modelItem) {\n name = modelItem.replace('model:', '');\n }\n }\n // unauthorized devices don't have a name available to read\n if (!name) {\n // Device FA8251A00719\n name = `Device ${pid}`;\n }\n } else {\n // Given an emulator pid, get the emulator name which can be used to start the emulator later.\n name = (await getAdbNameForDeviceIdAsync({ pid })) ?? '';\n }\n\n return props.connectionType\n ? { pid, name, type, isAuthorized, isBooted, connectionType: props.connectionType }\n : { pid, name, type, isAuthorized, isBooted };\n });\n\n return Promise.all(devicePromises);\n}\n\n/**\n * Return the Emulator name for an emulator ID, this can be used to determine if an emulator is booted.\n *\n * @param device.pid a value like `emulator-5554` from `abd devices`\n */\nexport async function getAdbNameForDeviceIdAsync(device: DeviceContext): Promise<string | null> {\n const results = await getServer().runAsync(adbArgs(device.pid, 'emu', 'avd', 'name'));\n\n if (results.match(/could not connect to TCP port .*: Connection refused/)) {\n // Can also occur when the emulator does not exist.\n throw new CommandError('EMULATOR_NOT_FOUND', results);\n }\n\n return sanitizeAdbDeviceName(results) ?? null;\n}\n\nexport async function isDeviceBootedAsync({\n name,\n}: { name?: string } = {}): Promise<Device | null> {\n const devices = await getAttachedDevicesAsync();\n\n if (!name) {\n return devices[0] ?? null;\n }\n\n return devices.find((device) => device.name === name) ?? null;\n}\n\n/**\n * Returns true when a device's splash screen animation has stopped.\n * This can be used to detect when a device is fully booted and ready to use.\n *\n * @param pid\n */\nexport async function isBootAnimationCompleteAsync(pid?: string): Promise<boolean> {\n try {\n const props = await getPropertyDataForDeviceAsync({ pid }, PROP_BOOT_ANIMATION_STATE);\n return !!props[PROP_BOOT_ANIMATION_STATE].match(/stopped/);\n } catch {\n return false;\n }\n}\n\n/** Get a list of ABIs for the provided device. */\nexport async function getDeviceABIsAsync(\n device: Pick<Device, 'name' | 'pid'>\n): Promise<DeviceABI[]> {\n const cpuAbiList = (await getPropertyDataForDeviceAsync(device, PROP_CPU_ABI_LIST_NAME))[\n PROP_CPU_ABI_LIST_NAME\n ];\n\n if (cpuAbiList) {\n return cpuAbiList.trim().split(',') as DeviceABI[];\n }\n\n const abi = (await getPropertyDataForDeviceAsync(device, PROP_CPU_NAME))[\n PROP_CPU_NAME\n ] as DeviceABI;\n return [abi];\n}\n\nexport async function getPropertyDataForDeviceAsync(\n device: DeviceContext,\n prop?: string\n): Promise<DeviceProperties> {\n const propCommand = prop\n ? adbShellArgs(device.pid, 'getprop', prop)\n : adbShellArgs(device.pid, 'getprop');\n try {\n // Prevent reading as UTF8.\n const results = await getServer().getFileOutputAsync(propCommand);\n // Like:\n // [wifi.direct.interface]: [p2p-dev-wlan0]\n // [wifi.interface]: [wlan0]\n\n if (prop) {\n debug(`Property data: (device pid: ${device.pid}, prop: ${prop}, data: ${results})`);\n return {\n [prop]: results,\n };\n }\n const props = parseAdbDeviceProperties(results);\n\n debug(`Parsed data:`, props);\n\n return props;\n } catch (error: any) {\n // TODO: Ensure error has message and not stderr\n throw new CommandError(`Failed to get properties for device (${device.pid}): ${error.message}`);\n }\n}\n\nfunction parseAdbDeviceProperties(devicePropertiesString: string) {\n const properties: DeviceProperties = {};\n const propertyExp = /\\[(.*?)\\]: \\[(.*?)\\]/gm;\n for (const match of devicePropertiesString.matchAll(propertyExp)) {\n properties[match[1]] = match[2];\n }\n return properties;\n}\n\n/**\n * Sanitize the ADB device name to only get the actual device name.\n * On Windows, we need to do \\r, \\n, and \\r\\n filtering to get the name.\n */\nexport function sanitizeAdbDeviceName(deviceName: string) {\n return deviceName\n .trim()\n .split(/[\\r\\n]+/)\n .shift();\n}\n"],"names":["DeviceABI","adbArgs","adbShellArgs","getAdbNameForDeviceIdAsync","getAttachedDevicesAsync","getDeviceABIsAsync","getPackageInfoAsync","getPropertyDataForDeviceAsync","getServer","installAsync","isBootAnimationCompleteAsync","isDeviceBootedAsync","isPackageInstalledAsync","launchActivityAsync","logUnauthorized","openUrlAsync","sanitizeAdbDeviceName","uninstallAsync","debug","require","CANT_START_ACTIVITY_ERROR","PROP_CPU_NAME","PROP_CPU_ABI_LIST_NAME","PROP_BOOT_ANIMATION_STATE","_server","ADBServer","device","Log","warn","chalk","bold","name","dim","learnMore","androidPackage","packages","runAsync","pid","env","EXPO_ADB_USER","lines","split","i","length","line","trim","launchActivity","url","command","push","openAsync","args","results","includes","match","CommandError","substring","indexOf","appId","filePath","options","concat","map","shellQuote","value","replace","output","splitItems","os","EOL","filter","attachedDevices","slice","props","Boolean","type","connectionType","isBooted","isAuthorized","devicePromises","deviceInfo","modelItem","find","info","Promise","all","devices","cpuAbiList","abi","prop","propCommand","getFileOutputAsync","parseAdbDeviceProperties","error","message","devicePropertiesString","properties","propertyExp","matchAll","deviceName","shift"],"mappings":"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"}
|
|
@@ -8,21 +8,46 @@ Object.defineProperty(exports, "DevToolsPlugin", {
|
|
|
8
8
|
return DevToolsPlugin;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
|
+
function _nodefs() {
|
|
12
|
+
const data = /*#__PURE__*/ _interop_require_default(require("node:fs"));
|
|
13
|
+
_nodefs = function() {
|
|
14
|
+
return data;
|
|
15
|
+
};
|
|
16
|
+
return data;
|
|
17
|
+
}
|
|
11
18
|
const _DevToolsPluginschema = require("./DevToolsPlugin.schema");
|
|
12
19
|
const _DevToolsPluginCliExtensionExecutor = require("./DevToolsPluginCliExtensionExecutor");
|
|
13
20
|
const _DevToolsPluginManager = require("./DevToolsPluginManager");
|
|
21
|
+
const _dir = require("../../utils/dir");
|
|
22
|
+
function _interop_require_default(obj) {
|
|
23
|
+
return obj && obj.__esModule ? obj : {
|
|
24
|
+
default: obj
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const maybeRealpath = (target)=>{
|
|
28
|
+
try {
|
|
29
|
+
return _nodefs().default.realpathSync(target);
|
|
30
|
+
} catch {
|
|
31
|
+
return target;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
14
34
|
class DevToolsPlugin {
|
|
15
35
|
constructor(plugin, projectRoot){
|
|
16
36
|
this.plugin = plugin;
|
|
17
37
|
this.projectRoot = projectRoot;
|
|
18
38
|
this._executor = undefined;
|
|
19
|
-
// Validate configuration schema
|
|
20
39
|
const result = _DevToolsPluginschema.PluginSchema.safeParse(plugin);
|
|
21
40
|
if (!result.success) {
|
|
22
41
|
throw new Error(`Invalid plugin configuration: ${result.error.message}`, {
|
|
23
42
|
cause: result.error
|
|
24
43
|
});
|
|
25
44
|
}
|
|
45
|
+
if (plugin.webpageRoot != null) {
|
|
46
|
+
const webpageRoot = maybeRealpath(plugin.webpageRoot);
|
|
47
|
+
if (!(0, _dir.isPathInside)(webpageRoot, plugin.packageRoot)) {
|
|
48
|
+
throw new Error(`webpageRoot (${plugin.webpageRoot}) is not inside packageRoot (${plugin.packageRoot}).`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
26
51
|
}
|
|
27
52
|
get packageName() {
|
|
28
53
|
return this.plugin.packageName;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/start/server/DevToolsPlugin.ts"],"sourcesContent":["import { DevToolsPluginInfo, PluginSchema } from './DevToolsPlugin.schema';\nimport { DevToolsPluginCliExtensionExecutor } from './DevToolsPluginCliExtensionExecutor';\nimport { DevToolsPluginEndpoint } from './DevToolsPluginManager';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/start/server/DevToolsPlugin.ts"],"sourcesContent":["import fs from 'node:fs';\n\nimport { DevToolsPluginInfo, PluginSchema } from './DevToolsPlugin.schema';\nimport { DevToolsPluginCliExtensionExecutor } from './DevToolsPluginCliExtensionExecutor';\nimport { DevToolsPluginEndpoint } from './DevToolsPluginManager';\nimport { isPathInside } from '../../utils/dir';\n\nconst maybeRealpath = (target: string): string => {\n try {\n return fs.realpathSync(target);\n } catch {\n return target;\n }\n};\n\n/**\n * Class that represents a DevTools plugin with CLI and/or web extensions\n *\n * Responsibilities:\n * - Validates plugin configuration against schema\n * - Provides access to plugin metadata (name, description\n * , endpoints)\n * - Manages CLI command execution via DevToolsPluginExecutor\n * - Lazily initializes executor when needed\n * - Constructs web endpoint URLs based on server configuration\n */\nexport class DevToolsPlugin {\n constructor(\n private plugin: DevToolsPluginInfo,\n public readonly projectRoot: string\n ) {\n const result = PluginSchema.safeParse(plugin);\n if (!result.success) {\n throw new Error(`Invalid plugin configuration: ${result.error.message}`, {\n cause: result.error,\n });\n }\n\n if (plugin.webpageRoot != null) {\n const webpageRoot = maybeRealpath(plugin.webpageRoot);\n if (!isPathInside(webpageRoot, plugin.packageRoot)) {\n throw new Error(\n `webpageRoot (${plugin.webpageRoot}) is not inside packageRoot (${plugin.packageRoot}).`\n );\n }\n }\n }\n\n private _executor: DevToolsPluginCliExtensionExecutor | undefined = undefined;\n\n get packageName(): string {\n return this.plugin.packageName;\n }\n\n get packageRoot(): string {\n return this.plugin.packageRoot;\n }\n\n get webpageEndpoint(): string | undefined {\n return this.plugin?.webpageRoot\n ? `${DevToolsPluginEndpoint}/${this.plugin?.packageName}`\n : undefined;\n }\n\n get webpageRoot(): string | undefined {\n return this.plugin?.webpageRoot;\n }\n\n get description(): string {\n return this.plugin.cliExtensions?.description ?? '';\n }\n\n get cliExtensions(): DevToolsPluginInfo['cliExtensions'] {\n return this.plugin.cliExtensions;\n }\n\n get executor(): DevToolsPluginCliExtensionExecutor | undefined {\n if (!this.plugin.cliExtensions?.entryPoint) {\n return undefined;\n }\n\n if (!this._executor) {\n this._executor = new DevToolsPluginCliExtensionExecutor(this.plugin, this.projectRoot);\n }\n\n return this._executor;\n }\n}\n"],"names":["DevToolsPlugin","maybeRealpath","target","fs","realpathSync","constructor","plugin","projectRoot","_executor","undefined","result","PluginSchema","safeParse","success","Error","error","message","cause","webpageRoot","isPathInside","packageRoot","packageName","webpageEndpoint","DevToolsPluginEndpoint","description","cliExtensions","executor","entryPoint","DevToolsPluginCliExtensionExecutor"],"mappings":";;;;+BA0BaA;;;eAAAA;;;;gEA1BE;;;;;;sCAEkC;oDACE;uCACZ;qBACV;;;;;;AAE7B,MAAMC,gBAAgB,CAACC;IACrB,IAAI;QACF,OAAOC,iBAAE,CAACC,YAAY,CAACF;IACzB,EAAE,OAAM;QACN,OAAOA;IACT;AACF;AAaO,MAAMF;IACXK,YACE,AAAQC,MAA0B,EAClC,AAAgBC,WAAmB,CACnC;aAFQD,SAAAA;aACQC,cAAAA;aAmBVC,YAA4DC;QAjBlE,MAAMC,SAASC,kCAAY,CAACC,SAAS,CAACN;QACtC,IAAI,CAACI,OAAOG,OAAO,EAAE;YACnB,MAAM,IAAIC,MAAM,CAAC,8BAA8B,EAAEJ,OAAOK,KAAK,CAACC,OAAO,EAAE,EAAE;gBACvEC,OAAOP,OAAOK,KAAK;YACrB;QACF;QAEA,IAAIT,OAAOY,WAAW,IAAI,MAAM;YAC9B,MAAMA,cAAcjB,cAAcK,OAAOY,WAAW;YACpD,IAAI,CAACC,IAAAA,iBAAY,EAACD,aAAaZ,OAAOc,WAAW,GAAG;gBAClD,MAAM,IAAIN,MACR,CAAC,aAAa,EAAER,OAAOY,WAAW,CAAC,6BAA6B,EAAEZ,OAAOc,WAAW,CAAC,EAAE,CAAC;YAE5F;QACF;IACF;IAIA,IAAIC,cAAsB;QACxB,OAAO,IAAI,CAACf,MAAM,CAACe,WAAW;IAChC;IAEA,IAAID,cAAsB;QACxB,OAAO,IAAI,CAACd,MAAM,CAACc,WAAW;IAChC;IAEA,IAAIE,kBAAsC;YACjC,cAC0B;QADjC,OAAO,EAAA,eAAA,IAAI,CAAChB,MAAM,qBAAX,aAAaY,WAAW,IAC3B,GAAGK,6CAAsB,CAAC,CAAC,GAAE,gBAAA,IAAI,CAACjB,MAAM,qBAAX,cAAae,WAAW,EAAE,GACvDZ;IACN;IAEA,IAAIS,cAAkC;YAC7B;QAAP,QAAO,eAAA,IAAI,CAACZ,MAAM,qBAAX,aAAaY,WAAW;IACjC;IAEA,IAAIM,cAAsB;YACjB;QAAP,OAAO,EAAA,6BAAA,IAAI,CAAClB,MAAM,CAACmB,aAAa,qBAAzB,2BAA2BD,WAAW,KAAI;IACnD;IAEA,IAAIC,gBAAqD;QACvD,OAAO,IAAI,CAACnB,MAAM,CAACmB,aAAa;IAClC;IAEA,IAAIC,WAA2D;YACxD;QAAL,IAAI,GAAC,6BAAA,IAAI,CAACpB,MAAM,CAACmB,aAAa,qBAAzB,2BAA2BE,UAAU,GAAE;YAC1C,OAAOlB;QACT;QAEA,IAAI,CAAC,IAAI,CAACD,SAAS,EAAE;YACnB,IAAI,CAACA,SAAS,GAAG,IAAIoB,sEAAkC,CAAC,IAAI,CAACtB,MAAM,EAAE,IAAI,CAACC,WAAW;QACvF;QAEA,OAAO,IAAI,CAACC,SAAS;IACvB;AACF"}
|