// ── What core hands this module, on the client side ──────────────────────── // // The client twin of `server/core.js`, and deliberately much simpler than it. // Every page imports its layout, its state components and its hooks from here, // so the boundary is one file. The normative contract is MODULE_API.md §3.2 and // §3.4. // // **Why this is a plain read and the server's is a lazy accessor.** On the // server, `ctx` arrives at `register(ctx)` — after every `require` has already // run — so `server/core.js` has to defer resolution to call time or a router // would capture `undefined` at file scope. There is no such gap here. // `window.__rg` is published by core's own bundle (client/src/modules/shared.js), // and every module chunk is a deferred script the server injects *after* that // bundle's tag, so by the time the first line of this file executes the global // is already there. Reading it once, at module scope, is safe — and it means a // component keeps the ordinary `import { PageHeader } from '…'` shape rather // than being wrapped in an accessor that would cost it its identity. // // The absent-global case is handled by `shim/rg.js`, which every shim beside it // also goes through — the shims touch the global before this file does, so a // check here would be unreachable. import { createElement } from 'react' import { createRoot } from 'react-dom/client' import { Link } from 'react-router-dom' import { rg as shared } from './shim/rg.js' const rg = shared() // ── The shared-dependency self-check ─────────────────────────────────────── // // Keep this. There are two BUILD guards on the same rule — `assertSharedNotBundled` // in vite.config.js at resolution time, and `scripts/checkExternals.js` on the // finished artifact — and both reason about the chunk in isolation. Neither can // see the one failure that only exists once the chunk meets a core: a // `window.__rg` whose React is not the React that rendered the page. // // Identity is the only question worth asking. A second React satisfies every // type check, renders its first element happily, and then throws about an invalid // hook call somewhere unrelated — in a component that has nothing to do with it. if (createElement !== rg.react.createElement || createRoot !== rg.reactDom.createRoot || Link !== rg.router.Link) { console.error( '[rust] the bindings this chunk imported are not the ones core published — it has bundled ' + 'its own copy of a shared dependency. Check the aliases in vite.config.js (MODULE_API.md §3.6).', ) } // The curated kit (§3.4). Nine exports, and it is CLOSED: layout, headings, the // three data-page states, the fetch hook, read-only access to the session and the // site's settings, and `Slot`. Anything else your pages need — tables, tabs, an // editor — you bundle yourself, in a `components/` directory of your own. // // `Slot` is the one that is not a widget. It renders a place THIS module declared // for core to fill (`entry.jsx`, and `routes/public/Clan.jsx` where two are used): // the inverted direction of the extension-slot mechanism, added in 1.6.0. It is in // the shared kit rather than reimplementable for the reason the whole kit exists — // a second error boundary with different behaviour would be a second bug, and what // this one contains is CORE's content failing inside YOUR page. // // Closed is a real constraint and it is the price of the boundary being worth // anything: adding a member is a minor `MODULE_API_VERSION` bump, and changing an // existing prop on a kit component is a major one. Use them, though. A module page that // ships its own layout is a page that stops looking like the site it is installed // in, and drifts further every time core changes. export const { PublicLayout, PageHeader, Loading, ErrorState, EmptyState, useAsync, useAuth, useSite, Slot, } = rg.ui // The registry, for entry.jsx. Everything else here is read by pages. export const registry = rg.registry // The core API version this module was loaded against. Logged by entry.jsx — // `module.json`'s `coreApi` range is checked by the loader before this file is // ever served, so there is nothing to re-check, only something to report. export const coreApiVersion = rg.version export default rg