All checks were successful
Deploy / deploy (push) Successful in 3m58s
- Extract world-parse + packet capture into @albion/shared (reused by server and a new standalone agent workspace). - Migrate the data layer from SQLite/better-sqlite3 to shared Postgres (async pg with a ?->$n helper; economy engine preloads the item/recipe graph so its sync recursion still works). - API-key auth (ALBION_API_KEY) on all /api routes except health; web UI sends it via a fetch wrapper + key-entry gate; server serves the built UI with a path-traversal-safe static handler (drops @fastify/static). - Windows companion agent: pushes world map + captured market orders to /api/ingest/*; runs on the gaming PC where the game traffic lives. - Docker + docker-compose (external proxy + backend networks for Nginx Proxy Manager and shared Postgres) and a Forgejo deploy workflow. - Validated end-to-end against Postgres 16 and a full compose run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
47 lines
1.7 KiB
TypeScript
47 lines
1.7 KiB
TypeScript
import type { FastifyInstance } from 'fastify';
|
|
import { get, query } from '../db/index.js';
|
|
|
|
export async function itemRoutes(app: FastifyInstance): Promise<void> {
|
|
app.get('/api/items/search', async (req) => {
|
|
const { q = '' } = req.query as { q?: string };
|
|
const queryStr = q.trim();
|
|
if (!queryStr) return { results: [] };
|
|
const results = await query(
|
|
`SELECT unique_name, name_en, tier, enchantment, shop_category, shop_subcategory
|
|
FROM items
|
|
WHERE name_en ILIKE ? OR unique_name ILIKE ?
|
|
ORDER BY tier, enchantment, unique_name
|
|
LIMIT 50`,
|
|
[`%${queryStr}%`, `%${queryStr}%`],
|
|
);
|
|
return { results };
|
|
});
|
|
|
|
app.get('/api/items/:uniqueName', async (req, reply) => {
|
|
const { uniqueName } = req.params as { uniqueName: string };
|
|
const item = await get('SELECT * FROM items WHERE unique_name = ?', [uniqueName]);
|
|
if (!item) return reply.code(404).send({ error: 'item not found' });
|
|
|
|
const recipes = (await query('SELECT * FROM recipes WHERE output_item = ? ORDER BY source, variant', [uniqueName])) as any[];
|
|
for (const r of recipes) {
|
|
r.inputs = await query(
|
|
`SELECT ri.input_item, ri.count, ri.max_return_amount, i.name_en
|
|
FROM recipe_inputs ri LEFT JOIN items i ON i.unique_name = ri.input_item
|
|
WHERE ri.recipe_id = ?`,
|
|
[r.id],
|
|
);
|
|
}
|
|
|
|
const usedIn = await query(
|
|
`SELECT DISTINCT r.output_item, i.name_en
|
|
FROM recipe_inputs ri
|
|
JOIN recipes r ON r.id = ri.recipe_id
|
|
LEFT JOIN items i ON i.unique_name = r.output_item
|
|
WHERE ri.input_item = ?
|
|
LIMIT 100`,
|
|
[uniqueName],
|
|
);
|
|
|
|
return { item, recipes, usedIn };
|
|
});
|
|
}
|