THROWAWAY BRANCH — evidence for the Phase 1 contract, never merged. See
modules/uo/SPIKE.md and docs/website/MODULE_API.md Part 7.
The six public spawn-atlas routes now live in modules/uo/, reached only through
the ctx/register surface, with the client half loading as a prebuilt ESM chunk.
All three exit criteria met:
• zero internal-file imports from the module into core; the built chunk has
zero bare import specifiers and bundles no React
• routes.manifest.json AND routes.guards.json are byte-identical
• /uo/atlas renders from /modules/uo/entry.js under script-src 'self' with
zero CSP violation reports
729 core tests and 81 module tests pass. Verified end to end against the real
database: the schema fragment replays after core's, onBoot runs the atlas
refresh, and the six API URLs answer unchanged.
Two things the spike changed in the contract:
• ctx.express / ctx.validator. A module lives outside server/, so Node never
reaches server/node_modules and require('express') fails outright — the
server-side twin of the one-React rule, which §2.6 had only for the client.
• window.__rg.jsxRuntime, so a module can build with the automatic JSX
runtime its tooling already assumes rather than being forced to classic.
And it confirmed §6.1 empirically: regenerating the OpenAPI spec silently
deleted all 361 lines of the atlas paths with "Swagger-autogen: Success", while
the route manifest kept all six in the same run. That is exactly the
static-analysis-vs-runtime split the fragment merge exists to prevent.
Co-Authored-By: Claude <noreply@anthropic.com>
410 lines
19 KiB
JavaScript
410 lines
19 KiB
JavaScript
const B = window.__rg.jsxRuntime, { jsx: t, jsxs: l, Fragment: A } = B, U = window.__rg.react, {
|
||
useState: h,
|
||
useEffect: I,
|
||
useMemo: j,
|
||
useCallback: W,
|
||
useRef: ne,
|
||
useContext: se,
|
||
useReducer: re,
|
||
createElement: ie,
|
||
cloneElement: le,
|
||
createContext: oe,
|
||
forwardRef: ce,
|
||
memo: de,
|
||
Fragment: me,
|
||
Children: pe,
|
||
isValidElement: ue,
|
||
StrictMode: he,
|
||
Suspense: ge,
|
||
lazy: fe
|
||
} = U, E = window.__rg.router, {
|
||
Link: z,
|
||
NavLink: ye,
|
||
Navigate: xe,
|
||
Outlet: we,
|
||
Route: be,
|
||
Routes: ve,
|
||
useParams: M,
|
||
useNavigate: Se,
|
||
useLocation: Ne,
|
||
useSearchParams: $e,
|
||
createBrowserRouter: Ce,
|
||
RouterProvider: ke
|
||
} = E, { PublicLayout: F, PageHeader: D, Loading: C, ErrorState: v, EmptyState: S, useAsync: k, useAuth: Re, useSite: ze } = window.__rg.ui, { request: f } = window.__rg.api, w = (e) => e ? `?${e}` : "", O = {
|
||
creatures: (e = {}) => {
|
||
const a = new URLSearchParams();
|
||
return e.q && a.set("q", e.q), e.facet && a.set("facet", e.facet), e.limit && a.set("limit", e.limit), e.offset && a.set("offset", e.offset), f(`/public/atlas/creatures${w(a.toString())}`);
|
||
},
|
||
creature: (e, a = {}) => {
|
||
const s = new URLSearchParams();
|
||
return a.facet && s.set("facet", a.facet), a.points && s.set("points", a.points), f(`/public/atlas/creatures/${encodeURIComponent(e)}${w(s.toString())}`);
|
||
},
|
||
regions: (e = {}) => {
|
||
const a = new URLSearchParams();
|
||
return e.facet && a.set("facet", e.facet), e.q && a.set("q", e.q), f(`/public/atlas/regions${w(a.toString())}`);
|
||
},
|
||
landmarks: (e = {}) => {
|
||
const a = new URLSearchParams();
|
||
return e.facet && a.set("facet", e.facet), e.q && a.set("q", e.q), f(`/public/atlas/landmarks${w(a.toString())}`);
|
||
},
|
||
champions: (e = {}) => {
|
||
const a = new URLSearchParams();
|
||
return e.facet && a.set("facet", e.facet), f(`/public/atlas/champions${w(a.toString())}`);
|
||
},
|
||
meta: () => f("/public/atlas/meta")
|
||
}, y = { atlas: O }, H = 50, x = (e) => Number.isFinite(e) ? e.toLocaleString() : "—", Q = [
|
||
{ key: "creatures", label: "Creatures" },
|
||
{ key: "champions", label: "Champion altars" },
|
||
{ key: "places", label: "Places" }
|
||
];
|
||
function R({ active: e, onClick: a, children: s }) {
|
||
return /* @__PURE__ */ t(
|
||
"button",
|
||
{
|
||
type: "button",
|
||
onClick: a,
|
||
className: "sans",
|
||
style: {
|
||
fontSize: "0.78rem",
|
||
padding: "5px 12px",
|
||
borderRadius: 999,
|
||
cursor: "pointer",
|
||
color: e ? "var(--bg-deep)" : "var(--muted)",
|
||
background: e ? "var(--accent)" : "transparent",
|
||
border: `1px solid ${e ? "var(--accent)" : "var(--line)"}`
|
||
},
|
||
children: s
|
||
}
|
||
);
|
||
}
|
||
function G({ creature: e }) {
|
||
const a = Object.entries(e.facets || {}).sort((s, r) => r[1] - s[1]);
|
||
return /* @__PURE__ */ l(
|
||
z,
|
||
{
|
||
to: `/uo/atlas/${encodeURIComponent(e.slug)}`,
|
||
className: "panel",
|
||
style: {
|
||
padding: "13px 15px",
|
||
display: "flex",
|
||
alignItems: "center",
|
||
gap: 14,
|
||
textDecoration: "none",
|
||
color: "inherit"
|
||
},
|
||
children: [
|
||
/* @__PURE__ */ l("div", { style: { minWidth: 0, flex: 1 }, children: [
|
||
/* @__PURE__ */ t(
|
||
"div",
|
||
{
|
||
className: "display",
|
||
style: {
|
||
fontSize: "0.98rem",
|
||
color: "var(--head)",
|
||
overflow: "hidden",
|
||
textOverflow: "ellipsis",
|
||
whiteSpace: "nowrap"
|
||
},
|
||
children: e.name
|
||
}
|
||
),
|
||
/* @__PURE__ */ t("div", { className: "sans dim", style: { fontSize: "0.74rem", marginTop: 3 }, children: a.length === 0 ? "—" : a.map(([s, r]) => `${s} (${r})`).join(" · ") })
|
||
] }),
|
||
/* @__PURE__ */ l("div", { className: "sans", style: { flex: "none", textAlign: "right" }, children: [
|
||
/* @__PURE__ */ t("div", { style: { color: "var(--head)", fontSize: "0.92rem" }, children: x(e.total) }),
|
||
/* @__PURE__ */ l("div", { className: "dim", style: { fontSize: "0.68rem", letterSpacing: "0.05em" }, children: [
|
||
x(e.points),
|
||
" spawners"
|
||
] })
|
||
] })
|
||
]
|
||
}
|
||
);
|
||
}
|
||
function V({ q: e, facet: a }) {
|
||
const [s, r] = h({ loading: !0, error: null, items: [], total: 0 }), [i, p] = h(!1), o = W(
|
||
async (n) => await y.atlas.creatures({ q: e, facet: a, limit: H, offset: n }),
|
||
[e, a]
|
||
);
|
||
I(() => {
|
||
let n = !0;
|
||
return r({ loading: !0, error: null, items: [], total: 0 }), o(0).then((d) => {
|
||
n && r({ loading: !1, error: null, items: d.creatures || [], total: d.total || 0 });
|
||
}).catch((d) => n && r({ loading: !1, error: d, items: [], total: 0 })), () => {
|
||
n = !1;
|
||
};
|
||
}, [o]);
|
||
const c = async () => {
|
||
p(!0);
|
||
try {
|
||
const n = await o(s.items.length);
|
||
r((d) => ({ ...d, items: [...d.items, ...n.creatures || []], total: n.total ?? d.total }));
|
||
} catch {
|
||
} finally {
|
||
p(!1);
|
||
}
|
||
};
|
||
return s.loading ? /* @__PURE__ */ t(C, {}) : s.error ? /* @__PURE__ */ t(v, { message: "Could not load the bestiary right now." }) : s.items.length === 0 ? /* @__PURE__ */ t(S, { children: "Nothing in the atlas matches that." }) : /* @__PURE__ */ l(A, { children: [
|
||
/* @__PURE__ */ l("p", { className: "sans dim", style: { fontSize: "0.78rem", margin: "0 0 12px" }, children: [
|
||
"Showing ",
|
||
x(s.items.length),
|
||
" of ",
|
||
x(s.total)
|
||
] }),
|
||
/* @__PURE__ */ t("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: s.items.map((n) => /* @__PURE__ */ t(G, { creature: n }, n.slug)) }),
|
||
s.items.length < s.total && /* @__PURE__ */ t("div", { style: { textAlign: "center", marginTop: 16 }, children: /* @__PURE__ */ t("button", { type: "button", className: "btn", onClick: c, disabled: i, children: i ? "Loading…" : "Load more" }) })
|
||
] });
|
||
}
|
||
function X({ facet: e }) {
|
||
const { loading: a, error: s, data: r } = k(() => y.atlas.champions(e), [e]);
|
||
return a ? /* @__PURE__ */ t(C, {}) : s ? /* @__PURE__ */ t(v, { message: "Could not load the champion altars right now." }) : !r || r.length === 0 ? /* @__PURE__ */ t(S, { children: "No champion altars are configured." }) : /* @__PURE__ */ t("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: r.map((i) => /* @__PURE__ */ l("div", { className: "panel", style: { padding: "13px 15px", display: "flex", gap: 14, alignItems: "center" }, children: [
|
||
/* @__PURE__ */ l("div", { style: { minWidth: 0, flex: 1 }, children: [
|
||
/* @__PURE__ */ t("div", { className: "display", style: { fontSize: "0.98rem", color: "var(--head)" }, children: i.label || i.name }),
|
||
/* @__PURE__ */ l("div", { className: "sans dim", style: { fontSize: "0.74rem", marginTop: 3 }, children: [
|
||
i.facet,
|
||
i.group ? ` · ${i.group}` : "",
|
||
" · ",
|
||
i.x,
|
||
", ",
|
||
i.y
|
||
] })
|
||
] }),
|
||
/* @__PURE__ */ t("span", { className: "sans", style: { flex: "none", fontSize: "0.76rem", color: "var(--muted)" }, children: i.randomType ? "Random champion" : i.type || "—" })
|
||
] }, i.slug)) });
|
||
}
|
||
function J({ q: e, facet: a }) {
|
||
const { loading: s, error: r, data: i } = k(
|
||
() => Promise.all([y.atlas.regions({ q: e, facet: a }), y.atlas.landmarks({ q: e, facet: a })]),
|
||
[e, a]
|
||
), p = j(() => {
|
||
if (!i) return [];
|
||
const [o, c] = i;
|
||
return [
|
||
...o.map((n) => ({ key: `r:${n.facet}:${n.name}`, name: n.name, facet: n.facet, detail: n.parent || n.type || "Region", kind: "Region" })),
|
||
...c.map((n) => ({ key: `l:${n.facet}:${n.group || ""}:${n.name}:${n.x}:${n.y}`, name: n.group ? `${n.group} — ${n.name}` : n.name, facet: n.facet, detail: `${n.x}, ${n.y}`, kind: "Landmark" }))
|
||
].sort((n, d) => n.name.localeCompare(d.name));
|
||
}, [i]);
|
||
return s ? /* @__PURE__ */ t(C, {}) : r ? /* @__PURE__ */ t(v, { message: "Could not load places right now." }) : p.length === 0 ? /* @__PURE__ */ t(S, { children: "No regions or landmarks match that." }) : /* @__PURE__ */ t("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: p.map((o) => /* @__PURE__ */ l("div", { className: "panel", style: { padding: "10px 14px", display: "flex", gap: 12, alignItems: "baseline" }, children: [
|
||
/* @__PURE__ */ t("span", { className: "sans", style: { flex: 1, minWidth: 0, color: "var(--head)", fontSize: "0.88rem" }, children: o.name }),
|
||
/* @__PURE__ */ l("span", { className: "sans dim", style: { fontSize: "0.72rem" }, children: [
|
||
o.facet,
|
||
" · ",
|
||
o.detail
|
||
] }),
|
||
/* @__PURE__ */ t("span", { className: "sans dim", style: { fontSize: "0.66rem", letterSpacing: "0.06em", flex: "none" }, children: o.kind })
|
||
] }, o.key)) });
|
||
}
|
||
function K() {
|
||
var L, _, q;
|
||
const [e, a] = h("creatures"), [s, r] = h(""), [i, p] = h(""), [o, c] = h(""), n = k(() => y.atlas.meta());
|
||
I(() => {
|
||
const m = setTimeout(() => p(s.trim()), 250);
|
||
return () => clearTimeout(m);
|
||
}, [s]);
|
||
const d = ((L = n.data) == null ? void 0 : L.facets) || [], u = ((_ = n.data) == null ? void 0 : _.counts) || null, N = (q = n.data) != null && q.importedAt ? new Date(n.data.importedAt) : null;
|
||
return /* @__PURE__ */ t(F, { section: "website", children: /* @__PURE__ */ l("div", { className: "shell-narrow page-body", children: [
|
||
/* @__PURE__ */ t(
|
||
D,
|
||
{
|
||
eyebrow: "Bestiary",
|
||
title: "Spawn atlas",
|
||
lead: "Where everything lives, read straight out of the shard's own spawn files — so it stays accurate whether or not the server is up."
|
||
}
|
||
),
|
||
u && /* @__PURE__ */ l("p", { className: "sans dim", style: { fontSize: "0.76rem", margin: "-12px 0 18px" }, children: [
|
||
x(u.creatures),
|
||
" creatures across ",
|
||
x(u.points),
|
||
" spawners",
|
||
Number.isFinite(u.unresolvedPoints) && u.points ? ` · ${Math.round((u.points - u.unresolvedPoints) / u.points * 100)}% placed to a named region or landmark` : "",
|
||
N ? ` · parsed ${N.toLocaleDateString()}` : ""
|
||
] }),
|
||
/* @__PURE__ */ t("div", { style: { display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 12 }, children: Q.map((m) => /* @__PURE__ */ t(R, { active: e === m.key, onClick: () => a(m.key), children: m.label }, m.key)) }),
|
||
e !== "champions" && /* @__PURE__ */ t(
|
||
"input",
|
||
{
|
||
className: "input",
|
||
type: "search",
|
||
value: s,
|
||
onChange: (m) => r(m.target.value),
|
||
placeholder: e === "creatures" ? "Search creatures…" : "Search regions and landmarks…",
|
||
style: { width: "100%", marginBottom: 12 }
|
||
}
|
||
),
|
||
d.length > 0 && /* @__PURE__ */ l("div", { style: { display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 18 }, children: [
|
||
/* @__PURE__ */ t(R, { active: o === "", onClick: () => c(""), children: "All facets" }),
|
||
d.map((m) => /* @__PURE__ */ t(R, { active: o === m, onClick: () => c(m), children: m }, m))
|
||
] }),
|
||
n.error && /* @__PURE__ */ t(v, { message: "Could not load the atlas right now." }),
|
||
!n.error && !n.loading && !N && /* @__PURE__ */ t(S, { children: "The spawn atlas has not been imported yet." }),
|
||
!n.error && N && /* @__PURE__ */ l(A, { children: [
|
||
e === "creatures" && /* @__PURE__ */ t(V, { q: i, facet: o }),
|
||
e === "champions" && /* @__PURE__ */ t(X, { facet: o }),
|
||
e === "places" && /* @__PURE__ */ t(J, { q: i, facet: o })
|
||
] })
|
||
] }) });
|
||
}
|
||
const g = (e) => Number.isFinite(e) ? e.toLocaleString() : "—";
|
||
function Y(e, a) {
|
||
const s = (r) => r >= 60 ? `${Math.round(r / 60)}m` : `${r}s`;
|
||
return !Number.isFinite(e) || !Number.isFinite(a) ? null : e === a ? s(e) : `${s(e)}–${s(a)}`;
|
||
}
|
||
function P({ title: e, right: a, children: s }) {
|
||
return /* @__PURE__ */ l("section", { className: "panel", style: { padding: 18 }, children: [
|
||
/* @__PURE__ */ l("div", { style: { display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 12 }, children: [
|
||
/* @__PURE__ */ t("h2", { className: "display", style: { margin: "0 0 12px", fontSize: "1.02rem", color: "var(--head)" }, children: e }),
|
||
a
|
||
] }),
|
||
s
|
||
] });
|
||
}
|
||
function Z({ places: e }) {
|
||
return e.length === 0 ? /* @__PURE__ */ t("p", { className: "sans dim", style: { margin: 0 }, children: "No placed spawners." }) : /* @__PURE__ */ t("div", { children: e.map((a) => /* @__PURE__ */ l(
|
||
"div",
|
||
{
|
||
className: "sans",
|
||
style: {
|
||
display: "flex",
|
||
alignItems: "baseline",
|
||
justifyContent: "space-between",
|
||
gap: 12,
|
||
padding: "6px 0",
|
||
borderBottom: "1px solid var(--line)",
|
||
fontSize: "0.86rem"
|
||
},
|
||
children: [
|
||
/* @__PURE__ */ t("span", { style: { minWidth: 0, color: "var(--head)" }, children: a.label }),
|
||
/* @__PURE__ */ l("span", { className: "dim", style: { flex: "none" }, children: [
|
||
a.facet,
|
||
" · ",
|
||
g(a.spawners),
|
||
" spawner",
|
||
a.spawners === 1 ? "" : "s",
|
||
" · up to",
|
||
" ",
|
||
g(a.maxAlive),
|
||
" at once"
|
||
] })
|
||
]
|
||
},
|
||
`${a.facet}:${a.label}`
|
||
)) });
|
||
}
|
||
function ee({ spawners: e, truncated: a }) {
|
||
const [s, r] = h(!1);
|
||
return e.length === 0 ? null : /* @__PURE__ */ t(
|
||
P,
|
||
{
|
||
title: "Individual spawners",
|
||
right: /* @__PURE__ */ t(
|
||
"button",
|
||
{
|
||
type: "button",
|
||
className: "sans",
|
||
onClick: () => r((i) => !i),
|
||
style: { background: "none", border: "none", color: "var(--accent)", cursor: "pointer", fontSize: "0.78rem" },
|
||
children: s ? "Hide" : `Show ${g(e.length)}`
|
||
}
|
||
),
|
||
children: s && /* @__PURE__ */ l("div", { style: { overflowX: "auto" }, children: [
|
||
/* @__PURE__ */ l("table", { className: "sans", style: { width: "100%", borderCollapse: "collapse", fontSize: "0.8rem" }, children: [
|
||
/* @__PURE__ */ t("thead", { children: /* @__PURE__ */ l("tr", { style: { textAlign: "left", color: "var(--muted)" }, children: [
|
||
/* @__PURE__ */ t("th", { style: { padding: "4px 8px 8px 0" }, children: "Place" }),
|
||
/* @__PURE__ */ t("th", { style: { padding: "4px 8px 8px 0" }, children: "Facet" }),
|
||
/* @__PURE__ */ t("th", { style: { padding: "4px 8px 8px 0" }, children: "Coords" }),
|
||
/* @__PURE__ */ t("th", { style: { padding: "4px 8px 8px 0" }, children: "Max" }),
|
||
/* @__PURE__ */ t("th", { style: { padding: "4px 0 8px 0" }, children: "Respawn" })
|
||
] }) }),
|
||
/* @__PURE__ */ t("tbody", { children: e.map((i) => /* @__PURE__ */ l("tr", { style: { borderTop: "1px solid var(--line)" }, children: [
|
||
/* @__PURE__ */ t("td", { style: { padding: "6px 8px 6px 0", color: "var(--head)" }, children: i.label }),
|
||
/* @__PURE__ */ t("td", { style: { padding: "6px 8px 6px 0" }, className: "dim", children: i.facet }),
|
||
/* @__PURE__ */ l("td", { style: { padding: "6px 8px 6px 0" }, className: "dim", children: [
|
||
i.x,
|
||
", ",
|
||
i.y
|
||
] }),
|
||
/* @__PURE__ */ t("td", { style: { padding: "6px 8px 6px 0" }, className: "dim", children: g(i.maxCount) }),
|
||
/* @__PURE__ */ t("td", { style: { padding: "6px 0" }, className: "dim", children: Y(i.minDelay, i.maxDelay) || "—" })
|
||
] }, i.id)) })
|
||
] }),
|
||
a && /* @__PURE__ */ t("p", { className: "sans dim", style: { fontSize: "0.74rem", margin: "10px 0 0" }, children: "Only the largest spawners are listed." })
|
||
] })
|
||
}
|
||
);
|
||
}
|
||
function te() {
|
||
var o;
|
||
const { slug: e } = M(), { loading: a, error: s, data: r } = k(() => y.atlas.creature(e), [e]), i = (s == null ? void 0 : s.status) === 404 || (s == null ? void 0 : s.message) === "Not Found", p = j(
|
||
() => Object.entries((r == null ? void 0 : r.facets) || {}).sort((c, n) => n[1] - c[1]),
|
||
[r]
|
||
);
|
||
return /* @__PURE__ */ t(F, { section: "website", children: /* @__PURE__ */ l("div", { className: "shell-narrow page-body", children: [
|
||
/* @__PURE__ */ t("p", { className: "sans", style: { marginBottom: 8 }, children: /* @__PURE__ */ t(z, { to: "/uo/atlas", style: { color: "var(--accent)", fontSize: "0.78rem" }, children: "← Spawn atlas" }) }),
|
||
a && /* @__PURE__ */ t(C, {}),
|
||
s && !i && /* @__PURE__ */ t(v, { message: "Could not load that creature right now." }),
|
||
i && /* @__PURE__ */ t(S, { children: "Nothing by that name spawns on this shard." }),
|
||
!a && !s && r && /* @__PURE__ */ l(A, { children: [
|
||
/* @__PURE__ */ t(
|
||
D,
|
||
{
|
||
eyebrow: "Bestiary",
|
||
title: r.name,
|
||
lead: `Up to ${g(r.total)} alive at once across ${g(r.points)} spawner${r.points === 1 ? "" : "s"}.`
|
||
}
|
||
),
|
||
/* @__PURE__ */ l("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: [
|
||
/* @__PURE__ */ t(
|
||
P,
|
||
{
|
||
title: "Where it spawns",
|
||
right: /* @__PURE__ */ t("span", { className: "sans dim", style: { fontSize: "0.74rem" }, children: p.map(([c, n]) => `${c} (${n})`).join(" · ") }),
|
||
children: /* @__PURE__ */ t(Z, { places: r.places || [] })
|
||
}
|
||
),
|
||
/* @__PURE__ */ t(ee, { spawners: r.spawners || [], truncated: !!r.spawnersTruncated }),
|
||
((o = r.alsoHere) == null ? void 0 : o.length) > 0 && /* @__PURE__ */ t(P, { title: "Shares a spawner with", children: /* @__PURE__ */ t("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: r.alsoHere.map((c) => /* @__PURE__ */ l(
|
||
z,
|
||
{
|
||
to: `/uo/atlas/${encodeURIComponent(c.slug)}`,
|
||
className: "sans",
|
||
style: {
|
||
fontSize: "0.78rem",
|
||
padding: "4px 11px",
|
||
borderRadius: 999,
|
||
border: "1px solid var(--line)",
|
||
color: "var(--muted)",
|
||
textDecoration: "none"
|
||
},
|
||
children: [
|
||
c.name,
|
||
" ",
|
||
/* @__PURE__ */ l("span", { className: "dim", children: [
|
||
"×",
|
||
g(c.shared)
|
||
] })
|
||
]
|
||
},
|
||
c.slug
|
||
)) }) })
|
||
] })
|
||
] })
|
||
] }) });
|
||
}
|
||
const $ = "uo", T = "^1.0.0";
|
||
function ae(e) {
|
||
const [a] = String(e || "").split(".");
|
||
return a === T.replace(/^\^/, "").split(".")[0];
|
||
}
|
||
const b = window.__rg;
|
||
b ? ae(b.version) ? (b.registry.registerRoutes($, {
|
||
// Paths are relative to the module's namespace; core prefixes them, so these
|
||
// render at /uo/atlas and /uo/atlas/:slug (MODULE_SYSTEM.md §2.8).
|
||
public: [
|
||
{ path: "atlas", element: /* @__PURE__ */ t(K, {}) },
|
||
{ path: "atlas/:slug", element: /* @__PURE__ */ t(te, {}) }
|
||
]
|
||
}), b.registry.registerNav($, {
|
||
area: "public",
|
||
items: [{ label: "Atlas", to: "/uo/atlas", feature: "atlas", order: 12 }]
|
||
})) : console.error(`[module-${$}] needs core API ${T}, this core is ${b.version} — not registering`) : console.error(`[module-${$}] window.__rg is missing — core did not publish its shared dependencies`);
|