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>
47 lines
1.7 KiB
JavaScript
47 lines
1.7 KiB
JavaScript
const { query } = require('../../core')
|
|
|
|
// INSERT IGNORE on the UNIQUE dedupe_key — a re-ingested event (WS-reconnect
|
|
// backfill overlap) is silently skipped rather than duplicated. Returns true if
|
|
// a new row was actually inserted.
|
|
async function insertIgnore({ kind, t, bootId, payload, dedupeKey }) {
|
|
const res = await query(
|
|
`INSERT IGNORE INTO shard_events (kind, t, boot_id, payload, dedupe_key)
|
|
VALUES (?, ?, ?, ?, ?)`,
|
|
[kind, t, bootId || null, JSON.stringify(payload), dedupeKey],
|
|
)
|
|
return res.affectedRows > 0
|
|
}
|
|
|
|
// Recent events, newest first. Filter by a single `kind`, or an allowlist of
|
|
// `kinds` (IN clause) — the public feed uses the allowlist so it can never leak
|
|
// staff/sensitive kinds. limit is clamped by the model.
|
|
async function list({ kind, kinds, limit }) {
|
|
// An allowlist that resolved to NOTHING means "serve nothing" — never "serve
|
|
// everything". Falling through to the unfiltered query below would have turned
|
|
// a fully-gated visibility config into a full dump of the event log, staff
|
|
// audit and cheat detections included.
|
|
if (kinds && kinds.length === 0) return []
|
|
if (kinds && kinds.length) {
|
|
const placeholders = kinds.map(() => '?').join(', ')
|
|
return query(
|
|
`SELECT id, kind, t, boot_id, payload, created_at
|
|
FROM shard_events WHERE kind IN (${placeholders}) ORDER BY t DESC LIMIT ?`,
|
|
[...kinds, limit],
|
|
)
|
|
}
|
|
if (kind) {
|
|
return query(
|
|
`SELECT id, kind, t, boot_id, payload, created_at
|
|
FROM shard_events WHERE kind = ? ORDER BY t DESC LIMIT ?`,
|
|
[kind, limit],
|
|
)
|
|
}
|
|
return query(
|
|
`SELECT id, kind, t, boot_id, payload, created_at
|
|
FROM shard_events ORDER BY t DESC LIMIT ?`,
|
|
[limit],
|
|
)
|
|
}
|
|
|
|
module.exports = { insertIgnore, list }
|