{"version":3,"file":"ssr-client.cjs","sources":["../../src/ssr-client.tsx"],"sourcesContent":["import { isPlainObject } from '@tanstack/router-core'\n\nimport invariant from 'tiny-invariant'\n\nimport { startSerializer } from './serializer'\nimport type {\n  AnyRouter,\n  ControllablePromise,\n  MakeRouteMatch,\n} from '@tanstack/react-router'\n\nimport type { DeferredPromiseState, Manifest } from '@tanstack/router-core'\n\ndeclare global {\n  interface Window {\n    __TSR_SSR__?: StartSsrGlobal\n  }\n}\n\nexport interface StartSsrGlobal {\n  matches: Array<SsrMatch>\n  streamedValues: Record<\n    string,\n    {\n      value: any\n      parsed: any\n    }\n  >\n  cleanScripts: () => void\n  dehydrated?: any\n  initMatch: (match: SsrMatch) => void\n  resolvePromise: (opts: {\n    matchId: string\n    id: number\n    promiseState: DeferredPromiseState<any>\n  }) => void\n  injectChunk: (opts: { matchId: string; id: number; chunk: string }) => void\n  closeStream: (opts: { matchId: string; id: number }) => void\n}\n\nexport interface SsrMatch {\n  id: string\n  __beforeLoadContext: string\n  loaderData?: string\n  error?: string\n  extracted?: Array<ClientExtractedEntry>\n  updatedAt: MakeRouteMatch['updatedAt']\n  status: MakeRouteMatch['status']\n}\n\nexport type ClientExtractedEntry =\n  | ClientExtractedStream\n  | ClientExtractedPromise\n\nexport interface ClientExtractedPromise extends ClientExtractedBaseEntry {\n  type: 'promise'\n  value?: ControllablePromise<any>\n}\n\nexport interface ClientExtractedStream extends ClientExtractedBaseEntry {\n  type: 'stream'\n  value?: ReadableStream & { controller?: ReadableStreamDefaultController }\n}\n\nexport interface ClientExtractedBaseEntry {\n  type: string\n  path: Array<string>\n}\n\nexport interface ResolvePromiseState {\n  matchId: string\n  id: number\n  promiseState: DeferredPromiseState<any>\n}\n\nexport interface DehydratedRouter {\n  manifest: Manifest | undefined\n  dehydratedData: any\n}\n\nexport function hydrate(router: AnyRouter) {\n  invariant(\n    window.__TSR_SSR__?.dehydrated,\n    'Expected to find a dehydrated data on window.__TSR_SSR__.dehydrated... but we did not. Please file an issue!',\n  )\n\n  const { manifest, dehydratedData } = startSerializer.parse(\n    window.__TSR_SSR__.dehydrated,\n  ) as DehydratedRouter\n\n  router.ssr = {\n    manifest,\n    serializer: startSerializer,\n  }\n\n  router.clientSsr = {\n    getStreamedValue: <T,>(key: string): T | undefined => {\n      if (router.isServer) {\n        return undefined\n      }\n\n      const streamedValue = window.__TSR_SSR__?.streamedValues[key]\n\n      if (!streamedValue) {\n        return\n      }\n\n      if (!streamedValue.parsed) {\n        streamedValue.parsed = router.ssr!.serializer.parse(streamedValue.value)\n      }\n\n      return streamedValue.parsed\n    },\n  }\n\n  // Hydrate the router state\n  const matches = router.matchRoutes(router.state.location)\n  // kick off loading the route chunks\n  const routeChunkPromise = Promise.all(\n    matches.map((match) => {\n      const route = router.looseRoutesById[match.routeId]!\n      return router.loadRouteChunk(route)\n    }),\n  )\n  matches.forEach((match) => {\n    const route = router.looseRoutesById[match.routeId]!\n\n    // Right after hydration and before the first render, we need to rehydrate each match\n    // This includes rehydrating the loaderData and also using the beforeLoadContext\n    // to reconstruct any context that was serialized on the server\n\n    const dehydratedMatch = window.__TSR_SSR__!.matches.find(\n      (d) => d.id === match.id,\n    )\n\n    if (dehydratedMatch) {\n      Object.assign(match, dehydratedMatch)\n\n      const parentMatch = matches[match.index - 1]\n      const parentContext = parentMatch?.context ?? router.options.context ?? {}\n\n      // Handle beforeLoadContext\n      if (dehydratedMatch.__beforeLoadContext) {\n        match.__beforeLoadContext = router.ssr!.serializer.parse(\n          dehydratedMatch.__beforeLoadContext,\n        ) as any\n\n        match.context = {\n          ...parentContext,\n          ...match.__routeContext,\n          ...match.__beforeLoadContext,\n        }\n      }\n\n      // Handle loaderData\n      if (dehydratedMatch.loaderData) {\n        match.loaderData = router.ssr!.serializer.parse(\n          dehydratedMatch.loaderData,\n        )\n      }\n\n      // Handle error\n      if (dehydratedMatch.error) {\n        match.error = router.ssr!.serializer.parse(dehydratedMatch.error)\n      }\n\n      // Handle extracted\n      ;(match as unknown as SsrMatch).extracted?.forEach((ex) => {\n        deepMutableSetByPath(match, ['loaderData', ...ex.path], ex.value)\n      })\n    } else {\n      Object.assign(match, {\n        status: 'success',\n        updatedAt: Date.now(),\n      })\n    }\n\n    const assetContext = {\n      matches: router.state.matches,\n      match,\n      params: match.params,\n      loaderData: match.loaderData,\n    }\n    const headFnContent = route.options.head?.(assetContext)\n\n    const scripts = route.options.scripts?.(assetContext)\n\n    match.meta = headFnContent?.meta\n    match.links = headFnContent?.links\n    match.headScripts = headFnContent?.scripts\n    match.scripts = scripts\n\n    return match\n  })\n\n  router.__store.setState((s) => {\n    return {\n      ...s,\n      matches,\n    }\n  })\n\n  // Allow the user to handle custom hydration data\n  router.options.hydrate?.(dehydratedData)\n  return routeChunkPromise\n}\n\nfunction deepMutableSetByPath<T>(obj: T, path: Array<string>, value: any) {\n  // mutable set by path retaining array and object references\n  if (path.length === 1) {\n    ;(obj as any)[path[0]!] = value\n  }\n\n  const [key, ...rest] = path\n\n  if (Array.isArray(obj)) {\n    deepMutableSetByPath(obj[Number(key)], rest, value)\n  } else if (isPlainObject(obj)) {\n    deepMutableSetByPath((obj as any)[key!], rest, value)\n  }\n}\n"],"names":["startSerializer","_a","_c","_b","isPlainObject"],"mappings":";;;;;AAgFO,SAAS,QAAQ,QAAmB;;AACzC;AAAA,KACE,YAAO,gBAAP,mBAAoB;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,EAAE,UAAU,eAAe,IAAIA,WAAgB,gBAAA;AAAA,IACnD,OAAO,YAAY;AAAA,EACrB;AAEA,SAAO,MAAM;AAAA,IACX;AAAA,IACA,YAAYA,WAAAA;AAAAA,EACd;AAEA,SAAO,YAAY;AAAA,IACjB,kBAAkB,CAAK,QAA+B;;AACpD,UAAI,OAAO,UAAU;AACZ,eAAA;AAAA,MAAA;AAGT,YAAM,iBAAgBC,MAAA,OAAO,gBAAP,gBAAAA,IAAoB,eAAe;AAEzD,UAAI,CAAC,eAAe;AAClB;AAAA,MAAA;AAGE,UAAA,CAAC,cAAc,QAAQ;AACzB,sBAAc,SAAS,OAAO,IAAK,WAAW,MAAM,cAAc,KAAK;AAAA,MAAA;AAGzE,aAAO,cAAc;AAAA,IAAA;AAAA,EAEzB;AAGA,QAAM,UAAU,OAAO,YAAY,OAAO,MAAM,QAAQ;AAExD,QAAM,oBAAoB,QAAQ;AAAA,IAChC,QAAQ,IAAI,CAAC,UAAU;AACrB,YAAM,QAAQ,OAAO,gBAAgB,MAAM,OAAO;AAC3C,aAAA,OAAO,eAAe,KAAK;AAAA,IACnC,CAAA;AAAA,EACH;AACQ,UAAA,QAAQ,CAAC,UAAU;;AACzB,UAAM,QAAQ,OAAO,gBAAgB,MAAM,OAAO;AAM5C,UAAA,kBAAkB,OAAO,YAAa,QAAQ;AAAA,MAClD,CAAC,MAAM,EAAE,OAAO,MAAM;AAAA,IACxB;AAEA,QAAI,iBAAiB;AACZ,aAAA,OAAO,OAAO,eAAe;AAEpC,YAAM,cAAc,QAAQ,MAAM,QAAQ,CAAC;AAC3C,YAAM,iBAAgB,2CAAa,YAAW,OAAO,QAAQ,WAAW,CAAC;AAGzE,UAAI,gBAAgB,qBAAqB;AACjC,cAAA,sBAAsB,OAAO,IAAK,WAAW;AAAA,UACjD,gBAAgB;AAAA,QAClB;AAEA,cAAM,UAAU;AAAA,UACd,GAAG;AAAA,UACH,GAAG,MAAM;AAAA,UACT,GAAG,MAAM;AAAA,QACX;AAAA,MAAA;AAIF,UAAI,gBAAgB,YAAY;AACxB,cAAA,aAAa,OAAO,IAAK,WAAW;AAAA,UACxC,gBAAgB;AAAA,QAClB;AAAA,MAAA;AAIF,UAAI,gBAAgB,OAAO;AACzB,cAAM,QAAQ,OAAO,IAAK,WAAW,MAAM,gBAAgB,KAAK;AAAA,MAAA;AAIhE,OAAAA,MAAA,MAA8B,cAA9B,gBAAAA,IAAyC,QAAQ,CAAC,OAAO;AACpC,6BAAA,OAAO,CAAC,cAAc,GAAG,GAAG,IAAI,GAAG,GAAG,KAAK;AAAA,MAAA;AAAA,IACjE,OACI;AACL,aAAO,OAAO,OAAO;AAAA,QACnB,QAAQ;AAAA,QACR,WAAW,KAAK,IAAI;AAAA,MAAA,CACrB;AAAA,IAAA;AAGH,UAAM,eAAe;AAAA,MACnB,SAAS,OAAO,MAAM;AAAA,MACtB;AAAA,MACA,QAAQ,MAAM;AAAA,MACd,YAAY,MAAM;AAAA,IACpB;AACA,UAAM,iBAAgBC,OAAAC,MAAA,MAAM,SAAQ,SAAd,gBAAAD,IAAA,KAAAC,KAAqB;AAE3C,UAAM,WAAU,iBAAM,SAAQ,YAAd,4BAAwB;AAExC,UAAM,OAAO,+CAAe;AAC5B,UAAM,QAAQ,+CAAe;AAC7B,UAAM,cAAc,+CAAe;AACnC,UAAM,UAAU;AAET,WAAA;AAAA,EAAA,CACR;AAEM,SAAA,QAAQ,SAAS,CAAC,MAAM;AACtB,WAAA;AAAA,MACL,GAAG;AAAA,MACH;AAAA,IACF;AAAA,EAAA,CACD;AAGM,qBAAA,SAAQ,YAAR,4BAAkB;AAClB,SAAA;AACT;AAEA,SAAS,qBAAwB,KAAQ,MAAqB,OAAY;AAEpE,MAAA,KAAK,WAAW,GAAG;AACnB,QAAY,KAAK,CAAC,CAAE,IAAI;AAAA,EAAA;AAG5B,QAAM,CAAC,KAAK,GAAG,IAAI,IAAI;AAEnB,MAAA,MAAM,QAAQ,GAAG,GAAG;AACtB,yBAAqB,IAAI,OAAO,GAAG,CAAC,GAAG,MAAM,KAAK;AAAA,EAAA,WACzCC,WAAAA,cAAc,GAAG,GAAG;AAC7B,yBAAsB,IAAY,GAAI,GAAG,MAAM,KAAK;AAAA,EAAA;AAExD;;"}