docs(reference): import Dune: Awakening server-manager references
All checks were successful
CI / backend-types (push) Successful in 10s
CI / frontend-build (push) Successful in 15s
CI / agent-tests (push) Successful in 39s
CI / integration (push) Successful in 22s

Phase 2 references for the host-agent Dune adapter, moved out of volatile /tmp
into docs/reference-repos/ (per Commander). Three upstream projects, .git +
node_modules + compiled binaries stripped (16MB source). Nested AI-instruction
files (.claude/, CLAUDE.md) removed so they don't pollute Corrosion sessions.

- icehunter/    dune-admin (Go+React) — 4 control planes; SETUP_DOCKER.md is the
                closest analog to our agent's Dune docker control plane (compose
                lifecycle, docker logs, RabbitMQ-via-exec, dune Postgres schema)
- adainrivers/  Rust/Tauri desktop — SSH+k8s BattleGroup control, maintenance
                daemon, in-game admin console (Rust idiom reference)
- the4rchangel/ Node web UI replacing battlegroup.bat — matches the Commander's
                Hyper-V self-host path + game-config schema

See docs/reference-repos/README.md for the full index + how we use each.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Vantz Stockwell
2026-06-11 21:08:05 -04:00
parent 0715492ddf
commit 651a35d4be
1334 changed files with 238971 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
/**
* Compatibility shim — re-exports the item-data API from store.ts so existing
* import sites (MarketTab/ItemDetail, GiveItemsModal) continue to work without
* modification.
*/
export type { ItemEntry, ItemDataFile } from './store'
export { cdnBase, getItemData, getItemEntry } from './store'

View File

@@ -0,0 +1,200 @@
/**
* Unified data store — fetches static JSON files from the Go backend first
* (enabling local overrides), falls back to the CDN when Go returns 404 or
* when running on a pure CDN deploy with no backend reachable.
*
* All atoms use jotai's implicit default store so cache persists until a hard
* refresh. Components use useAtom(loadable(atomRef)); imperative callers use
* getDefaultStore().get(atomRef) via the helper functions below.
*/
import { atom, getDefaultStore } from 'jotai'
import { loadable } from 'jotai/utils'
import { useAtom } from 'jotai'
import type { Atom } from 'jotai'
import { apiBase, isCdnDeploy } from '../api/client'
// ── CDN base ──────────────────────────────────────────────────────────────────
/** Returns the CDN base URL, stripped of trailing slashes. */
export const cdnBase = (): string =>
((import.meta.env.VITE_CDN_BASE_URL as string) ?? 'https://assets.dune.layout.tools').replace(/\/$/, '')
// ── Fetch primitive ───────────────────────────────────────────────────────────
/**
* Fetches a named data file. On non-CDN deploys the Go backend is tried first
* (allows local overrides); a non-ok response or network error causes
* transparent fallback to the CDN. Throws only when both sources fail.
*/
async function fetchDataFile<T>(filename: string): Promise<T> {
if (!isCdnDeploy) {
try {
const res = await fetch(`${apiBase}/data/${filename}`)
if (res.ok) return res.json() as Promise<T>
}
catch {
// fall through to CDN
}
}
const res = await fetch(`${cdnBase()}/${filename}`)
if (!res.ok) throw new Error(`Failed to load ${filename}`)
return res.json() as Promise<T>
}
// ── Types ─────────────────────────────────────────────────────────────────────
export type ItemEntry = {
name?: string
category?: string
tier?: number
rarity?: string
is_gradeable?: boolean
armor_value?: number
mitigation?: Record<string, number>
}
export type ItemDataFile = {
default_stack_max?: number
default_volume?: number
names?: Record<string, string>
items: Record<string, ItemEntry>
}
export type QualityData = {
weapon_damage: number[]
armor: number[]
volume: number[]
}
export type SkillModule = {
id: string
label: string
}
export type Vehicle = {
id: string
label: string
actor_class: string
templates: string[]
}
export type CheatScript = {
name: string
danger: boolean
}
export type PacksData = {
packs: Record<string, {
name: string
category: string
tier: number
items: { template: string, qty: number, quality: number }[]
}>
}
// ── Atoms ─────────────────────────────────────────────────────────────────────
export const itemDataAtom = atom<Promise<ItemDataFile>>(async () => {
try {
return await fetchDataFile<ItemDataFile>('item-data.json')
}
catch {
return { items: {} }
}
})
export const tagsDataAtom = atom<Promise<unknown>>(async () => {
try {
return await fetchDataFile<unknown>('tags-data.json')
}
catch {
return {}
}
})
export const qualityDataAtom = atom<Promise<QualityData>>(async () => {
try {
return await fetchDataFile<QualityData>('quality-data.json')
}
catch {
return { weapon_damage: [], armor: [], volume: [] }
}
})
export const gameplayTagsAtom = atom<Promise<string[]>>(async () => {
try {
return await fetchDataFile<string[]>('gameplayTags.json')
}
catch {
return []
}
})
export const skillModulesAtom = atom<Promise<SkillModule[]>>(async () => {
try {
return await fetchDataFile<SkillModule[]>('skillModules.json')
}
catch {
return []
}
})
export const vehiclesAtom = atom<Promise<Vehicle[]>>(async () => {
try {
return await fetchDataFile<Vehicle[]>('vehicles.json')
}
catch {
return []
}
})
export const cheatScriptsAtom = atom<Promise<CheatScript[]>>(async () => {
try {
return await fetchDataFile<CheatScript[]>('cheatScripts.json')
}
catch {
return []
}
})
export const packsAtom = atom<Promise<PacksData>>(async () => {
try {
return await fetchDataFile<PacksData>('packs.json')
}
catch {
return { packs: {} }
}
})
// ── React hook ────────────────────────────────────────────────────────────────
/** Wraps a data atom with loadable so components can read it without Suspense. */
export function useDataFile<T>(fileAtom: Atom<Promise<T>>): {
data: T | null
loading: boolean
error: string | null
} {
const [state] = useAtom(loadable(fileAtom))
switch (state.state) {
case 'loading':
return { data: null, loading: true, error: null }
case 'hasError':
return { data: null, loading: false, error: String(state.error) }
default:
return { data: state.data, loading: false, error: null }
}
}
// ── Imperative accessors (non-React call sites) ───────────────────────────────
/** Returns a Promise resolving to the full item data. Shares the jotai cache. */
export function getItemData(): Promise<ItemDataFile> {
return getDefaultStore().get(itemDataAtom)
}
/** Returns the ItemEntry for the given template ID, or null if not found. */
export async function getItemEntry(templateId: string): Promise<ItemEntry | null> {
const data = await getItemData()
return data.items[templateId] ?? null
}