test(server): port core's UO suite onto the ctx harness
22 test files moved from core, plus the two that were split out of files core keeps. 351 tests pass. One change runs through every moved test, and it is the boundary rather than a chore: core internals can no longer be stubbed by requiring them, because there are none to require. `../utils/db` and `../model/settings` do not exist here. What a test controls instead is the ctx core would have handed over, installed once by test/_setup.js -- which is a better seam anyway, since it is exactly the surface the contract promises and nothing wider. The ctx _setup installs is deliberately unfrozen. Core freezes what it hands a module and entry.test.js still asserts against a frozen one; but a test that needs settings.get to return a path has to be able to say so. Two tests changed SHAPE, and that is the boundary too. fromShardEvent used to assert through publish() into pushDevices and a captured fetch -- which endpoints were hit, how many requests went out. None of that is this module's any more: publish is ctx.push.publish, and the device registry and the relay are behind it. Reaching for them from here would be reaching past ctx. What remains is what the module owns and is the part worth guarding: a game account resolves to a website user, a personal target that resolves to nobody is dropped rather than published, and a sensitive kind never reaches publish at all. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -45,11 +45,18 @@ const { isBuiltin } = require('module')
|
||||
const MODULE_ROOT = path.resolve(__dirname, '..', '..')
|
||||
const SERVER_ROOT = path.join(MODULE_ROOT, 'server')
|
||||
|
||||
// Dependencies this half is allowed to resolve for itself. Empty, and that is
|
||||
// the design: everything the server half needs comes from `ctx` (§2.3). A new
|
||||
// entry here is a real decision — it becomes a package an operator's install
|
||||
// has to carry — so it should be argued for in a PR, not added in passing.
|
||||
const ALLOWED_PACKAGES = new Set([])
|
||||
// Packages the SHIPPED half may resolve for itself: this package's declared
|
||||
// `dependencies`, and nothing else. Read from package.json rather than listed
|
||||
// here, so adding one is a visible, reviewable edit to the manifest that also
|
||||
// changes what CI installs and what the release tarball carries.
|
||||
//
|
||||
// Adding a dependency is a real decision. §2.7 permits a module its own, and the
|
||||
// release tarball carries `server/node_modules` because an operator never builds
|
||||
// — so every entry is weight in the artifact and a package the operator's
|
||||
// deployment now runs. Anything core already owns must come from `ctx` instead:
|
||||
// a second express is a second Router prototype, a second express-rate-limit is
|
||||
// a second store, and a limit enforced by two independent counters is not the
|
||||
// limit either of them states.
|
||||
|
||||
const SKIP_DIRS = new Set(['node_modules', 'coverage', '.git'])
|
||||
|
||||
@@ -58,9 +65,9 @@ const SKIP_DIRS = new Set(['node_modules', 'coverage', '.git'])
|
||||
const NOT_SHIPPED = [path.join(SERVER_ROOT, 'test'), path.join(SERVER_ROOT, 'scripts')]
|
||||
const isShipped = (file) => !NOT_SHIPPED.some((d) => file.startsWith(d + path.sep))
|
||||
|
||||
const devDependencies = new Set(
|
||||
Object.keys(JSON.parse(fs.readFileSync(path.join(SERVER_ROOT, 'package.json'), 'utf8')).devDependencies || {}),
|
||||
)
|
||||
const manifest = JSON.parse(fs.readFileSync(path.join(SERVER_ROOT, 'package.json'), 'utf8'))
|
||||
const dependencies = new Set(Object.keys(manifest.dependencies || {}))
|
||||
const devDependencies = new Set(Object.keys(manifest.devDependencies || {}))
|
||||
|
||||
// `require('x')`, `from 'x'`, `import('x')`. Deliberately textual: parsing would
|
||||
// need a dependency, and a specifier this pattern misses is a specifier written
|
||||
@@ -135,7 +142,7 @@ function* walk(dir) {
|
||||
* has never been shown to fail is a check nobody knows the state of — and this
|
||||
* one guards the acceptance criterion for the whole contract.
|
||||
*/
|
||||
function scan(root, moduleRoot = MODULE_ROOT, { shipped = isShipped, dev = devDependencies } = {}) {
|
||||
function scan(root, moduleRoot = MODULE_ROOT, { shipped = isShipped, deps = dependencies, dev = devDependencies } = {}) {
|
||||
const violations = []
|
||||
for (const file of walk(root)) {
|
||||
const source = stripCommentsAndTemplates(fs.readFileSync(file, 'utf8'))
|
||||
@@ -151,7 +158,7 @@ function scan(root, moduleRoot = MODULE_ROOT, { shipped = isShipped, dev = devDe
|
||||
const pkg = specifier.startsWith('@')
|
||||
? specifier.split('/').slice(0, 2).join('/')
|
||||
: specifier.split('/')[0]
|
||||
const allowed = ALLOWED_PACKAGES.has(pkg) || (!shipped(file) && dev.has(pkg))
|
||||
const allowed = deps.has(pkg) || (!shipped(file) && dev.has(pkg))
|
||||
// The `node:` prefix can only ever name a builtin, so it never reaches
|
||||
// node_modules and is safe whatever this Node version enumerates.
|
||||
const builtin = isBuiltin(specifier) || specifier.startsWith('node:')
|
||||
|
||||
Reference in New Issue
Block a user