feat(public): type the brand block so mobile clients get typed theming
Branding is already returned by GET /public/settings (the `brand` block: name/colors/logo/hero/favicon, per-shard from BRAND_*). §8.6 of the Android plan asks to confirm it — this makes it a first-class part of the contract so the app's OpenAPI codegen produces typed branding instead of an untyped map. - Swagger: add Brand + PublicSettings schemas; /public/settings now references PublicSettings (was additionalProperties:true). Brand documents that asset fields may be site-relative paths (resolve against the base URL). - test/publicBrand.test.js locks the brand theming contract the app depends on (all fields present; BRAND_* defaults; admin site_title/contact_email overrides; accentInt never leaked). No behavior change to the response — it already carried `brand`; this types and guards it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NgyHnrNa8WwG3doxvxjuCr
This commit is contained in:
@@ -587,6 +587,40 @@ const doc = {
|
||||
server: { type: 'string', example: '1.0.0', description: 'Server package version (informational).' },
|
||||
},
|
||||
},
|
||||
Brand: {
|
||||
type: 'object',
|
||||
description:
|
||||
'Per-shard branding (BRAND_* env, with admin overrides for name/contactEmail). A client themes itself from this — one instance runs as any shard. Asset fields (logo/hero/favicon) may be site-relative paths; resolve them against the site base URL.',
|
||||
properties: {
|
||||
name: { type: 'string', example: 'Runic Gateway' },
|
||||
shortName: { type: 'string', example: 'Runic Gateway' },
|
||||
tagline: { type: 'string', example: 'an independent private Ultima Online shard' },
|
||||
description: { type: 'string' },
|
||||
contactEmail: { type: 'string', example: '' },
|
||||
url: { type: 'string', example: '' },
|
||||
accent: { type: 'string', example: '#7f99bd', description: 'Seed/accent color (hex) for theming.' },
|
||||
logo: { type: 'string', example: '', description: 'Logo URL or site-relative path; empty = no logo.' },
|
||||
hero: { type: 'string', example: '/assets/img/runic-emblem.png', description: 'Hero image URL or site-relative path.' },
|
||||
favicon: { type: 'string', example: '/assets/img/favicon.ico', description: 'Favicon URL or site-relative path.' },
|
||||
},
|
||||
},
|
||||
PublicSettings: {
|
||||
type: 'object',
|
||||
description:
|
||||
'Public site settings + branding (GET /public/settings). Whitelisted string settings, plus derived availability flags and the brand block a client themes from. Additional whitelisted keys may appear.',
|
||||
properties: {
|
||||
site_title: { type: 'string', example: 'Runic Gateway' },
|
||||
status_message: { type: 'string', example: '' },
|
||||
maintenance_message: { type: 'string', example: '' },
|
||||
registration: {
|
||||
type: 'object',
|
||||
properties: { password: { type: 'boolean' }, sso: { type: 'boolean' } },
|
||||
},
|
||||
gameAccountSignup: { type: 'boolean', example: false },
|
||||
brand: { $ref: '#/components/schemas/Brand' },
|
||||
},
|
||||
additionalProperties: true,
|
||||
},
|
||||
// Delete/mutation acknowledgements — each echoes the affected resource key
|
||||
// or a boolean flag rather than a { message } string.
|
||||
DeletedId: {
|
||||
|
||||
Reference in New Issue
Block a user