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>
38 lines
1.4 KiB
JavaScript
38 lines
1.4 KiB
JavaScript
const { query } = require('../../core')
|
|
|
|
// One row per shard feature. Absent rows are fine — utils/shardVisibility.js
|
|
// compiles a default for every known feature and merges stored rows over it, so
|
|
// a fresh install with an empty table behaves exactly as the site did pre-v3.
|
|
|
|
const COLS = 'feature, enabled, audience, stream, field_rules, updated_by, updated_at'
|
|
|
|
const listAll = () => query(`SELECT ${COLS} FROM shard_feature_visibility`)
|
|
|
|
const getOne = (feature) =>
|
|
query(`SELECT ${COLS} FROM shard_feature_visibility WHERE feature = ?`, [feature])
|
|
|
|
// Upsert one feature's settings. `fieldRules` is stored as a JSON object of
|
|
// {field: rung}; the caller has already stripped locked fields and validated
|
|
// every rung against the ladder.
|
|
const upsert = ({ feature, enabled, audience, stream, fieldRules, updatedBy }) =>
|
|
query(
|
|
`INSERT INTO shard_feature_visibility (feature, enabled, audience, stream, field_rules, updated_by)
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
ON DUPLICATE KEY UPDATE
|
|
enabled = VALUES(enabled),
|
|
audience = VALUES(audience),
|
|
stream = VALUES(stream),
|
|
field_rules = VALUES(field_rules),
|
|
updated_by = VALUES(updated_by)`,
|
|
[
|
|
feature,
|
|
enabled ? 1 : 0,
|
|
audience,
|
|
stream ? 1 : 0,
|
|
fieldRules == null ? null : JSON.stringify(fieldRules),
|
|
updatedBy ?? null,
|
|
],
|
|
)
|
|
|
|
module.exports = { listAll, getOne, upsert }
|