feat(server): port the UO models, utils and schema fragment

The data half of the extraction: 8 model directories, 13 utils, the shard
stream catalog and the 27-table schema fragment with its purge.

server/core.js is what makes the port a one-line import change per file rather
than a signature change per function. Ported code requires its dependencies at
file scope -- `const { query } = require('../../core')` -- which runs before
register() has been called and before any ctx exists. So every member is a
stable function that resolves ctx when CALLED, and nothing may be destructured
off ctx at init either, because core is free to hand over a getter.

Two helpers are vendored rather than taken from ctx, and the line between them
is the point. utils/excerpt.js is core's deriveExcerpt -- nine lines of pure
text handling. Core's sanitiser next to it was NOT copied: a second copy of a
security control diverges silently the moment either is fixed. announceLinks.js
vendors legError and articleUrl the same way, but baseUrl could not be: core's
reads APP_BASE_URL, and §2.7 forbids a module reading core's environment, so it
comes off ctx.site.baseUrl.

The schema fragment is core's 27 shard_*/uo_link_* statements, verbs CREATE,
ALTER and UPDATE only, every CREATE TABLE guarded. Two of its tables carry a
foreign key INTO users, which is allowed and is why the replay order matters --
core's schema is in place before this runs. The reverse never occurs and must
not: it would make core unable to boot without a module installed.

One real port bug caught by the integration run, not by tests: the atlas art
map resolved `../../../db/data`, which pointed at core's tree when this file
lived there and points outside server/ now. A path that happens to resolve is
exactly what survives a green suite, because the absent-file branch returns {}
and looks like the normal case.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-11 12:06:26 -05:00
committed by Claude
parent 47809854ef
commit fe3251a543
40 changed files with 7967 additions and 3 deletions

52
server/db/purge.sql Normal file
View File

@@ -0,0 +1,52 @@
-- ── module-uo's teardown ──────────────────────────────────────────────────
--
-- Destructive, and run ONLY by an explicit admin purge (MODULE_API.md §2.6).
-- Nothing on the boot path ever executes this file — uninstalling a module
-- leaves its data alone, and removing the data is a separate decision an
-- operator has to make on purpose.
--
-- It exists because `schema.sql` does. A module that can create tables and
-- cannot drop them leaves an operator with orphaned data and no supported way
-- to remove it, which is why core refuses to load a module that declares one
-- without the other.
--
-- **The order is the reverse of creation, and that is load-bearing**: two of
-- these tables carry a foreign key into core's `users`, and several reference
-- each other. Dropping a parent before its children fails on the constraint,
-- and a purge that fails halfway is worse than one that does not run — it
-- leaves exactly the orphaned data this file exists to remove. `IF EXISTS` on
-- every line so a partially-installed module still tears down cleanly.
--
-- What is NOT here, deliberately: rows this module wrote into core's tables.
-- `notification_subs` rows for `shard.*` streams and `announce_job_legs` rows
-- with leg `towncrier` belong to core's tables, and a module does not delete
-- from those — core prunes them when it drops the registrations, which it can
-- do because it knows which registrant owned what.
DROP TABLE IF EXISTS `shard_atlas_pending`;
DROP TABLE IF EXISTS `shard_atlas_meta`;
DROP TABLE IF EXISTS `shard_cliloc_meta`;
DROP TABLE IF EXISTS `shard_clilocs`;
DROP TABLE IF EXISTS `shard_champion_spawns`;
DROP TABLE IF EXISTS `shard_landmarks`;
DROP TABLE IF EXISTS `shard_regions`;
DROP TABLE IF EXISTS `shard_spawn_point_types`;
DROP TABLE IF EXISTS `shard_spawn_points`;
DROP TABLE IF EXISTS `shard_spawn_creatures`;
DROP TABLE IF EXISTS `shard_feature_visibility`;
DROP TABLE IF EXISTS `shard_vendor_items`;
DROP TABLE IF EXISTS `shard_vendors`;
DROP TABLE IF EXISTS `shard_points_boards`;
DROP TABLE IF EXISTS `shard_ruleset`;
DROP TABLE IF EXISTS `shard_presence`;
DROP TABLE IF EXISTS `shard_governor_terms`;
DROP TABLE IF EXISTS `shard_governors`;
DROP TABLE IF EXISTS `shard_guilds`;
DROP TABLE IF EXISTS `shard_pages`;
DROP TABLE IF EXISTS `shard_champs`;
DROP TABLE IF EXISTS `shard_account_links`;
DROP TABLE IF EXISTS `shard_houses`;
DROP TABLE IF EXISTS `shard_economy`;
DROP TABLE IF EXISTS `shard_online`;
DROP TABLE IF EXISTS `shard_events`;
DROP TABLE IF EXISTS `uo_link_config`;