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:
52
server/utils/announceLinks.js
Normal file
52
server/utils/announceLinks.js
Normal file
@@ -0,0 +1,52 @@
|
||||
// The three helpers the town-crier leg needs from core's announce pipeline.
|
||||
//
|
||||
// Core owns `announce_jobs`, the worker that drains it and the retry policy;
|
||||
// this module owns one leg of it (MODULE_API.md §2.4). These three lived in
|
||||
// core's `announceJobs.logic` and are reproduced here rather than added to
|
||||
// `ctx`, because each is a few lines of pure string handling with no state and
|
||||
// no policy — the kind of thing a contract member would only make harder to
|
||||
// change on both sides.
|
||||
//
|
||||
// The one that could NOT be vendored is `baseUrl`. Core's version reads
|
||||
// `process.env.APP_BASE_URL`, and §2.7 forbids a module reading core's
|
||||
// environment — it is core's deployment fact, not the module's. So it comes off
|
||||
// `ctx.site.baseUrl` (API 1.1.0), read per call rather than captured, which also
|
||||
// means a module built before an env change keeps agreeing with core after it.
|
||||
|
||||
// NOT destructured. `core.baseUrl` is a getter that resolves `ctx`, so pulling
|
||||
// it out here would run at require time — before `register()` — and throw. Read
|
||||
// it inside the function, where `ctx` exists.
|
||||
const core = require('../core')
|
||||
|
||||
/** Where this deployment is reachable, without a trailing slash. */
|
||||
function baseUrl() {
|
||||
return core.baseUrl
|
||||
}
|
||||
|
||||
/**
|
||||
* The public link that goes in an announcement.
|
||||
*
|
||||
* News has no per-post route — core's SPA has only the list — so this links the
|
||||
* list, matching what the pre-pipeline Discord announce did. It names a CORE
|
||||
* route on purpose: the news list is core's page and stays core's through the
|
||||
* whole extraction, so this is a module linking to its host, not a leftover.
|
||||
*/
|
||||
function articleUrl(base) {
|
||||
return `${String(base || '').replace(/\/+$/, '')}/site/news`
|
||||
}
|
||||
|
||||
/**
|
||||
* Squeeze a leg client's `{ ok, status, data, error }` into the one line stored
|
||||
* in `announce_job_legs.last_error` and shown in the admin panel.
|
||||
*/
|
||||
function legError(result) {
|
||||
if (!result) return 'no response'
|
||||
if (result.status) {
|
||||
return result.data && result.data.message
|
||||
? `${result.status}: ${result.data.message}`
|
||||
: result.error || `status ${result.status}`
|
||||
}
|
||||
return result.error || 'request failed'
|
||||
}
|
||||
|
||||
module.exports = { baseUrl, articleUrl, legError }
|
||||
Reference in New Issue
Block a user