{"version":3,"sources":["../../../../src/shared/lib/segment-cache/segment-value-encoding.ts"],"sourcesContent":["import { PAGE_SEGMENT_KEY } from '../segment'\nimport type { Segment as FlightRouterStateSegment } from '../app-router-types'\n\n// TypeScript trick to simulate opaque types, like in Flow.\ntype Opaque<K, T> = T & { __brand: K }\n\nexport type SegmentRequestKeyPart = Opaque<'SegmentRequestKeyPart', string>\nexport type SegmentRequestKey = Opaque<'SegmentRequestKey', string>\n\nexport const ROOT_SEGMENT_REQUEST_KEY = '' as SegmentRequestKey\n\nexport const HEAD_REQUEST_KEY = '/_head' as SegmentRequestKey\n\nexport function createSegmentRequestKeyPart(\n  segment: FlightRouterStateSegment\n): SegmentRequestKeyPart {\n  if (typeof segment === 'string') {\n    if (segment.startsWith(PAGE_SEGMENT_KEY)) {\n      // The Flight Router State type sometimes includes the search params in\n      // the page segment. However, the Segment Cache tracks this as a separate\n      // key. So, we strip the search params here, and then add them back when\n      // the cache entry is turned back into a FlightRouterState. This is an\n      // unfortunate consequence of the FlightRouteState being used both as a\n      // transport type and as a cache key; we'll address this once more of the\n      // Segment Cache implementation has settled.\n      // TODO: We should hoist the search params out of the FlightRouterState\n      // type entirely, This is our plan for dynamic route params, too.\n      return PAGE_SEGMENT_KEY as SegmentRequestKeyPart\n    }\n    const safeName =\n      // TODO: FlightRouterState encodes Not Found routes as \"/_not-found\".\n      // But params typically don't include the leading slash. We should use\n      // a different encoding to avoid this special case.\n      segment === '/_not-found'\n        ? '_not-found'\n        : encodeToFilesystemAndURLSafeString(segment)\n    // Since this is not a dynamic segment, it's fully encoded. It does not\n    // need to be \"hydrated\" with a param value.\n    return safeName as SegmentRequestKeyPart\n  }\n\n  const name = segment[0]\n  const paramType = segment[2]\n  const safeName = encodeToFilesystemAndURLSafeString(name)\n\n  const encodedName = '$' + paramType + '$' + safeName\n  return encodedName as SegmentRequestKeyPart\n}\n\nexport function appendSegmentRequestKeyPart(\n  parentRequestKey: SegmentRequestKey,\n  parallelRouteKey: string,\n  childRequestKeyPart: SegmentRequestKeyPart\n): SegmentRequestKey {\n  // Aside from being filesystem safe, segment keys are also designed so that\n  // each segment and parallel route creates its own subdirectory. Roughly in\n  // the same shape as the source app directory. This is mostly just for easier\n  // debugging (you can open up the build folder and navigate the output); if\n  // we wanted to do we could just use a flat structure.\n\n  // Omit the parallel route key for children, since this is the most\n  // common case. Saves some bytes (and it's what the app directory does).\n  const slotKey =\n    parallelRouteKey === 'children'\n      ? childRequestKeyPart\n      : `@${encodeToFilesystemAndURLSafeString(parallelRouteKey)}/${childRequestKeyPart}`\n  return (parentRequestKey + '/' + slotKey) as SegmentRequestKey\n}\n\n// Define a regex pattern to match the most common characters found in a route\n// param. It excludes anything that might not be cross-platform filesystem\n// compatible, like |. It does not need to be precise because the fallback is to\n// just base64url-encode the whole parameter, which is fine; we just don't do it\n// by default for compactness, and for easier debugging.\nconst simpleParamValueRegex = /^[a-zA-Z0-9\\-_@]+$/\n\nfunction encodeToFilesystemAndURLSafeString(value: string) {\n  if (simpleParamValueRegex.test(value)) {\n    return value\n  }\n  // If there are any unsafe characters, base64url-encode the entire value.\n  // We also add a ! prefix so it doesn't collide with the simple case.\n  const base64url = btoa(value)\n    .replace(/\\+/g, '-') // Replace '+' with '-'\n    .replace(/\\//g, '_') // Replace '/' with '_'\n    .replace(/=+$/, '') // Remove trailing '='\n  return '!' + base64url\n}\n\nexport function convertSegmentPathToStaticExportFilename(\n  segmentPath: string\n): string {\n  return `__next${segmentPath.replace(/\\//g, '.')}.txt`\n}\n"],"names":["HEAD_REQUEST_KEY","ROOT_SEGMENT_REQUEST_KEY","appendSegmentRequestKeyPart","convertSegmentPathToStaticExportFilename","createSegmentRequestKeyPart","segment","startsWith","PAGE_SEGMENT_KEY","safeName","encodeToFilesystemAndURLSafeString","name","paramType","encodedName","parentRequestKey","parallelRouteKey","childRequestKeyPart","slotKey","simpleParamValueRegex","value","test","base64url","btoa","replace","segmentPath"],"mappings":";;;;;;;;;;;;;;;;;;IAWaA,gBAAgB;eAAhBA;;IAFAC,wBAAwB;eAAxBA;;IAwCGC,2BAA2B;eAA3BA;;IAwCAC,wCAAwC;eAAxCA;;IA5EAC,2BAA2B;eAA3BA;;;yBAbiB;AAS1B,MAAMH,2BAA2B;AAEjC,MAAMD,mBAAmB;AAEzB,SAASI,4BACdC,OAAiC;IAEjC,IAAI,OAAOA,YAAY,UAAU;QAC/B,IAAIA,QAAQC,UAAU,CAACC,yBAAgB,GAAG;YACxC,uEAAuE;YACvE,yEAAyE;YACzE,wEAAwE;YACxE,sEAAsE;YACtE,uEAAuE;YACvE,yEAAyE;YACzE,4CAA4C;YAC5C,uEAAuE;YACvE,iEAAiE;YACjE,OAAOA,yBAAgB;QACzB;QACA,MAAMC,WACJ,qEAAqE;QACrE,sEAAsE;QACtE,mDAAmD;QACnDH,YAAY,gBACR,eACAI,mCAAmCJ;QACzC,uEAAuE;QACvE,4CAA4C;QAC5C,OAAOG;IACT;IAEA,MAAME,OAAOL,OAAO,CAAC,EAAE;IACvB,MAAMM,YAAYN,OAAO,CAAC,EAAE;IAC5B,MAAMG,WAAWC,mCAAmCC;IAEpD,MAAME,cAAc,MAAMD,YAAY,MAAMH;IAC5C,OAAOI;AACT;AAEO,SAASV,4BACdW,gBAAmC,EACnCC,gBAAwB,EACxBC,mBAA0C;IAE1C,2EAA2E;IAC3E,2EAA2E;IAC3E,6EAA6E;IAC7E,2EAA2E;IAC3E,sDAAsD;IAEtD,mEAAmE;IACnE,wEAAwE;IACxE,MAAMC,UACJF,qBAAqB,aACjBC,sBACA,CAAC,CAAC,EAAEN,mCAAmCK,kBAAkB,CAAC,EAAEC,qBAAqB;IACvF,OAAQF,mBAAmB,MAAMG;AACnC;AAEA,8EAA8E;AAC9E,0EAA0E;AAC1E,gFAAgF;AAChF,gFAAgF;AAChF,wDAAwD;AACxD,MAAMC,wBAAwB;AAE9B,SAASR,mCAAmCS,KAAa;IACvD,IAAID,sBAAsBE,IAAI,CAACD,QAAQ;QACrC,OAAOA;IACT;IACA,yEAAyE;IACzE,qEAAqE;IACrE,MAAME,YAAYC,KAAKH,OACpBI,OAAO,CAAC,OAAO,KAAK,uBAAuB;KAC3CA,OAAO,CAAC,OAAO,KAAK,uBAAuB;KAC3CA,OAAO,CAAC,OAAO,IAAI,sBAAsB;;IAC5C,OAAO,MAAMF;AACf;AAEO,SAASjB,yCACdoB,WAAmB;IAEnB,OAAO,CAAC,MAAM,EAAEA,YAAYD,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC;AACvD","ignoreList":[0]}