{"version":3,"file":"ssr.mjs","names":[],"sources":["../../../../@mongez/react-atom/src/ssr.tsx"],"sourcesContent":["/**\n * SSR helpers.\n *\n * These are framework-agnostic primitives for the standard SSR flow:\n *\n *   server:  store.snapshot() → serializeStore() → embed in HTML\n *   client:  readHydration()  → <AtomStoreProvider initialValues={...}>\n *\n * They're intentionally small. Next.js App Router, Remix, and TanStack\n * Start each have their own preferred transport (`__NEXT_DATA__`, loader\n * payloads, streaming chunks); the helpers here only cover the \"vanilla\"\n * inline-script-tag transport. If your framework already has a typed\n * server-to-client payload (e.g. `useLoaderData()`), skip these helpers\n * and feed the snapshot straight into `<AtomStoreProvider initialValues>`.\n */\nimport type { AtomStore } from \"@mongez/atom\";\nimport React from \"react\";\n\n/**\n * The default DOM id used by {@link HydrateAtomsScript} and\n * {@link readHydration}. Override per-provider if you need to embed\n * multiple snapshots in one document.\n */\nexport const DEFAULT_HYDRATION_SCRIPT_ID = \"__mongez_atom_state\";\n\n/**\n * Build a JSON string suitable for embedding inside an HTML `<script>`\n * tag. Two safety steps beyond a plain `JSON.stringify`:\n *\n *   1. The closing tag sequence `</` is escaped to `<\\/` so an atom value\n *      containing literal HTML cannot break out of the script element.\n *   2. The U+2028 / U+2029 line separators (which are valid JSON but not\n *      valid JavaScript string literals) are escaped.\n */\nexport function serializeSnapshot(\n  snapshot: Record<string, unknown>,\n  options: {\n    /**\n     * Custom replacer passed through to `JSON.stringify`.\n     */\n    replacer?: (key: string, value: unknown) => unknown;\n    /**\n     * Pretty-printing indent. Defaults to 0 (compact).\n     */\n    space?: number;\n  } = {},\n): string {\n  const json = JSON.stringify(\n    snapshot,\n    options.replacer as any,\n    options.space,\n  );\n  return json\n    .replace(/<\\/(script)/gi, \"<\\\\/$1\")\n    .replace(/\\u2028/g, \"\\\\u2028\")\n    .replace(/\\u2029/g, \"\\\\u2029\");\n}\n\n/**\n * Convenience that snapshots a store and serializes the result in one call.\n *\n *   const payload = serializeStore(serverStore);\n *   // payload is a script-safe JSON string\n */\nexport function serializeStore(\n  store: AtomStore,\n  options?: Parameters<typeof serializeSnapshot>[1],\n): string {\n  return serializeSnapshot(store.snapshot(), options);\n}\n\nexport type HydrateAtomsScriptProps = {\n  /**\n   * The serialized snapshot to embed. Pass either a pre-serialized string\n   * (from {@link serializeStore}) or a raw snapshot object — the component\n   * will serialize it for you.\n   */\n  snapshot: Record<string, unknown> | string;\n  /**\n   * DOM id for the `<script>` element. Defaults to\n   * {@link DEFAULT_HYDRATION_SCRIPT_ID}. Set this when embedding multiple\n   * stores in one document (e.g. a shell + a route-level boundary).\n   */\n  id?: string;\n  /**\n   * `nonce` for CSP-protected pages.\n   */\n  nonce?: string;\n};\n\n/**\n * Renders an inline `<script type=\"application/json\">` carrying a store\n * snapshot for the client to pick up.\n *\n * Place this once per `<AtomStoreProvider>` you want to hydrate. The\n * matching client-side call is {@link readHydration}.\n *\n *   // server\n *   <AtomStoreProvider store={serverStore}>\n *     <App />\n *     <HydrateAtomsScript snapshot={serverStore.snapshot()} />\n *   </AtomStoreProvider>\n *\n *   // client root\n *   <AtomStoreProvider initialValues={readHydration() ?? undefined}>\n *     <App />\n *   </AtomStoreProvider>\n */\nexport function HydrateAtomsScript({\n  snapshot,\n  id = DEFAULT_HYDRATION_SCRIPT_ID,\n  nonce,\n}: HydrateAtomsScriptProps) {\n  const serialized =\n    typeof snapshot === \"string\" ? snapshot : serializeSnapshot(snapshot);\n\n  return (\n    <script\n      id={id}\n      type=\"application/json\"\n      nonce={nonce}\n      // The serializer already neutralized `</script>` and the line\n      // separators, so dangerouslySetInnerHTML is safe here.\n      dangerouslySetInnerHTML={{ __html: serialized }}\n    />\n  );\n}\n\n/**\n * Read a hydration snapshot embedded via {@link HydrateAtomsScript} from\n * the current document.\n *\n * - On the server (no `document`), returns `null`.\n * - When the script tag is missing, returns `null`.\n * - When the script body is not valid JSON, returns `null` and logs the\n *   error via `console.error` (so a malformed payload is visible during\n *   development but does not crash hydration).\n */\nexport function readHydration(\n  id: string = DEFAULT_HYDRATION_SCRIPT_ID,\n): Record<string, unknown> | null {\n  if (typeof document === \"undefined\") return null;\n  const el = document.getElementById(id);\n  if (!el) return null;\n  try {\n    return JSON.parse(el.textContent ?? \"null\") as\n      | Record<string, unknown>\n      | null;\n  } catch (err) {\n    // eslint-disable-next-line no-console\n    console.error(\n      `[@mongez/react-atom] Could not parse hydration script #${id}:`,\n      err,\n    );\n    return null;\n  }\n}\n"],"mappings":";;;;;;;;;AAuBA,MAAa,8BAA8B;;;;;;;;;;AAW3C,SAAgB,kBACd,UACA,UASI,CAAC,GACG;CAMR,OALa,KAAK,UAChB,UACA,QAAQ,UACR,QAAQ,KAEA,EACP,QAAQ,iBAAiB,QAAQ,EACjC,QAAQ,WAAW,SAAS,EAC5B,QAAQ,WAAW,SAAS;AACjC;;;;;;;AAQA,SAAgB,eACd,OACA,SACQ;CACR,OAAO,kBAAkB,MAAM,SAAS,GAAG,OAAO;AACpD;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,mBAAmB,EACjC,UACA,KAAK,6BACL,SAC0B;CAI1B,OACE,oBAAC,UAAD;EACM;EACJ,MAAK;EACE;EAGP,yBAAyB,EAAE,QAT7B,OAAO,aAAa,WAAW,WAAW,kBAAkB,QAAQ,EASpB;CAC/C;AAEL;;;;;;;;;;;AAYA,SAAgB,cACd,KAAa,6BACmB;CAChC,IAAI,OAAO,aAAa,aAAa,OAAO;CAC5C,MAAM,KAAK,SAAS,eAAe,EAAE;CACrC,IAAI,CAAC,IAAI,OAAO;CAChB,IAAI;EACF,OAAO,KAAK,MAAM,GAAG,eAAe,MAAM;CAG5C,SAAS,KAAK;EAEZ,QAAQ,MACN,0DAA0D,GAAG,IAC7D,GACF;EACA,OAAO;CACT;AACF"}