@expo/build-tools 1.0.221 → 1.0.223

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.
@@ -13,7 +13,7 @@ async function installDependenciesAsync({ packageManager, env, logger, infoCallb
13
13
  let args;
14
14
  switch (packageManager) {
15
15
  case packageManager_1.PackageManager.NPM: {
16
- args = [useFrozenLockfile ? 'ci' : 'install'];
16
+ args = useFrozenLockfile ? ['ci', '--include=dev'] : ['install'];
17
17
  break;
18
18
  }
19
19
  case packageManager_1.PackageManager.PNPM: {
@@ -1 +1 @@
1
- {"version":3,"file":"installDependencies.js","sourceRoot":"","sources":["../../src/common/installDependencies.ts"],"names":[],"mappings":";;;;;AASA,4DAoDC;AAED,gDAYC;AA3ED,gDAAwB;AAGxB,sEAAoF;AAGpF,4DAA8E;AAC9E,8CAA4D;AAErD,KAAK,UAAU,wBAAwB,CAAC,EAC7C,cAAc,EACd,GAAG,EACH,MAAM,EACN,cAAc,EACd,GAAG,EACH,iBAAiB,GAQlB;IACC,IAAI,IAAc,CAAC;IACnB,QAAQ,cAAc,EAAE,CAAC;QACvB,KAAK,+BAAc,CAAC,GAAG,CAAC,CAAC,CAAC;YACxB,IAAI,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAC9C,MAAM;QACR,CAAC;QACD,KAAK,+BAAc,CAAC,IAAI,CAAC,CAAC,CAAC;YACzB,IAAI,GAAG,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC;YACrF,MAAM;QACR,CAAC;QACD,KAAK,+BAAc,CAAC,IAAI,CAAC,CAAC,CAAC;YACzB,MAAM,mBAAmB,GAAG,MAAM,IAAA,kCAAwB,EAAC,GAAG,CAAC,CAAC;YAChE,IAAI,mBAAmB,EAAE,CAAC;gBACxB,IAAI,GAAG,CAAC,SAAS,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;YAC9F,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1E,CAAC;YACD,MAAM;QACR,CAAC;QACD,KAAK,+BAAc,CAAC,GAAG;YACrB,IAAI,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACxE,MAAM;QACR;YACE,MAAM,IAAI,KAAK,CAAC,gCAAgC,cAAc,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,GAAG,CAAC,aAAa,CAAC,KAAK,GAAG,EAAE,CAAC;QAC/B,IAAI,GAAG,CAAC,GAAG,IAAI,EAAE,WAAW,CAAC,CAAC;IAChC,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,YAAY,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,YAAY,CAAC,CAAC;IACjF,OAAO;QACL,YAAY,EAAE,IAAA,sBAAK,EAAC,cAAc,EAAE,IAAI,EAAE;YACxC,GAAG;YACH,MAAM;YACN,cAAc;YACd,GAAG;SACJ,CAAC;KACH,CAAC;AACJ,CAAC;AAED,SAAgB,kBAAkB,CAAC,GAAsB;IACvD,MAAM,cAAc,GAAG,IAAA,oCAAmB,EAAC,GAAG,CAAC,8BAA8B,EAAE,CAAC,CAAC;IACjF,IAAI,cAAc,KAAK,GAAG,CAAC,8BAA8B,EAAE,EAAE,CAAC;QAC5D,MAAM,mCAAmC,GAAG,cAAI,CAAC,QAAQ,CACvD,GAAG,CAAC,cAAc,EAClB,GAAG,CAAC,8BAA8B,EAAE,CACrC,CAAC;QACF,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,qBAAqB,mCAAmC,UAAU,GAAG,CAAC,cAAc,YAAY,CACjG,CAAC;IACJ,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC","sourcesContent":["import path from 'path';\n\nimport { Job } from '@expo/eas-build-job';\nimport spawn, { SpawnPromise, SpawnResult, SpawnOptions } from '@expo/turtle-spawn';\n\nimport { BuildContext } from '../context';\nimport { PackageManager, findPackagerRootDir } from '../utils/packageManager';\nimport { isUsingModernYarnVersion } from '../utils/project';\n\nexport async function installDependenciesAsync({\n packageManager,\n env,\n logger,\n infoCallbackFn,\n cwd,\n useFrozenLockfile,\n}: {\n packageManager: PackageManager;\n env: Record<string, string | undefined>;\n cwd: string;\n logger: Exclude<SpawnOptions['logger'], undefined>;\n infoCallbackFn?: SpawnOptions['infoCallbackFn'];\n useFrozenLockfile: boolean;\n}): Promise<{ spawnPromise: SpawnPromise<SpawnResult> }> {\n let args: string[];\n switch (packageManager) {\n case PackageManager.NPM: {\n args = [useFrozenLockfile ? 'ci' : 'install'];\n break;\n }\n case PackageManager.PNPM: {\n args = ['install', useFrozenLockfile ? '--frozen-lockfile' : '--no-frozen-lockfile'];\n break;\n }\n case PackageManager.YARN: {\n const isModernYarnVersion = await isUsingModernYarnVersion(cwd);\n if (isModernYarnVersion) {\n args = ['install', '--inline-builds', useFrozenLockfile ? '--immutable' : '--no-immutable'];\n } else {\n args = ['install', ...(useFrozenLockfile ? ['--frozen-lockfile'] : [])];\n }\n break;\n }\n case PackageManager.BUN:\n args = ['install', ...(useFrozenLockfile ? ['--frozen-lockfile'] : [])];\n break;\n default:\n throw new Error(`Unsupported package manager: ${packageManager}`);\n }\n if (env['EAS_VERBOSE'] === '1') {\n args = [...args, '--verbose'];\n }\n logger.info(`Running \"${packageManager} ${args.join(' ')}\" in ${cwd} directory`);\n return {\n spawnPromise: spawn(packageManager, args, {\n cwd,\n logger,\n infoCallbackFn,\n env,\n }),\n };\n}\n\nexport function resolvePackagerDir(ctx: BuildContext<Job>): string {\n const packagerRunDir = findPackagerRootDir(ctx.getReactNativeProjectDirectory());\n if (packagerRunDir !== ctx.getReactNativeProjectDirectory()) {\n const relativeReactNativeProjectDirectory = path.relative(\n ctx.buildDirectory,\n ctx.getReactNativeProjectDirectory()\n );\n ctx.logger.info(\n `We detected that '${relativeReactNativeProjectDirectory}' is a ${ctx.packageManager} workspace`\n );\n }\n return packagerRunDir;\n}\n"]}
1
+ {"version":3,"file":"installDependencies.js","sourceRoot":"","sources":["../../src/common/installDependencies.ts"],"names":[],"mappings":";;;;;AASA,4DAoDC;AAED,gDAYC;AA3ED,gDAAwB;AAGxB,sEAAoF;AAGpF,4DAA8E;AAC9E,8CAA4D;AAErD,KAAK,UAAU,wBAAwB,CAAC,EAC7C,cAAc,EACd,GAAG,EACH,MAAM,EACN,cAAc,EACd,GAAG,EACH,iBAAiB,GAQlB;IACC,IAAI,IAAc,CAAC;IACnB,QAAQ,cAAc,EAAE,CAAC;QACvB,KAAK,+BAAc,CAAC,GAAG,CAAC,CAAC,CAAC;YACxB,IAAI,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YACjE,MAAM;QACR,CAAC;QACD,KAAK,+BAAc,CAAC,IAAI,CAAC,CAAC,CAAC;YACzB,IAAI,GAAG,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC;YACrF,MAAM;QACR,CAAC;QACD,KAAK,+BAAc,CAAC,IAAI,CAAC,CAAC,CAAC;YACzB,MAAM,mBAAmB,GAAG,MAAM,IAAA,kCAAwB,EAAC,GAAG,CAAC,CAAC;YAChE,IAAI,mBAAmB,EAAE,CAAC;gBACxB,IAAI,GAAG,CAAC,SAAS,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;YAC9F,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1E,CAAC;YACD,MAAM;QACR,CAAC;QACD,KAAK,+BAAc,CAAC,GAAG;YACrB,IAAI,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACxE,MAAM;QACR;YACE,MAAM,IAAI,KAAK,CAAC,gCAAgC,cAAc,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,GAAG,CAAC,aAAa,CAAC,KAAK,GAAG,EAAE,CAAC;QAC/B,IAAI,GAAG,CAAC,GAAG,IAAI,EAAE,WAAW,CAAC,CAAC;IAChC,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,YAAY,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,YAAY,CAAC,CAAC;IACjF,OAAO;QACL,YAAY,EAAE,IAAA,sBAAK,EAAC,cAAc,EAAE,IAAI,EAAE;YACxC,GAAG;YACH,MAAM;YACN,cAAc;YACd,GAAG;SACJ,CAAC;KACH,CAAC;AACJ,CAAC;AAED,SAAgB,kBAAkB,CAAC,GAAsB;IACvD,MAAM,cAAc,GAAG,IAAA,oCAAmB,EAAC,GAAG,CAAC,8BAA8B,EAAE,CAAC,CAAC;IACjF,IAAI,cAAc,KAAK,GAAG,CAAC,8BAA8B,EAAE,EAAE,CAAC;QAC5D,MAAM,mCAAmC,GAAG,cAAI,CAAC,QAAQ,CACvD,GAAG,CAAC,cAAc,EAClB,GAAG,CAAC,8BAA8B,EAAE,CACrC,CAAC;QACF,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,qBAAqB,mCAAmC,UAAU,GAAG,CAAC,cAAc,YAAY,CACjG,CAAC;IACJ,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC","sourcesContent":["import path from 'path';\n\nimport { Job } from '@expo/eas-build-job';\nimport spawn, { SpawnPromise, SpawnResult, SpawnOptions } from '@expo/turtle-spawn';\n\nimport { BuildContext } from '../context';\nimport { PackageManager, findPackagerRootDir } from '../utils/packageManager';\nimport { isUsingModernYarnVersion } from '../utils/project';\n\nexport async function installDependenciesAsync({\n packageManager,\n env,\n logger,\n infoCallbackFn,\n cwd,\n useFrozenLockfile,\n}: {\n packageManager: PackageManager;\n env: Record<string, string | undefined>;\n cwd: string;\n logger: Exclude<SpawnOptions['logger'], undefined>;\n infoCallbackFn?: SpawnOptions['infoCallbackFn'];\n useFrozenLockfile: boolean;\n}): Promise<{ spawnPromise: SpawnPromise<SpawnResult> }> {\n let args: string[];\n switch (packageManager) {\n case PackageManager.NPM: {\n args = useFrozenLockfile ? ['ci', '--include=dev'] : ['install'];\n break;\n }\n case PackageManager.PNPM: {\n args = ['install', useFrozenLockfile ? '--frozen-lockfile' : '--no-frozen-lockfile'];\n break;\n }\n case PackageManager.YARN: {\n const isModernYarnVersion = await isUsingModernYarnVersion(cwd);\n if (isModernYarnVersion) {\n args = ['install', '--inline-builds', useFrozenLockfile ? '--immutable' : '--no-immutable'];\n } else {\n args = ['install', ...(useFrozenLockfile ? ['--frozen-lockfile'] : [])];\n }\n break;\n }\n case PackageManager.BUN:\n args = ['install', ...(useFrozenLockfile ? ['--frozen-lockfile'] : [])];\n break;\n default:\n throw new Error(`Unsupported package manager: ${packageManager}`);\n }\n if (env['EAS_VERBOSE'] === '1') {\n args = [...args, '--verbose'];\n }\n logger.info(`Running \"${packageManager} ${args.join(' ')}\" in ${cwd} directory`);\n return {\n spawnPromise: spawn(packageManager, args, {\n cwd,\n logger,\n infoCallbackFn,\n env,\n }),\n };\n}\n\nexport function resolvePackagerDir(ctx: BuildContext<Job>): string {\n const packagerRunDir = findPackagerRootDir(ctx.getReactNativeProjectDirectory());\n if (packagerRunDir !== ctx.getReactNativeProjectDirectory()) {\n const relativeReactNativeProjectDirectory = path.relative(\n ctx.buildDirectory,\n ctx.getReactNativeProjectDirectory()\n );\n ctx.logger.info(\n `We detected that '${relativeReactNativeProjectDirectory}' is a ${ctx.packageManager} workspace`\n );\n }\n return packagerRunDir;\n}\n"]}
@@ -29,6 +29,8 @@ const createSubmissionEntity_1 = require("./functions/createSubmissionEntity");
29
29
  const downloadBuild_1 = require("./functions/downloadBuild");
30
30
  const repack_1 = require("./functions/repack");
31
31
  const downloadArtifact_1 = require("./functions/downloadArtifact");
32
+ const restoreCache_1 = require("./functions/restoreCache");
33
+ const saveCache_1 = require("./functions/saveCache");
32
34
  const internalMaestroTest_1 = require("./functions/internalMaestroTest");
33
35
  function getEasFunctions(ctx) {
34
36
  const functions = [
@@ -40,6 +42,8 @@ function getEasFunctions(ctx) {
40
42
  (0, prebuild_1.createPrebuildBuildFunction)(),
41
43
  (0, downloadBuild_1.createDownloadBuildFunction)(),
42
44
  (0, repack_1.createRepackBuildFunction)(),
45
+ (0, restoreCache_1.createRestoreCacheFunction)(),
46
+ (0, saveCache_1.createSaveCacheFunction)(),
43
47
  (0, configureEASUpdateIfInstalled_1.configureEASUpdateIfInstalledFunction)(),
44
48
  (0, injectAndroidCredentials_1.injectAndroidCredentialsFunction)(),
45
49
  (0, configureAndroidVersion_1.configureAndroidVersionFunction)(),
@@ -1 +1 @@
1
- {"version":3,"file":"easFunctions.js","sourceRoot":"","sources":["../../src/steps/easFunctions.ts"],"names":[],"mappings":";;AAkCA,0CA8CC;AA5ED,+DAA+E;AAC/E,mDAAmE;AACnE,yDAAwE;AACxE,uEAAuF;AACvF,mDAAmE;AACnE,yFAAyG;AACzG,6FAAkG;AAClG,mFAAwF;AACxF,iFAAsF;AACtF,qDAA0D;AAC1D,qGAA0G;AAC1G,iFAAsF;AACtF,yEAA8E;AAC9E,yFAA8F;AAC9F,yDAA8D;AAC9D,2EAA2F;AAC3F,qEAAqF;AACrF,+DAA+E;AAC/E,uIAA0I;AAC1I,yDAAyE;AACzE,mEAA8E;AAC9E,uEAAuF;AACvF,mGAAwG;AACxG,yDAAmE;AACnE,+EAAoF;AACpF,6DAAwE;AACxE,+CAA+D;AAC/D,mEAA8E;AAC9E,yEAAuF;AAEvF,SAAgB,eAAe,CAAC,GAAuB;IACrD,MAAM,SAAS,GAAG;QAChB,IAAA,sCAA2B,GAAE;QAC7B,IAAA,iDAA8B,GAAE;QAChC,IAAA,kDAAiC,EAAC,GAAG,CAAC;QACtC,IAAA,2CAA6B,GAAE;QAC/B,IAAA,0DAAqC,GAAE;QACvC,IAAA,sCAA2B,GAAE;QAC7B,IAAA,2CAA2B,GAAE;QAC7B,IAAA,kCAAyB,GAAE;QAE3B,IAAA,qEAAqC,GAAE;QACvC,IAAA,2DAAgC,GAAE;QAClC,IAAA,yDAA+B,GAAE;QACjC,IAAA,sCAAwB,GAAE;QAC1B,IAAA,6BAAiB,GAAE;QACnB,IAAA,6EAAyC,GAAE;QAC3C,IAAA,yDAA+B,GAAE;QACjC,IAAA,iDAA2B,GAAE;QAC7B,IAAA,iEAAmC,GAAE;QACrC,IAAA,iCAAmB,GAAE;QACrB,IAAA,8DAAuC,GAAE;QACzC,IAAA,wDAAoC,GAAE;QACtC,IAAA,kDAAiC,GAAE;QAEnC,IAAA,4CAA8B,GAAE;QAChC,IAAA,iDAA8B,GAAE;QAEhC,IAAA,2EAAwC,GAAE;QAE1C,IAAA,uDAA8B,GAAE;QAEhC,IAAA,0DAAoC,EAAC,GAAG,CAAC;KAC1C,CAAC;IAEF,IAAI,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;QACtB,SAAS,CAAC,IAAI,CACZ,GAAG;YACD,IAAA,4EAA8C,EAAC,GAAG,CAAC;YACnD,IAAA,0DAAqC,EAAC,GAAG,CAAC;YAC1C,IAAA,6GAAwD,EAAC,GAAG,CAAC;SAC9D,CACF,CAAC;IACJ,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["import { BuildFunction } from '@expo/steps';\n\nimport { CustomBuildContext } from '../customBuildContext';\n\nimport { createUploadArtifactBuildFunction } from './functions/uploadArtifact';\nimport { createCheckoutBuildFunction } from './functions/checkout';\nimport { createSetUpNpmrcBuildFunction } from './functions/useNpmToken';\nimport { createInstallNodeModulesBuildFunction } from './functions/installNodeModules';\nimport { createPrebuildBuildFunction } from './functions/prebuild';\nimport { createFindAndUploadBuildArtifactsBuildFunction } from './functions/findAndUploadBuildArtifacts';\nimport { configureEASUpdateIfInstalledFunction } from './functions/configureEASUpdateIfInstalled';\nimport { injectAndroidCredentialsFunction } from './functions/injectAndroidCredentials';\nimport { configureAndroidVersionFunction } from './functions/configureAndroidVersion';\nimport { runGradleFunction } from './functions/runGradle';\nimport { resolveAppleTeamIdFromCredentialsFunction } from './functions/resolveAppleTeamIdFromCredentials';\nimport { configureIosCredentialsFunction } from './functions/configureIosCredentials';\nimport { configureIosVersionFunction } from './functions/configureIosVersion';\nimport { generateGymfileFromTemplateFunction } from './functions/generateGymfileFromTemplate';\nimport { runFastlaneFunction } from './functions/runFastlane';\nimport { createStartAndroidEmulatorBuildFunction } from './functions/startAndroidEmulator';\nimport { createStartIosSimulatorBuildFunction } from './functions/startIosSimulator';\nimport { createInstallMaestroBuildFunction } from './functions/installMaestro';\nimport { createGetCredentialsForBuildTriggeredByGithubIntegration } from './functions/getCredentialsForBuildTriggeredByGitHubIntegration';\nimport { createInstallPodsBuildFunction } from './functions/installPods';\nimport { createSendSlackMessageFunction } from './functions/sendSlackMessage';\nimport { createResolveBuildConfigBuildFunction } from './functions/resolveBuildConfig';\nimport { calculateEASUpdateRuntimeVersionFunction } from './functions/calculateEASUpdateRuntimeVersion';\nimport { eagerBundleBuildFunction } from './functions/eagerBundle';\nimport { createSubmissionEntityFunction } from './functions/createSubmissionEntity';\nimport { createDownloadBuildFunction } from './functions/downloadBuild';\nimport { createRepackBuildFunction } from './functions/repack';\nimport { createDownloadArtifactFunction } from './functions/downloadArtifact';\nimport { createInternalEasMaestroTestFunction } from './functions/internalMaestroTest';\n\nexport function getEasFunctions(ctx: CustomBuildContext): BuildFunction[] {\n const functions = [\n createCheckoutBuildFunction(),\n createDownloadArtifactFunction(),\n createUploadArtifactBuildFunction(ctx),\n createSetUpNpmrcBuildFunction(),\n createInstallNodeModulesBuildFunction(),\n createPrebuildBuildFunction(),\n createDownloadBuildFunction(),\n createRepackBuildFunction(),\n\n configureEASUpdateIfInstalledFunction(),\n injectAndroidCredentialsFunction(),\n configureAndroidVersionFunction(),\n eagerBundleBuildFunction(),\n runGradleFunction(),\n resolveAppleTeamIdFromCredentialsFunction(),\n configureIosCredentialsFunction(),\n configureIosVersionFunction(),\n generateGymfileFromTemplateFunction(),\n runFastlaneFunction(),\n createStartAndroidEmulatorBuildFunction(),\n createStartIosSimulatorBuildFunction(),\n createInstallMaestroBuildFunction(),\n\n createInstallPodsBuildFunction(),\n createSendSlackMessageFunction(),\n\n calculateEASUpdateRuntimeVersionFunction(),\n\n createSubmissionEntityFunction(),\n\n createInternalEasMaestroTestFunction(ctx),\n ];\n\n if (ctx.hasBuildJob()) {\n functions.push(\n ...[\n createFindAndUploadBuildArtifactsBuildFunction(ctx),\n createResolveBuildConfigBuildFunction(ctx),\n createGetCredentialsForBuildTriggeredByGithubIntegration(ctx),\n ]\n );\n }\n\n return functions;\n}\n"]}
1
+ {"version":3,"file":"easFunctions.js","sourceRoot":"","sources":["../../src/steps/easFunctions.ts"],"names":[],"mappings":";;AAoCA,0CAiDC;AAjFD,+DAA+E;AAC/E,mDAAmE;AACnE,yDAAwE;AACxE,uEAAuF;AACvF,mDAAmE;AACnE,yFAAyG;AACzG,6FAAkG;AAClG,mFAAwF;AACxF,iFAAsF;AACtF,qDAA0D;AAC1D,qGAA0G;AAC1G,iFAAsF;AACtF,yEAA8E;AAC9E,yFAA8F;AAC9F,yDAA8D;AAC9D,2EAA2F;AAC3F,qEAAqF;AACrF,+DAA+E;AAC/E,uIAA0I;AAC1I,yDAAyE;AACzE,mEAA8E;AAC9E,uEAAuF;AACvF,mGAAwG;AACxG,yDAAmE;AACnE,+EAAoF;AACpF,6DAAwE;AACxE,+CAA+D;AAC/D,mEAA8E;AAC9E,2DAAsE;AACtE,qDAAgE;AAChE,yEAAuF;AAEvF,SAAgB,eAAe,CAAC,GAAuB;IACrD,MAAM,SAAS,GAAG;QAChB,IAAA,sCAA2B,GAAE;QAC7B,IAAA,iDAA8B,GAAE;QAChC,IAAA,kDAAiC,EAAC,GAAG,CAAC;QACtC,IAAA,2CAA6B,GAAE;QAC/B,IAAA,0DAAqC,GAAE;QACvC,IAAA,sCAA2B,GAAE;QAC7B,IAAA,2CAA2B,GAAE;QAC7B,IAAA,kCAAyB,GAAE;QAE3B,IAAA,yCAA0B,GAAE;QAC5B,IAAA,mCAAuB,GAAE;QAEzB,IAAA,qEAAqC,GAAE;QACvC,IAAA,2DAAgC,GAAE;QAClC,IAAA,yDAA+B,GAAE;QACjC,IAAA,sCAAwB,GAAE;QAC1B,IAAA,6BAAiB,GAAE;QACnB,IAAA,6EAAyC,GAAE;QAC3C,IAAA,yDAA+B,GAAE;QACjC,IAAA,iDAA2B,GAAE;QAC7B,IAAA,iEAAmC,GAAE;QACrC,IAAA,iCAAmB,GAAE;QACrB,IAAA,8DAAuC,GAAE;QACzC,IAAA,wDAAoC,GAAE;QACtC,IAAA,kDAAiC,GAAE;QAEnC,IAAA,4CAA8B,GAAE;QAChC,IAAA,iDAA8B,GAAE;QAEhC,IAAA,2EAAwC,GAAE;QAE1C,IAAA,uDAA8B,GAAE;QAEhC,IAAA,0DAAoC,EAAC,GAAG,CAAC;KAC1C,CAAC;IAEF,IAAI,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;QACtB,SAAS,CAAC,IAAI,CACZ,GAAG;YACD,IAAA,4EAA8C,EAAC,GAAG,CAAC;YACnD,IAAA,0DAAqC,EAAC,GAAG,CAAC;YAC1C,IAAA,6GAAwD,EAAC,GAAG,CAAC;SAC9D,CACF,CAAC;IACJ,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["import { BuildFunction } from '@expo/steps';\n\nimport { CustomBuildContext } from '../customBuildContext';\n\nimport { createUploadArtifactBuildFunction } from './functions/uploadArtifact';\nimport { createCheckoutBuildFunction } from './functions/checkout';\nimport { createSetUpNpmrcBuildFunction } from './functions/useNpmToken';\nimport { createInstallNodeModulesBuildFunction } from './functions/installNodeModules';\nimport { createPrebuildBuildFunction } from './functions/prebuild';\nimport { createFindAndUploadBuildArtifactsBuildFunction } from './functions/findAndUploadBuildArtifacts';\nimport { configureEASUpdateIfInstalledFunction } from './functions/configureEASUpdateIfInstalled';\nimport { injectAndroidCredentialsFunction } from './functions/injectAndroidCredentials';\nimport { configureAndroidVersionFunction } from './functions/configureAndroidVersion';\nimport { runGradleFunction } from './functions/runGradle';\nimport { resolveAppleTeamIdFromCredentialsFunction } from './functions/resolveAppleTeamIdFromCredentials';\nimport { configureIosCredentialsFunction } from './functions/configureIosCredentials';\nimport { configureIosVersionFunction } from './functions/configureIosVersion';\nimport { generateGymfileFromTemplateFunction } from './functions/generateGymfileFromTemplate';\nimport { runFastlaneFunction } from './functions/runFastlane';\nimport { createStartAndroidEmulatorBuildFunction } from './functions/startAndroidEmulator';\nimport { createStartIosSimulatorBuildFunction } from './functions/startIosSimulator';\nimport { createInstallMaestroBuildFunction } from './functions/installMaestro';\nimport { createGetCredentialsForBuildTriggeredByGithubIntegration } from './functions/getCredentialsForBuildTriggeredByGitHubIntegration';\nimport { createInstallPodsBuildFunction } from './functions/installPods';\nimport { createSendSlackMessageFunction } from './functions/sendSlackMessage';\nimport { createResolveBuildConfigBuildFunction } from './functions/resolveBuildConfig';\nimport { calculateEASUpdateRuntimeVersionFunction } from './functions/calculateEASUpdateRuntimeVersion';\nimport { eagerBundleBuildFunction } from './functions/eagerBundle';\nimport { createSubmissionEntityFunction } from './functions/createSubmissionEntity';\nimport { createDownloadBuildFunction } from './functions/downloadBuild';\nimport { createRepackBuildFunction } from './functions/repack';\nimport { createDownloadArtifactFunction } from './functions/downloadArtifact';\nimport { createRestoreCacheFunction } from './functions/restoreCache';\nimport { createSaveCacheFunction } from './functions/saveCache';\nimport { createInternalEasMaestroTestFunction } from './functions/internalMaestroTest';\n\nexport function getEasFunctions(ctx: CustomBuildContext): BuildFunction[] {\n const functions = [\n createCheckoutBuildFunction(),\n createDownloadArtifactFunction(),\n createUploadArtifactBuildFunction(ctx),\n createSetUpNpmrcBuildFunction(),\n createInstallNodeModulesBuildFunction(),\n createPrebuildBuildFunction(),\n createDownloadBuildFunction(),\n createRepackBuildFunction(),\n\n createRestoreCacheFunction(),\n createSaveCacheFunction(),\n\n configureEASUpdateIfInstalledFunction(),\n injectAndroidCredentialsFunction(),\n configureAndroidVersionFunction(),\n eagerBundleBuildFunction(),\n runGradleFunction(),\n resolveAppleTeamIdFromCredentialsFunction(),\n configureIosCredentialsFunction(),\n configureIosVersionFunction(),\n generateGymfileFromTemplateFunction(),\n runFastlaneFunction(),\n createStartAndroidEmulatorBuildFunction(),\n createStartIosSimulatorBuildFunction(),\n createInstallMaestroBuildFunction(),\n\n createInstallPodsBuildFunction(),\n createSendSlackMessageFunction(),\n\n calculateEASUpdateRuntimeVersionFunction(),\n\n createSubmissionEntityFunction(),\n\n createInternalEasMaestroTestFunction(ctx),\n ];\n\n if (ctx.hasBuildJob()) {\n functions.push(\n ...[\n createFindAndUploadBuildArtifactsBuildFunction(ctx),\n createResolveBuildConfigBuildFunction(ctx),\n createGetCredentialsForBuildTriggeredByGithubIntegration(ctx),\n ]\n );\n }\n\n return functions;\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import { bunyan } from '@expo/logger';
2
+ import { BuildFunction } from '@expo/steps';
3
+ export declare function createRestoreCacheFunction(): BuildFunction;
4
+ export declare function downloadCacheAsync({ logger, jobRunId, expoApiServerURL, robotAccessToken, paths, key, keyPrefixes, }: {
5
+ logger: bunyan;
6
+ jobRunId: string;
7
+ expoApiServerURL: string;
8
+ robotAccessToken: string;
9
+ paths: string[];
10
+ key: string;
11
+ keyPrefixes: string[];
12
+ }): Promise<{
13
+ archivePath: string;
14
+ matchedKey: string;
15
+ }>;
16
+ export declare function decompressCacheAsync({ archivePath, workingDirectory, verbose, logger, }: {
17
+ archivePath: string;
18
+ workingDirectory: string;
19
+ verbose: boolean;
20
+ logger: bunyan;
21
+ }): Promise<void>;
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.createRestoreCacheFunction = createRestoreCacheFunction;
30
+ exports.downloadCacheAsync = downloadCacheAsync;
31
+ exports.decompressCacheAsync = decompressCacheAsync;
32
+ const fs_1 = __importDefault(require("fs"));
33
+ const os_1 = __importDefault(require("os"));
34
+ const path_1 = __importDefault(require("path"));
35
+ const stream_1 = __importDefault(require("stream"));
36
+ const util_1 = require("util");
37
+ const tar = __importStar(require("tar"));
38
+ const steps_1 = require("@expo/steps");
39
+ const zod_1 = __importDefault(require("zod"));
40
+ const nullthrows_1 = __importDefault(require("nullthrows"));
41
+ const node_fetch_1 = __importDefault(require("node-fetch"));
42
+ const results_1 = require("@expo/results");
43
+ const retryOnDNSFailure_1 = require("../../utils/retryOnDNSFailure");
44
+ const artifacts_1 = require("../../utils/artifacts");
45
+ const cache_1 = require("../utils/cache");
46
+ const streamPipeline = (0, util_1.promisify)(stream_1.default.pipeline);
47
+ function createRestoreCacheFunction() {
48
+ return new steps_1.BuildFunction({
49
+ namespace: 'eas',
50
+ id: 'restore_cache',
51
+ name: 'Restore Cache',
52
+ inputProviders: [
53
+ steps_1.BuildStepInput.createProvider({
54
+ id: 'path',
55
+ required: false,
56
+ allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
57
+ }),
58
+ steps_1.BuildStepInput.createProvider({
59
+ id: 'key',
60
+ required: true,
61
+ allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
62
+ }),
63
+ steps_1.BuildStepInput.createProvider({
64
+ id: 'restore_keys',
65
+ required: false,
66
+ allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
67
+ }),
68
+ ],
69
+ outputProviders: [
70
+ steps_1.BuildStepOutput.createProvider({
71
+ id: 'cache_hit',
72
+ required: false,
73
+ }),
74
+ ],
75
+ fn: async (stepsCtx, { env, inputs, outputs }) => {
76
+ var _a, _b, _c, _d;
77
+ const { logger } = stepsCtx;
78
+ try {
79
+ if (stepsCtx.global.staticContext.job.platform) {
80
+ logger.error('Caches are not supported in build jobs yet.');
81
+ return;
82
+ }
83
+ const paths = zod_1.default
84
+ .array(zod_1.default.string())
85
+ .parse(((_a = inputs.path.value) !== null && _a !== void 0 ? _a : '').split(/[\r\n]+/))
86
+ .filter((path) => path.length > 0);
87
+ const key = zod_1.default.string().parse(inputs.key.value);
88
+ const restoreKeys = zod_1.default
89
+ .array(zod_1.default.string())
90
+ .parse(((_b = inputs.restore_keys.value) !== null && _b !== void 0 ? _b : '').split(/[\r\n]+/))
91
+ .filter((key) => key !== '');
92
+ const taskId = (0, nullthrows_1.default)(env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set');
93
+ const { archivePath, matchedKey } = await downloadCacheAsync({
94
+ logger,
95
+ jobRunId: taskId,
96
+ expoApiServerURL: stepsCtx.global.staticContext.expoApiServerURL,
97
+ robotAccessToken: (_d = (_c = stepsCtx.global.staticContext.job.secrets) === null || _c === void 0 ? void 0 : _c.robotAccessToken) !== null && _d !== void 0 ? _d : null,
98
+ paths,
99
+ key,
100
+ keyPrefixes: restoreKeys,
101
+ });
102
+ const { size } = await fs_1.default.promises.stat(archivePath);
103
+ logger.info(`Downloaded cache archive from ${archivePath} (${(0, artifacts_1.formatBytes)(size)}).`);
104
+ await decompressCacheAsync({
105
+ archivePath,
106
+ workingDirectory: stepsCtx.workingDirectory,
107
+ verbose: true,
108
+ logger,
109
+ });
110
+ outputs.cache_hit.set(`${matchedKey === key}`);
111
+ }
112
+ catch (error) {
113
+ logger.error({ err: error }, 'Failed to restore cache');
114
+ }
115
+ },
116
+ });
117
+ }
118
+ async function downloadCacheAsync({ logger, jobRunId, expoApiServerURL, robotAccessToken, paths, key, keyPrefixes, }) {
119
+ const response = await (0, retryOnDNSFailure_1.retryOnDNSFailure)(node_fetch_1.default)(new URL('v2/turtle-caches/download', expoApiServerURL), {
120
+ method: 'POST',
121
+ body: JSON.stringify({
122
+ jobRunId,
123
+ key,
124
+ version: (0, cache_1.getCacheVersion)(paths),
125
+ keyPrefixes,
126
+ }),
127
+ headers: {
128
+ Authorization: `Bearer ${robotAccessToken}`,
129
+ 'Content-Type': 'application/json',
130
+ },
131
+ });
132
+ if (!response.ok) {
133
+ if (response.status === 404) {
134
+ throw new Error(`No cache found for this key, ensure it was created with eas/save_cache (${response.status})`);
135
+ }
136
+ const textResult = await (0, results_1.asyncResult)(response.text());
137
+ throw new Error(`Unexpected response from server (${response.status}): ${textResult.value}`);
138
+ }
139
+ const result = await (0, results_1.asyncResult)(response.json());
140
+ if (!result.ok) {
141
+ throw new Error(`Unexpected response from server (${response.status}): ${result.reason}`);
142
+ }
143
+ const { matchedKey, downloadUrl } = result.value.data;
144
+ logger.info(`Matched cache key: ${matchedKey}. Downloading...`);
145
+ const downloadDestinationDirectory = await fs_1.default.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'restore-cache-'));
146
+ const downloadResponse = await (0, retryOnDNSFailure_1.retryOnDNSFailure)(node_fetch_1.default)(downloadUrl);
147
+ if (!downloadResponse.ok) {
148
+ throw new Error(`Unexpected response from cache server (${downloadResponse.status}): ${downloadResponse.statusText}`);
149
+ }
150
+ // URL may contain percent-encoded characters, e.g. my%20file.apk
151
+ // this replaces all non-alphanumeric characters (excluding dot) with underscore
152
+ const archiveFilename = path_1.default
153
+ .basename(new URL(downloadUrl).pathname)
154
+ .replace(/([^a-z0-9.-]+)/gi, '_');
155
+ const archivePath = path_1.default.join(downloadDestinationDirectory, archiveFilename);
156
+ await streamPipeline(downloadResponse.body, fs_1.default.createWriteStream(archivePath));
157
+ return { archivePath, matchedKey };
158
+ }
159
+ async function decompressCacheAsync({ archivePath, workingDirectory, verbose, logger, }) {
160
+ if (verbose) {
161
+ logger.info(`Extracting cache to ${workingDirectory}:`);
162
+ }
163
+ // First, extract everything to the working directory
164
+ const fileHandle = await fs_1.default.promises.open(archivePath, 'r');
165
+ const extractedFiles = [];
166
+ await streamPipeline(fileHandle.createReadStream(), tar.extract({
167
+ cwd: workingDirectory,
168
+ onwarn: (code, message, data) => {
169
+ logger.warn({ code, data }, message);
170
+ },
171
+ preservePaths: true,
172
+ onReadEntry: (entry) => {
173
+ extractedFiles.push(entry.path);
174
+ if (verbose) {
175
+ logger.info(`- ${entry.path}`);
176
+ }
177
+ },
178
+ }));
179
+ // Handle absolute paths that were prefixed with __absolute__
180
+ for (const extractedPath of extractedFiles) {
181
+ if (extractedPath.startsWith('__absolute__/')) {
182
+ const originalAbsolutePath = extractedPath.slice('__absolute__'.length);
183
+ const currentPath = path_1.default.join(workingDirectory, extractedPath);
184
+ try {
185
+ // Ensure the target directory exists
186
+ await fs_1.default.promises.mkdir(path_1.default.dirname(originalAbsolutePath), { recursive: true });
187
+ // Move the file to its original absolute location
188
+ await fs_1.default.promises.rename(currentPath, originalAbsolutePath);
189
+ if (verbose) {
190
+ logger.info(`Moved ${extractedPath} to ${originalAbsolutePath}`);
191
+ }
192
+ }
193
+ catch (error) {
194
+ logger.warn(`Failed to restore absolute path ${originalAbsolutePath}: ${error}`);
195
+ }
196
+ }
197
+ }
198
+ // Clean up any remaining __absolute__ directories
199
+ const absoluteDir = path_1.default.join(workingDirectory, '__absolute__');
200
+ if (await fs_1.default.promises
201
+ .access(absoluteDir)
202
+ .then(() => true)
203
+ .catch(() => false)) {
204
+ await fs_1.default.promises.rm(absoluteDir, { recursive: true, force: true });
205
+ }
206
+ }
207
+ //# sourceMappingURL=restoreCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restoreCache.js","sourceRoot":"","sources":["../../../src/steps/functions/restoreCache.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport stream from 'stream';\nimport { promisify } from 'util';\n\nimport * as tar from 'tar';\nimport { bunyan } from '@expo/logger';\nimport {\n BuildFunction,\n BuildStepInput,\n BuildStepInputValueTypeName,\n BuildStepOutput,\n} from '@expo/steps';\nimport z from 'zod';\nimport nullthrows from 'nullthrows';\nimport fetch from 'node-fetch';\nimport { asyncResult } from '@expo/results';\n\nimport { retryOnDNSFailure } from '../../utils/retryOnDNSFailure';\nimport { formatBytes } from '../../utils/artifacts';\nimport { getCacheVersion } from '../utils/cache';\n\nconst streamPipeline = promisify(stream.pipeline);\n\nexport function createRestoreCacheFunction(): BuildFunction {\n return new BuildFunction({\n namespace: 'eas',\n id: 'restore_cache',\n name: 'Restore Cache',\n inputProviders: [\n BuildStepInput.createProvider({\n id: 'path',\n required: false,\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n BuildStepInput.createProvider({\n id: 'key',\n required: true,\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n BuildStepInput.createProvider({\n id: 'restore_keys',\n required: false,\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n ],\n outputProviders: [\n BuildStepOutput.createProvider({\n id: 'cache_hit',\n required: false,\n }),\n ],\n fn: async (stepsCtx, { env, inputs, outputs }) => {\n const { logger } = stepsCtx;\n\n try {\n if (stepsCtx.global.staticContext.job.platform) {\n logger.error('Caches are not supported in build jobs yet.');\n return;\n }\n\n const paths = z\n .array(z.string())\n .parse(((inputs.path.value ?? '') as string).split(/[\\r\\n]+/))\n .filter((path) => path.length > 0);\n const key = z.string().parse(inputs.key.value);\n const restoreKeys = z\n .array(z.string())\n .parse(((inputs.restore_keys.value ?? '') as string).split(/[\\r\\n]+/))\n .filter((key) => key !== '');\n\n const taskId = nullthrows(env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set');\n\n const { archivePath, matchedKey } = await downloadCacheAsync({\n logger,\n jobRunId: taskId,\n expoApiServerURL: stepsCtx.global.staticContext.expoApiServerURL,\n robotAccessToken: stepsCtx.global.staticContext.job.secrets?.robotAccessToken ?? null,\n paths,\n key,\n keyPrefixes: restoreKeys,\n });\n\n const { size } = await fs.promises.stat(archivePath);\n logger.info(`Downloaded cache archive from ${archivePath} (${formatBytes(size)}).`);\n\n await decompressCacheAsync({\n archivePath,\n workingDirectory: stepsCtx.workingDirectory,\n verbose: true,\n logger,\n });\n\n outputs.cache_hit.set(`${matchedKey === key}`);\n } catch (error) {\n logger.error({ err: error }, 'Failed to restore cache');\n }\n },\n });\n}\n\nexport async function downloadCacheAsync({\n logger,\n jobRunId,\n expoApiServerURL,\n robotAccessToken,\n paths,\n key,\n keyPrefixes,\n}: {\n logger: bunyan;\n jobRunId: string;\n expoApiServerURL: string;\n robotAccessToken: string;\n paths: string[];\n key: string;\n keyPrefixes: string[];\n}): Promise<{ archivePath: string; matchedKey: string }> {\n const response = await retryOnDNSFailure(fetch)(\n new URL('v2/turtle-caches/download', expoApiServerURL),\n {\n method: 'POST',\n body: JSON.stringify({\n jobRunId,\n key,\n version: getCacheVersion(paths),\n keyPrefixes,\n }),\n headers: {\n Authorization: `Bearer ${robotAccessToken}`,\n 'Content-Type': 'application/json',\n },\n }\n );\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new Error(\n `No cache found for this key, ensure it was created with eas/save_cache (${response.status})`\n );\n }\n const textResult = await asyncResult(response.text());\n throw new Error(`Unexpected response from server (${response.status}): ${textResult.value}`);\n }\n\n const result = await asyncResult(response.json());\n if (!result.ok) {\n throw new Error(`Unexpected response from server (${response.status}): ${result.reason}`);\n }\n\n const { matchedKey, downloadUrl } = result.value.data;\n\n logger.info(`Matched cache key: ${matchedKey}. Downloading...`);\n\n const downloadDestinationDirectory = await fs.promises.mkdtemp(\n path.join(os.tmpdir(), 'restore-cache-')\n );\n\n const downloadResponse = await retryOnDNSFailure(fetch)(downloadUrl);\n if (!downloadResponse.ok) {\n throw new Error(\n `Unexpected response from cache server (${downloadResponse.status}): ${downloadResponse.statusText}`\n );\n }\n\n // URL may contain percent-encoded characters, e.g. my%20file.apk\n // this replaces all non-alphanumeric characters (excluding dot) with underscore\n const archiveFilename = path\n .basename(new URL(downloadUrl).pathname)\n .replace(/([^a-z0-9.-]+)/gi, '_');\n const archivePath = path.join(downloadDestinationDirectory, archiveFilename);\n\n await streamPipeline(downloadResponse.body, fs.createWriteStream(archivePath));\n\n return { archivePath, matchedKey };\n}\n\nexport async function decompressCacheAsync({\n archivePath,\n workingDirectory,\n verbose,\n logger,\n}: {\n archivePath: string;\n workingDirectory: string;\n verbose: boolean;\n logger: bunyan;\n}): Promise<void> {\n if (verbose) {\n logger.info(`Extracting cache to ${workingDirectory}:`);\n }\n\n // First, extract everything to the working directory\n const fileHandle = await fs.promises.open(archivePath, 'r');\n const extractedFiles: string[] = [];\n\n await streamPipeline(\n fileHandle.createReadStream(),\n tar.extract({\n cwd: workingDirectory,\n onwarn: (code, message, data) => {\n logger.warn({ code, data }, message);\n },\n preservePaths: true,\n onReadEntry: (entry) => {\n extractedFiles.push(entry.path);\n if (verbose) {\n logger.info(`- ${entry.path}`);\n }\n },\n })\n );\n\n // Handle absolute paths that were prefixed with __absolute__\n for (const extractedPath of extractedFiles) {\n if (extractedPath.startsWith('__absolute__/')) {\n const originalAbsolutePath = extractedPath.slice('__absolute__'.length);\n const currentPath = path.join(workingDirectory, extractedPath);\n\n try {\n // Ensure the target directory exists\n await fs.promises.mkdir(path.dirname(originalAbsolutePath), { recursive: true });\n\n // Move the file to its original absolute location\n await fs.promises.rename(currentPath, originalAbsolutePath);\n\n if (verbose) {\n logger.info(`Moved ${extractedPath} to ${originalAbsolutePath}`);\n }\n } catch (error) {\n logger.warn(`Failed to restore absolute path ${originalAbsolutePath}: ${error}`);\n }\n }\n }\n\n // Clean up any remaining __absolute__ directories\n const absoluteDir = path.join(workingDirectory, '__absolute__');\n if (\n await fs.promises\n .access(absoluteDir)\n .then(() => true)\n .catch(() => false)\n ) {\n await fs.promises.rm(absoluteDir, { recursive: true, force: true });\n }\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import { bunyan } from '@expo/logger';
2
+ import { BuildFunction } from '@expo/steps';
3
+ export declare function createSaveCacheFunction(): BuildFunction;
4
+ export declare function uploadCacheAsync({ logger, jobRunId, expoApiServerURL, robotAccessToken, paths, key, archivePath, size, }: {
5
+ logger: bunyan;
6
+ jobRunId: string;
7
+ expoApiServerURL: string;
8
+ robotAccessToken: string;
9
+ paths: string[];
10
+ key: string;
11
+ archivePath: string;
12
+ size: number;
13
+ }): Promise<void>;
14
+ export declare function compressCacheAsync({ paths, workingDirectory, verbose, logger, }: {
15
+ paths: string[];
16
+ workingDirectory: string;
17
+ verbose: boolean;
18
+ logger: bunyan;
19
+ }): Promise<{
20
+ archivePath: string;
21
+ }>;
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.createSaveCacheFunction = createSaveCacheFunction;
30
+ exports.uploadCacheAsync = uploadCacheAsync;
31
+ exports.compressCacheAsync = compressCacheAsync;
32
+ const fs_1 = __importDefault(require("fs"));
33
+ const os_1 = __importDefault(require("os"));
34
+ const path_1 = __importDefault(require("path"));
35
+ const tar = __importStar(require("tar"));
36
+ const fast_glob_1 = __importDefault(require("fast-glob"));
37
+ const steps_1 = require("@expo/steps");
38
+ const zod_1 = __importDefault(require("zod"));
39
+ const nullthrows_1 = __importDefault(require("nullthrows"));
40
+ const node_fetch_1 = __importDefault(require("node-fetch"));
41
+ const results_1 = require("@expo/results");
42
+ const retryOnDNSFailure_1 = require("../../utils/retryOnDNSFailure");
43
+ const artifacts_1 = require("../../utils/artifacts");
44
+ const cache_1 = require("../utils/cache");
45
+ function createSaveCacheFunction() {
46
+ return new steps_1.BuildFunction({
47
+ namespace: 'eas',
48
+ id: 'save_cache',
49
+ name: 'Save Cache',
50
+ inputProviders: [
51
+ steps_1.BuildStepInput.createProvider({
52
+ id: 'path',
53
+ required: false,
54
+ allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
55
+ }),
56
+ steps_1.BuildStepInput.createProvider({
57
+ id: 'key',
58
+ required: true,
59
+ allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
60
+ }),
61
+ ],
62
+ fn: async (stepsCtx, { env, inputs }) => {
63
+ var _a, _b, _c;
64
+ const { logger } = stepsCtx;
65
+ try {
66
+ if (stepsCtx.global.staticContext.job.platform) {
67
+ logger.error('Caches are not supported in build jobs yet.');
68
+ return;
69
+ }
70
+ const paths = zod_1.default
71
+ .array(zod_1.default.string())
72
+ .parse(((_a = inputs.path.value) !== null && _a !== void 0 ? _a : '').split(/[\r\n]+/))
73
+ .filter((path) => path.length > 0);
74
+ const key = zod_1.default.string().parse(inputs.key.value);
75
+ const taskId = (0, nullthrows_1.default)(env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set');
76
+ const { archivePath } = await compressCacheAsync({
77
+ paths,
78
+ workingDirectory: stepsCtx.workingDirectory,
79
+ verbose: true,
80
+ logger,
81
+ });
82
+ const { size } = await fs_1.default.promises.stat(archivePath);
83
+ await uploadCacheAsync({
84
+ logger,
85
+ jobRunId: taskId,
86
+ expoApiServerURL: stepsCtx.global.staticContext.expoApiServerURL,
87
+ robotAccessToken: (_c = (_b = stepsCtx.global.staticContext.job.secrets) === null || _b === void 0 ? void 0 : _b.robotAccessToken) !== null && _c !== void 0 ? _c : null,
88
+ archivePath,
89
+ key,
90
+ paths,
91
+ size,
92
+ });
93
+ }
94
+ catch (error) {
95
+ logger.error({ err: error }, 'Failed to create cache');
96
+ }
97
+ },
98
+ });
99
+ }
100
+ async function uploadCacheAsync({ logger, jobRunId, expoApiServerURL, robotAccessToken, paths, key, archivePath, size, }) {
101
+ const response = await (0, retryOnDNSFailure_1.retryOnDNSFailure)(node_fetch_1.default)(new URL('v2/turtle-caches/upload-sessions', expoApiServerURL), {
102
+ method: 'POST',
103
+ body: JSON.stringify({
104
+ jobRunId,
105
+ key,
106
+ version: (0, cache_1.getCacheVersion)(paths),
107
+ size,
108
+ }),
109
+ headers: {
110
+ Authorization: `Bearer ${robotAccessToken}`,
111
+ 'Content-Type': 'application/json',
112
+ },
113
+ });
114
+ if (!response.ok) {
115
+ if (response.status === 409) {
116
+ logger.info(`Cache already exists, skipping upload`);
117
+ return;
118
+ }
119
+ const textResult = await (0, results_1.asyncResult)(response.text());
120
+ throw new Error(`Unexpected response from server (${response.status}): ${textResult.value}`);
121
+ }
122
+ const result = await (0, results_1.asyncResult)(response.json());
123
+ if (!result.ok) {
124
+ throw new Error(`Unexpected response from server (${response.status}): ${result.reason}`);
125
+ }
126
+ const { url, headers } = result.value.data;
127
+ logger.info(`Uploading cache...`);
128
+ const uploadResponse = await (0, retryOnDNSFailure_1.retryOnDNSFailure)(node_fetch_1.default)(new URL(url), {
129
+ method: 'PUT',
130
+ headers,
131
+ body: fs_1.default.createReadStream(archivePath),
132
+ });
133
+ if (!uploadResponse.ok) {
134
+ throw new Error(`Unexpected response from cache server (${uploadResponse.status}): ${uploadResponse.statusText}`);
135
+ }
136
+ logger.info(`Uploaded cache archive to ${archivePath} (${(0, artifacts_1.formatBytes)(size)}).`);
137
+ }
138
+ async function compressCacheAsync({ paths, workingDirectory, verbose, logger, }) {
139
+ const archiveDestinationDirectory = await fs_1.default.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'save-cache-'));
140
+ // Process and normalize all paths
141
+ const allFiles = [];
142
+ for (const inputPath of paths) {
143
+ // Resolve to absolute path
144
+ const absolutePath = path_1.default.isAbsolute(inputPath)
145
+ ? inputPath
146
+ : path_1.default.resolve(workingDirectory, inputPath);
147
+ try {
148
+ const stat = await fs_1.default.promises.stat(absolutePath);
149
+ if (stat.isDirectory()) {
150
+ // For directories, get all files recursively
151
+ const pattern = fast_glob_1.default.isDynamicPattern(inputPath) ? inputPath : `${absolutePath}/**`;
152
+ const dirFiles = await (0, fast_glob_1.default)(pattern, {
153
+ absolute: true,
154
+ onlyFiles: true,
155
+ cwd: fast_glob_1.default.isDynamicPattern(inputPath) ? workingDirectory : undefined,
156
+ });
157
+ for (const filePath of dirFiles) {
158
+ // Calculate the archive path
159
+ let archivePath;
160
+ if (path_1.default.isAbsolute(inputPath)) {
161
+ // For absolute input paths, check if they're within workingDirectory
162
+ const relativeToWorkdir = path_1.default.relative(workingDirectory, filePath);
163
+ if (!relativeToWorkdir.startsWith('..') && !path_1.default.isAbsolute(relativeToWorkdir)) {
164
+ // File is within working directory - use relative path
165
+ archivePath = relativeToWorkdir;
166
+ }
167
+ else {
168
+ // File is outside working directory - preserve relative structure from original path
169
+ const relativeToInput = path_1.default.relative(absolutePath, filePath);
170
+ archivePath = path_1.default.posix.join('__absolute__' + inputPath, relativeToInput);
171
+ }
172
+ }
173
+ else {
174
+ // For relative input paths, maintain relative structure
175
+ archivePath = path_1.default.relative(workingDirectory, filePath);
176
+ }
177
+ allFiles.push({ absolutePath: filePath, archivePath });
178
+ }
179
+ }
180
+ else {
181
+ // Single file
182
+ let archivePath;
183
+ if (path_1.default.isAbsolute(inputPath)) {
184
+ const relativeToWorkdir = path_1.default.relative(workingDirectory, absolutePath);
185
+ if (!relativeToWorkdir.startsWith('..') && !path_1.default.isAbsolute(relativeToWorkdir)) {
186
+ archivePath = relativeToWorkdir;
187
+ }
188
+ else {
189
+ archivePath = '__absolute__' + inputPath;
190
+ }
191
+ }
192
+ else {
193
+ archivePath = inputPath;
194
+ }
195
+ allFiles.push({ absolutePath, archivePath });
196
+ }
197
+ }
198
+ catch (error) {
199
+ logger.warn({ error }, 'Failed to resolve paths');
200
+ // Handle glob patterns
201
+ if (fast_glob_1.default.isDynamicPattern(inputPath)) {
202
+ const globFiles = await (0, fast_glob_1.default)(inputPath, {
203
+ absolute: true,
204
+ cwd: workingDirectory,
205
+ onlyFiles: true,
206
+ });
207
+ for (const filePath of globFiles) {
208
+ const archivePath = path_1.default.relative(workingDirectory, filePath);
209
+ allFiles.push({ absolutePath: filePath, archivePath });
210
+ }
211
+ }
212
+ else {
213
+ throw new Error(`Path does not exist: ${inputPath}`);
214
+ }
215
+ }
216
+ }
217
+ if (allFiles.length === 0) {
218
+ throw new Error('No files found to cache');
219
+ }
220
+ const archivePath = path_1.default.join(archiveDestinationDirectory, 'cache.tar.gz');
221
+ if (verbose) {
222
+ logger.info(`Compressing cache with ${allFiles.length} files:`);
223
+ }
224
+ // Create a temporary directory with the correct structure
225
+ const tempDir = await fs_1.default.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'cache-temp-'));
226
+ try {
227
+ // Copy all files to temp directory maintaining archive structure
228
+ for (const { absolutePath, archivePath: targetRelativePath } of allFiles) {
229
+ const targetPath = path_1.default.join(tempDir, targetRelativePath);
230
+ await fs_1.default.promises.mkdir(path_1.default.dirname(targetPath), { recursive: true });
231
+ await fs_1.default.promises.copyFile(absolutePath, targetPath);
232
+ if (verbose) {
233
+ logger.info(`- ${targetRelativePath}`);
234
+ }
235
+ }
236
+ // Create tar archive from the structured temp directory
237
+ await tar.c({
238
+ gzip: true,
239
+ file: archivePath,
240
+ cwd: tempDir,
241
+ }, allFiles.map(({ archivePath: targetPath }) => targetPath));
242
+ }
243
+ finally {
244
+ await fs_1.default.promises.rm(tempDir, { recursive: true, force: true });
245
+ }
246
+ return { archivePath };
247
+ }
248
+ //# sourceMappingURL=saveCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"saveCache.js","sourceRoot":"","sources":["../../../src/steps/functions/saveCache.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport path from 'path';\n\nimport * as tar from 'tar';\nimport fg from 'fast-glob';\nimport { bunyan } from '@expo/logger';\nimport { BuildFunction, BuildStepInput, BuildStepInputValueTypeName } from '@expo/steps';\nimport z from 'zod';\nimport nullthrows from 'nullthrows';\nimport fetch from 'node-fetch';\nimport { asyncResult } from '@expo/results';\n\nimport { retryOnDNSFailure } from '../../utils/retryOnDNSFailure';\nimport { formatBytes } from '../../utils/artifacts';\nimport { getCacheVersion } from '../utils/cache';\n\nexport function createSaveCacheFunction(): BuildFunction {\n return new BuildFunction({\n namespace: 'eas',\n id: 'save_cache',\n name: 'Save Cache',\n inputProviders: [\n BuildStepInput.createProvider({\n id: 'path',\n required: false,\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n BuildStepInput.createProvider({\n id: 'key',\n required: true,\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n ],\n fn: async (stepsCtx, { env, inputs }) => {\n const { logger } = stepsCtx;\n\n try {\n if (stepsCtx.global.staticContext.job.platform) {\n logger.error('Caches are not supported in build jobs yet.');\n return;\n }\n\n const paths = z\n .array(z.string())\n .parse(((inputs.path.value ?? '') as string).split(/[\\r\\n]+/))\n .filter((path) => path.length > 0);\n const key = z.string().parse(inputs.key.value);\n const taskId = nullthrows(env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set');\n\n const { archivePath } = await compressCacheAsync({\n paths,\n workingDirectory: stepsCtx.workingDirectory,\n verbose: true,\n logger,\n });\n\n const { size } = await fs.promises.stat(archivePath);\n\n await uploadCacheAsync({\n logger,\n jobRunId: taskId,\n expoApiServerURL: stepsCtx.global.staticContext.expoApiServerURL,\n robotAccessToken: stepsCtx.global.staticContext.job.secrets?.robotAccessToken ?? null,\n archivePath,\n key,\n paths,\n size,\n });\n } catch (error) {\n logger.error({ err: error }, 'Failed to create cache');\n }\n },\n });\n}\n\nexport async function uploadCacheAsync({\n logger,\n jobRunId,\n expoApiServerURL,\n robotAccessToken,\n paths,\n key,\n archivePath,\n size,\n}: {\n logger: bunyan;\n jobRunId: string;\n expoApiServerURL: string;\n robotAccessToken: string;\n paths: string[];\n key: string;\n archivePath: string;\n size: number;\n}): Promise<void> {\n const response = await retryOnDNSFailure(fetch)(\n new URL('v2/turtle-caches/upload-sessions', expoApiServerURL),\n {\n method: 'POST',\n body: JSON.stringify({\n jobRunId,\n key,\n version: getCacheVersion(paths),\n size,\n }),\n headers: {\n Authorization: `Bearer ${robotAccessToken}`,\n 'Content-Type': 'application/json',\n },\n }\n );\n\n if (!response.ok) {\n if (response.status === 409) {\n logger.info(`Cache already exists, skipping upload`);\n return;\n }\n const textResult = await asyncResult(response.text());\n throw new Error(`Unexpected response from server (${response.status}): ${textResult.value}`);\n }\n\n const result = await asyncResult(response.json());\n if (!result.ok) {\n throw new Error(`Unexpected response from server (${response.status}): ${result.reason}`);\n }\n\n const { url, headers } = result.value.data;\n\n logger.info(`Uploading cache...`);\n\n const uploadResponse = await retryOnDNSFailure(fetch)(new URL(url), {\n method: 'PUT',\n headers,\n body: fs.createReadStream(archivePath),\n });\n if (!uploadResponse.ok) {\n throw new Error(\n `Unexpected response from cache server (${uploadResponse.status}): ${uploadResponse.statusText}`\n );\n }\n logger.info(`Uploaded cache archive to ${archivePath} (${formatBytes(size)}).`);\n}\n\nexport async function compressCacheAsync({\n paths,\n workingDirectory,\n verbose,\n logger,\n}: {\n paths: string[];\n workingDirectory: string;\n verbose: boolean;\n logger: bunyan;\n}): Promise<{ archivePath: string }> {\n const archiveDestinationDirectory = await fs.promises.mkdtemp(\n path.join(os.tmpdir(), 'save-cache-')\n );\n\n // Process and normalize all paths\n const allFiles: { absolutePath: string; archivePath: string }[] = [];\n\n for (const inputPath of paths) {\n // Resolve to absolute path\n const absolutePath = path.isAbsolute(inputPath)\n ? inputPath\n : path.resolve(workingDirectory, inputPath);\n\n try {\n const stat = await fs.promises.stat(absolutePath);\n\n if (stat.isDirectory()) {\n // For directories, get all files recursively\n const pattern = fg.isDynamicPattern(inputPath) ? inputPath : `${absolutePath}/**`;\n const dirFiles = await fg(pattern, {\n absolute: true,\n onlyFiles: true,\n cwd: fg.isDynamicPattern(inputPath) ? workingDirectory : undefined,\n });\n\n for (const filePath of dirFiles) {\n // Calculate the archive path\n let archivePath: string;\n\n if (path.isAbsolute(inputPath)) {\n // For absolute input paths, check if they're within workingDirectory\n const relativeToWorkdir = path.relative(workingDirectory, filePath);\n if (!relativeToWorkdir.startsWith('..') && !path.isAbsolute(relativeToWorkdir)) {\n // File is within working directory - use relative path\n archivePath = relativeToWorkdir;\n } else {\n // File is outside working directory - preserve relative structure from original path\n const relativeToInput = path.relative(absolutePath, filePath);\n archivePath = path.posix.join('__absolute__' + inputPath, relativeToInput);\n }\n } else {\n // For relative input paths, maintain relative structure\n archivePath = path.relative(workingDirectory, filePath);\n }\n\n allFiles.push({ absolutePath: filePath, archivePath });\n }\n } else {\n // Single file\n let archivePath: string;\n\n if (path.isAbsolute(inputPath)) {\n const relativeToWorkdir = path.relative(workingDirectory, absolutePath);\n if (!relativeToWorkdir.startsWith('..') && !path.isAbsolute(relativeToWorkdir)) {\n archivePath = relativeToWorkdir;\n } else {\n archivePath = '__absolute__' + inputPath;\n }\n } else {\n archivePath = inputPath;\n }\n\n allFiles.push({ absolutePath, archivePath });\n }\n } catch (error) {\n logger.warn({ error }, 'Failed to resolve paths');\n // Handle glob patterns\n if (fg.isDynamicPattern(inputPath)) {\n const globFiles = await fg(inputPath, {\n absolute: true,\n cwd: workingDirectory,\n onlyFiles: true,\n });\n\n for (const filePath of globFiles) {\n const archivePath = path.relative(workingDirectory, filePath);\n allFiles.push({ absolutePath: filePath, archivePath });\n }\n } else {\n throw new Error(`Path does not exist: ${inputPath}`);\n }\n }\n }\n\n if (allFiles.length === 0) {\n throw new Error('No files found to cache');\n }\n\n const archivePath = path.join(archiveDestinationDirectory, 'cache.tar.gz');\n\n if (verbose) {\n logger.info(`Compressing cache with ${allFiles.length} files:`);\n }\n\n // Create a temporary directory with the correct structure\n const tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'cache-temp-'));\n\n try {\n // Copy all files to temp directory maintaining archive structure\n for (const { absolutePath, archivePath: targetRelativePath } of allFiles) {\n const targetPath = path.join(tempDir, targetRelativePath);\n await fs.promises.mkdir(path.dirname(targetPath), { recursive: true });\n await fs.promises.copyFile(absolutePath, targetPath);\n\n if (verbose) {\n logger.info(`- ${targetRelativePath}`);\n }\n }\n\n // Create tar archive from the structured temp directory\n await tar.c(\n {\n gzip: true,\n file: archivePath,\n cwd: tempDir,\n },\n allFiles.map(({ archivePath: targetPath }) => targetPath)\n );\n } finally {\n await fs.promises.rm(tempDir, { recursive: true, force: true });\n }\n\n return { archivePath };\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare function getCacheVersion(paths: string[]): string;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCacheVersion = getCacheVersion;
4
+ const crypto_1 = require("crypto");
5
+ function getCacheVersion(paths) {
6
+ return (0, crypto_1.createHash)('sha256')
7
+ .update(`${process.platform}@${process.arch}#${paths.join('|')}`)
8
+ .digest('hex');
9
+ }
10
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/steps/utils/cache.ts"],"names":[],"mappings":";;AAEA,0CAIC;AAND,mCAAoC;AAEpC,SAAgB,eAAe,CAAC,KAAe;IAC7C,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;SAChE,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC","sourcesContent":["import { createHash } from 'crypto';\n\nexport function getCacheVersion(paths: string[]): string {\n return createHash('sha256')\n .update(`${process.platform}@${process.arch}#${paths.join('|')}`)\n .digest('hex');\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/build-tools",
3
- "version": "1.0.221",
3
+ "version": "1.0.223",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -85,5 +85,5 @@
85
85
  "node": "20.14.0",
86
86
  "yarn": "1.22.21"
87
87
  },
88
- "gitHead": "d199b9a2d4852d1711374e7db54e3ffdcad4edb4"
88
+ "gitHead": "492fbe5e13ef6536391219b7d6aba3f7c5e9e28a"
89
89
  }