{"version":3,"sources":["../../../../src/server/app-render/instant-validation/instant-config.tsx"],"sourcesContent":["import { getLayoutOrPageModule } from '../../lib/app-dir-module'\nimport type { LoaderTree } from '../../lib/app-dir-module'\nimport { parseLoaderTree } from '../../../shared/lib/router/utils/parse-loader-tree'\nimport {\n  PAGE_SEGMENT_KEY,\n  DEFAULT_SEGMENT_KEY,\n} from '../../../shared/lib/segment'\nimport {\n  UNDERSCORE_GLOBAL_ERROR_ROUTE,\n  UNDERSCORE_NOT_FOUND_ROUTE,\n} from '../../../shared/lib/entry-constants'\nimport type { Segment } from '../../../shared/lib/app-router-types'\nimport type {\n  AppSegmentConfig,\n  InstantSample,\n} from '../../../build/segment-config/app/app-segment-config'\nimport {\n  workAsyncStorage,\n  type WorkStore,\n} from '../work-async-storage.external'\nimport { InvariantError } from '../../../shared/lib/invariant-error'\n\n/**\n * True when an unconfigured segment should be treated as implicitly\n * validated under a non-manual default validation level. Only page and\n * default segments qualify — layouts do not validate on their own.\n */\nexport function isImplicitValidationSegment(segment: Segment): boolean {\n  const key = typeof segment === 'string' ? segment : segment[0]\n  return (\n    key === PAGE_SEGMENT_KEY ||\n    key.startsWith(PAGE_SEGMENT_KEY) ||\n    key === DEFAULT_SEGMENT_KEY\n  )\n}\n\n/**\n * Routes for the framework-synthesized error and not-found entries. They\n * have no user-configurable escape hatch (the framework supplies the page\n * when the user hasn't), so they're excluded from implicit validation under\n * a non-manual default validation level. Even when the user provides their\n * own `global-error` or root `not-found`, these pages are special-purpose\n * error UI — opting them into validation is something the user can do\n * explicitly via `instant`.\n */\nexport function isFrameworkErrorRoute(route: string | undefined): boolean {\n  return (\n    route === UNDERSCORE_GLOBAL_ERROR_ROUTE ||\n    route === UNDERSCORE_NOT_FOUND_ROUTE\n  )\n}\n\n/**\n * Matches any `prefetch` config that enables Partial Prefetching for the\n * segment: 'partial' or 'unstable_eager'. A route with Partial Prefetching\n * enabled also runtime-caches its navigations, so this gates the runtime\n * prefetch spawn.\n */\nexport async function anySegmentHasPartialPrefetchingEnabled(\n  tree: LoaderTree\n): Promise<boolean> {\n  const { mod: layoutOrPageMod } = await getLayoutOrPageModule(tree)\n\n  // TODO(restart-on-cache-miss): Does this work correctly for client page/layout modules?\n  const prefetchConfig = layoutOrPageMod\n    ? (layoutOrPageMod as AppSegmentConfig).prefetch\n    : undefined\n  if (prefetchConfig === 'partial' || prefetchConfig === 'unstable_eager') {\n    return true\n  }\n\n  const { parallelRoutes } = parseLoaderTree(tree)\n  for (const parallelRouteKey in parallelRoutes) {\n    const parallelRoute = parallelRoutes[parallelRouteKey]\n    const hasChildPartialPrefetching =\n      await anySegmentHasPartialPrefetchingEnabled(parallelRoute)\n    if (hasChildPartialPrefetching) {\n      return true\n    }\n  }\n\n  return false\n}\n\nexport async function isPageAllowedToBlock(tree: LoaderTree): Promise<boolean> {\n  const { mod: layoutOrPageMod } = await getLayoutOrPageModule(tree)\n\n  // TODO(restart-on-cache-miss): Does this work correctly for client page/layout modules?\n  const instantConfig = layoutOrPageMod\n    ? (layoutOrPageMod as AppSegmentConfig).instant\n    : undefined\n\n  // If we encounter a non-false instant config before a instant=false,\n  // the page isn't allowed to block. The config expresses a requirement for\n  // instant UI, so we should make sure that a static shell exists.\n  // (even if it'd use runtime prefetching for client navs)\n  if (instantConfig !== undefined) {\n    if (instantConfig === false) {\n      return true\n    } else {\n      return false\n    }\n  }\n\n  const { parallelRoutes } = parseLoaderTree(tree)\n  for (const parallelRouteKey in parallelRoutes) {\n    const parallelRoute = parallelRoutes[parallelRouteKey]\n    const subtreeIsBlocking = await isPageAllowedToBlock(parallelRoute)\n    if (subtreeIsBlocking) {\n      return true\n    }\n  }\n\n  return false\n}\n\nenum VALIDATION_LEVEL {\n  WARNING = 0,\n  ERROR = 1,\n}\n\n/**\n * Walks the loader tree and checks if any segment has an `instant` config\n * that needs validating for the given mode.\n *\n * - Explicit `instant` exports are checked against mode.\n * - Page and default segments without an explicit config get implicit\n *   validation when the default validation level applies to this mode.\n * - `unstable_disableValidation` on any segment kills validation for\n *   the whole tree.\n */\nasync function anySegmentNeedsInstantValidation(\n  rootTree: LoaderTree,\n  level: VALIDATION_LEVEL\n): Promise<boolean> {\n  const workStore = workAsyncStorage.getStore()\n  if (!workStore) {\n    throw new InvariantError(\n      'anySegmentNeedsInstantValidation must run inside a WorkStore'\n    )\n  }\n  const { validationLevel } = workStore\n\n  let baseValidationLevel: number = VALIDATION_LEVEL.WARNING\n  let manualValidation: boolean = false\n  switch (validationLevel) {\n    case 'manual-warning':\n      manualValidation = true\n    // intentional fallthrough\n    case 'warning':\n      baseValidationLevel = VALIDATION_LEVEL.WARNING\n      break\n    case 'experimental-manual-error':\n      manualValidation = true\n    // intentional fallthrough\n    case 'experimental-error':\n      baseValidationLevel = VALIDATION_LEVEL.ERROR\n      break\n    default:\n      validationLevel satisfies never\n  }\n\n  const applyDefaultValidation =\n    // We need to be validating the right level\n    level <= baseValidationLevel &&\n    // We need to not be in manual validation mode\n    !manualValidation &&\n    // We don't validate framework internal routes by default\n    !isFrameworkErrorRoute(workStore.route)\n\n  let needsValidation = false\n  let disabled = false\n\n  async function visit(tree: LoaderTree): Promise<void> {\n    if (disabled) return\n\n    const { mod: layoutOrPageMod } = await getLayoutOrPageModule(tree)\n    const instantConfig = layoutOrPageMod\n      ? (layoutOrPageMod as AppSegmentConfig).instant\n      : undefined\n\n    if (instantConfig === false) {\n      // Explicit opt-out. Doesn't itself trigger validation.\n    } else if (instantConfig === true) {\n      // Explicit opt-in using the default level.\n      if (level <= baseValidationLevel) {\n        needsValidation = true\n      }\n    } else if (typeof instantConfig === 'object' && instantConfig !== null) {\n      if (\n        instantConfig.unstable_disableValidation === true ||\n        (level === VALIDATION_LEVEL.WARNING &&\n          instantConfig.unstable_disableDevValidation === true) ||\n        (level === VALIDATION_LEVEL.ERROR &&\n          instantConfig.unstable_disableBuildValidation === true)\n      ) {\n        disabled = true\n        return\n      }\n\n      if (instantConfig.level !== undefined) {\n        const configuredLevel =\n          instantConfig.level === 'experimental-error'\n            ? VALIDATION_LEVEL.ERROR\n            : VALIDATION_LEVEL.WARNING\n        if (level <= configuredLevel) {\n          needsValidation = true\n        }\n      } else if (level <= baseValidationLevel) {\n        needsValidation = true\n      }\n    } else if (applyDefaultValidation && isImplicitValidationSegment(tree[0])) {\n      // No explicit config. Implicit validation applies to page/default\n      // segments when the default level is active for this mode.\n      needsValidation = true\n    }\n\n    const { parallelRoutes } = parseLoaderTree(tree)\n    for (const parallelRouteKey in parallelRoutes) {\n      await visit(parallelRoutes[parallelRouteKey])\n      if (disabled) return\n    }\n  }\n\n  await visit(rootTree)\n  if (disabled) {\n    return false\n  }\n  return needsValidation\n}\n\nexport const anySegmentNeedsInstantValidationInDev = cacheScopedToWorkStore(\n  async (rootTree: LoaderTree): Promise<boolean> =>\n    anySegmentNeedsInstantValidation(rootTree, VALIDATION_LEVEL.WARNING)\n)\n\nexport const anySegmentNeedsInstantValidationInBuild = cacheScopedToWorkStore(\n  async (rootTree: LoaderTree): Promise<boolean> =>\n    anySegmentNeedsInstantValidation(rootTree, VALIDATION_LEVEL.ERROR)\n)\n\nexport const resolveInstantConfigSamplesForPage = async (\n  tree: LoaderTree\n): Promise<InstantSample[] | null> => {\n  const { mod: layoutOrPageMod } = await getLayoutOrPageModule(tree)\n\n  const instantConfig = layoutOrPageMod\n    ? (layoutOrPageMod as AppSegmentConfig).instant\n    : undefined\n\n  let samples: InstantSample[] | null = null\n  if (\n    instantConfig !== undefined &&\n    typeof instantConfig === 'object' &&\n    instantConfig.unstable_samples\n  ) {\n    samples = instantConfig.unstable_samples\n  }\n\n  // The samples from inner segments override samples from outer segments,\n  // i.e. a page overrides the samples from a layout.\n  // We do not perform any merging logic.\n  const { parallelRoutes } = parseLoaderTree(tree)\n  for (const parallelRouteKey in parallelRoutes) {\n    if (parallelRouteKey !== 'children') {\n      // TODO(instant-validation-build): do something with with samples from non-children slots?\n      continue\n    }\n    const childTree = parallelRoutes[parallelRouteKey]\n    const childSamples = await resolveInstantConfigSamplesForPage(childTree)\n    if (childSamples !== null) {\n      samples = childSamples\n    }\n  }\n\n  return samples\n}\n\n/**\n * A simple cache wrapper for 1-argument functions.\n * The cache will live as long as the current WorkStore,\n * i.e. it's scoped to a single request.\n */\nfunction cacheScopedToWorkStore<TArg extends WeakKey, TRes>(\n  func: (arg: TArg) => TRes\n): (arg: TArg) => TRes {\n  const resultsPerWorkStore = new WeakMap<WorkStore, WeakMap<TArg, TRes>>()\n  return (arg: TArg): TRes => {\n    const workStore = workAsyncStorage.getStore()\n    if (!workStore) {\n      throw new InvariantError(\n        `${func.name || 'cacheScopedToWorkStore callee'} must run inside a WorkStore`\n      )\n    }\n\n    let results = resultsPerWorkStore.get(workStore)\n    if (results && results.has(arg)) {\n      return results.get(arg)!\n    }\n\n    const result = func(arg)\n\n    if (!results) {\n      results = new WeakMap()\n      resultsPerWorkStore.set(workStore, results)\n    }\n    results.set(arg, result)\n\n    return result\n  }\n}\n"],"names":["anySegmentHasPartialPrefetchingEnabled","anySegmentNeedsInstantValidationInBuild","anySegmentNeedsInstantValidationInDev","isFrameworkErrorRoute","isImplicitValidationSegment","isPageAllowedToBlock","resolveInstantConfigSamplesForPage","segment","key","PAGE_SEGMENT_KEY","startsWith","DEFAULT_SEGMENT_KEY","route","UNDERSCORE_GLOBAL_ERROR_ROUTE","UNDERSCORE_NOT_FOUND_ROUTE","tree","mod","layoutOrPageMod","getLayoutOrPageModule","prefetchConfig","prefetch","undefined","parallelRoutes","parseLoaderTree","parallelRouteKey","parallelRoute","hasChildPartialPrefetching","instantConfig","instant","subtreeIsBlocking","VALIDATION_LEVEL","anySegmentNeedsInstantValidation","rootTree","level","workStore","workAsyncStorage","getStore","InvariantError","validationLevel","baseValidationLevel","manualValidation","applyDefaultValidation","needsValidation","disabled","visit","unstable_disableValidation","unstable_disableDevValidation","unstable_disableBuildValidation","configuredLevel","cacheScopedToWorkStore","samples","unstable_samples","childTree","childSamples","func","resultsPerWorkStore","WeakMap","arg","name","results","get","has","result","set"],"mappings":"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","ignoreList":[0]}