UNPKG

@open-condo/miniapp-utils

Version:

A set of helper functions / components / hooks used to build new condo apps fast

1 lines 7.17 kB
{"version":3,"sources":["../../src/helpers/cookies.ts"],"sourcesContent":["import { getCookie } from 'cookies-next'\nimport { createContext, useContext } from 'react'\n\nimport type { IncomingMessage, ServerResponse } from 'http'\nimport type { Context } from 'react'\n\nconst SSR_COOKIES_DEFAULT_PROP_NAME = '__SSR_COOKIES__'\n\nexport type SSRCookiesContextValues<CookiesList extends ReadonlyArray<string>> = Record<CookiesList[number], string | null>\n\ntype Optional<T> = T | undefined\n\ntype SSRProps<PropsType extends Record<string, unknown>> = {\n props?: PropsType\n}\n\ntype SSRPropsWithCookies<\n PropsType extends Record<string, unknown>,\n CookiesList extends ReadonlyArray<string>,\n CookiesPropName extends string = typeof SSR_COOKIES_DEFAULT_PROP_NAME,\n> = {\n props: PropsType & {\n [K in CookiesPropName]?: SSRCookiesContextValues<CookiesList>\n }\n}\n\nexport type UseSSRCookiesExtractor<\n CookiesList extends ReadonlyArray<string>,\n CookiesPropName extends string = typeof SSR_COOKIES_DEFAULT_PROP_NAME,\n> = <PropsType extends Record<string, unknown>>(pageParams: SSRPropsWithCookies<PropsType, CookiesList, CookiesPropName>['props']) => SSRCookiesContextValues<CookiesList>\n\nexport type UseSSRCookies<CookiesList extends ReadonlyArray<string>> = () => SSRCookiesContextValues<CookiesList>\n\n/**\n * Helper that allows you to pass cookies from the request directly to the SSR,\n * thus avoiding layout shifts and loading states.\n *\n * NOTE: You should not use this tool to pass secure http-only cookies to the client,\n * that's why each application must define the list of allowed cookies itself.\n *\n * @example Init helper and export utils for app\n * import { SSRCookiesHelper } from '@open-condo/miniapp-utils/helpers/cookies'\n * import type { SSRCookiesContextValues } from '@open-condo/miniapp-utils/helpers/cookies'\n *\n * import type { Context } from 'react'\n *\n * // NOTE: put here only cookies needed in SRR (hydration), does not put http-only cookies here\n * const VITAL_COOKIES = ['residentId', 'isLayoutMinified'] as const\n *\n * const cookieHelper = new SSRCookiesHelper(VITAL_COOKIES)\n *\n * export const extractSSRCookies = cookieHelper.extractSSRCookies\n * export const useSSRCookiesExtractor = cookieHelper.generateUseSSRCookiesExtractorHook()\n * export const useSSRCookies = cookieHelper.generateUseSSRCookiesHook()\n * export const SSRCookiesContext = cookieHelper.getContext() as Context<SSRCookiesContextValues<typeof VITAL_COOKIES>>\n *\n * @example Extract cookies in getServerSideProps / getInitialProps\n * import { extractSSRCookies } from '@/domains/common/utils/ssr'\n *\n * export const getServerSideProps = async ({ req, res }) => {\n * return extractSSRCookies(req, res, {\n * props: { ... }\n * })\n * }\n *\n * @example Pass extracted cookies to React context in your _app.ts\n * import { SSRCookiesContext } from '@/domains/common/utils/ssr'\n *\n * export default function App ({ Component, pageProps }: AppProps): ReactNode {\n * const ssrCookies = useSSRCookiesExtractor(pageProps)\n *\n * return (\n * <SSRCookiesContext.Provider value={ssrCookies}>\n * <Component {...pageProps} />\n * </SSRCookiesContext.Provider>\n * )\n * }\n *\n * @example Use extracted cookies anywhere in your app.\n * // /domains/common/components/Layout.tsx\n * import { useState } from 'react'\n * import { useSSRCookies } from '@/domains/common/utils/ssr'\n *\n * import type { FC } from 'react'\n *\n * export const Layout: FC = () => {\n * const { isLayoutMinified } = useSSRCookies()\n *\n * const [layoutMinified, setLayoutMinified] = useState(isLayoutMinified === 'true')\n *\n * return {\n * // ...\n * }\n * }\n */\nexport class SSRCookiesHelper<\n CookiesList extends ReadonlyArray<string>,\n CookiesPropName extends string = typeof SSR_COOKIES_DEFAULT_PROP_NAME,\n> {\n allowedCookies: CookiesList\n propName: CookiesPropName\n private readonly context: Context<SSRCookiesContextValues<CookiesList>>\n private readonly defaultValues: SSRCookiesContextValues<CookiesList>\n\n constructor (allowedCookies: CookiesList, propName?: CookiesPropName) {\n this.allowedCookies = allowedCookies\n this.propName = propName || SSR_COOKIES_DEFAULT_PROP_NAME as CookiesPropName\n this.defaultValues = Object.fromEntries(allowedCookies.map(key => [key, null])) as SSRCookiesContextValues<CookiesList>\n this.context = createContext<SSRCookiesContextValues<CookiesList>>(this.defaultValues)\n\n this.extractSSRCookies = this.extractSSRCookies.bind(this)\n }\n\n getContext (): Context<SSRCookiesContextValues<CookiesList>> {\n return this.context\n }\n\n generateUseSSRCookiesExtractorHook (): UseSSRCookiesExtractor<CookiesList, CookiesPropName> {\n const defaultValues = this.defaultValues\n const propName = this.propName\n\n return function useSSRCookiesExtractor<PropsType extends Record<string, unknown>> (\n pageProps: SSRPropsWithCookies<PropsType, CookiesList, CookiesPropName>['props']\n ): SSRCookiesContextValues<CookiesList> {\n return pageProps[propName] || defaultValues\n }\n }\n\n generateUseSSRCookiesHook (): UseSSRCookies<CookiesList> {\n const context = this.context\n\n return function useSSRCookies (): SSRCookiesContextValues<CookiesList> {\n return useContext(context)\n }\n }\n\n extractSSRCookies<PropsType extends Record<string, unknown>> (\n req: Optional<IncomingMessage>,\n res: Optional<ServerResponse>,\n pageParams: SSRProps<PropsType>\n ): SSRPropsWithCookies<PropsType, CookiesList, CookiesPropName> {\n return {\n ...pageParams,\n props: {\n ...pageParams.props,\n [this.propName]: Object.fromEntries(\n Object.keys(this.defaultValues).map(key => [\n key,\n getCookie(key, { req, res }) || null,\n ])\n ),\n },\n } as SSRPropsWithCookies<PropsType, CookiesList, CookiesPropName>\n }\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,eAAe,kBAAkB;AAK1C,IAAM,gCAAgC;AAyF/B,IAAM,mBAAN,MAGL;AAAA,EAME,YAAa,gBAA6B,UAA4B;AAClE,SAAK,iBAAiB;AACtB,SAAK,WAAW,YAAY;AAC5B,SAAK,gBAAgB,OAAO,YAAY,eAAe,IAAI,SAAO,CAAC,KAAK,IAAI,CAAC,CAAC;AAC9E,SAAK,UAAU,cAAoD,KAAK,aAAa;AAErF,SAAK,oBAAoB,KAAK,kBAAkB,KAAK,IAAI;AAAA,EAC7D;AAAA,EAEA,aAA6D;AACzD,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,qCAA4F;AACxF,UAAM,gBAAgB,KAAK;AAC3B,UAAM,WAAW,KAAK;AAEtB,WAAO,SAAS,uBACZ,WACoC;AACpC,aAAO,UAAU,QAAQ,KAAK;AAAA,IAClC;AAAA,EACJ;AAAA,EAEA,4BAAyD;AACrD,UAAM,UAAU,KAAK;AAErB,WAAO,SAAS,gBAAuD;AACnE,aAAO,WAAW,OAAO;AAAA,IAC7B;AAAA,EACJ;AAAA,EAEA,kBACI,KACA,KACA,YAC6D;AAC7D,WAAO;AAAA,MACH,GAAG;AAAA,MACH,OAAO;AAAA,QACH,GAAG,WAAW;AAAA,QACd,CAAC,KAAK,QAAQ,GAAG,OAAO;AAAA,UACpB,OAAO,KAAK,KAAK,aAAa,EAAE,IAAI,SAAO;AAAA,YACvC;AAAA,YACA,UAAU,KAAK,EAAE,KAAK,IAAI,CAAC,KAAK;AAAA,UACpC,CAAC;AAAA,QACL;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;","names":[]}