Files
electronics-inventory/lib/storage.mjs
mikael-lovqvists-claude-agent f0bedc80a7 Add PDF file attachments to components
- Upload PDFs, rename them (conflict-checked), delete them
- Link/unlink files per component (many components can share a file)
- File picker dialog: browse existing files, rename inline, upload new
- Component detail shows linked files as clickable links
- Files stored in data/pdfs/, served at /pdf/:filename
- KV prefix: pdf:

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 00:19:30 +00:00

193 lines
4.1 KiB
JavaScript

import { mkdirSync } from 'node:fs';
import { Simple_KeyValue_Store } from './kv-store.mjs';
mkdirSync('./data', { recursive: true });
const store = new Simple_KeyValue_Store('./data/inventory.ndjson', {
auto_load: true,
auto_store: true,
debounce_flush_timeout: 5000,
});
// --- Field definitions ---
export function list_fields() {
const result = [];
for (const [key] of store.data.entries()) {
if (key.startsWith('f:')) {
result.push(store.get(key));
}
}
return result.sort((a, b) => a.name.localeCompare(b.name));
}
export function get_field(id) {
return store.get(`f:${id}`) ?? null;
}
export function set_field(field) {
store.set(`f:${field.id}`, field);
}
export function delete_field(id) {
return store.delete(`f:${id}`);
}
// --- Components ---
export function list_components() {
const result = [];
for (const [key] of store.data.entries()) {
if (key.startsWith('c:')) {
result.push(store.get(key));
}
}
return result.sort((a, b) => a.name.localeCompare(b.name));
}
export function get_component(id) {
return store.get(`c:${id}`) ?? null;
}
export function set_component(component) {
store.set(`c:${component.id}`, component);
}
export function delete_component(id) {
return store.delete(`c:${id}`);
}
// --- Inventory entries ---
export function list_inventory() {
const result = [];
for (const [key] of store.data.entries()) {
if (key.startsWith('i:')) {
result.push(store.get(key));
}
}
return result.sort((a, b) => a.created_at - b.created_at);
}
export function get_inventory_entry(id) {
return store.get(`i:${id}`) ?? null;
}
export function set_inventory_entry(entry) {
store.set(`i:${entry.id}`, entry);
}
export function delete_inventory_entry(id) {
return store.delete(`i:${id}`);
}
// --- Grid drafts ---
export function list_grid_drafts() {
const result = [];
for (const [key] of store.data.entries()) {
if (key.startsWith('d:')) result.push(store.get(key));
}
return result.sort((a, b) => b.updated_at - a.updated_at);
}
export function get_grid_draft(id) {
return store.get(`d:${id}`) ?? null;
}
export function set_grid_draft(draft) {
store.set(`d:${draft.id}`, draft);
}
export function delete_grid_draft(id) {
return store.delete(`d:${id}`);
}
// --- Source images ---
export function list_source_images() {
const result = [];
for (const [key] of store.data.entries()) {
if (key.startsWith('s:')) result.push(store.get(key));
}
return result.sort((a, b) => b.created_at - a.created_at);
}
export function get_source_image(id) {
return store.get(`s:${id}`) ?? null;
}
export function add_source_image(src) {
store.set(`s:${src.id}`, src);
}
export function delete_source_image(id) {
return store.delete(`s:${id}`);
}
// --- Component templates ---
export function list_component_templates() {
const result = [];
for (const [key] of store.data.entries()) {
if (key.startsWith('ct:')) result.push(store.get(key));
}
return result.sort((a, b) => a.name.localeCompare(b.name));
}
export function get_component_template(id) {
return store.get(`ct:${id}`) ?? null;
}
export function set_component_template(tmpl) {
store.set(`ct:${tmpl.id}`, tmpl);
}
export function delete_component_template(id) {
return store.delete(`ct:${id}`);
}
// --- PDF files ---
export function list_pdfs() {
const result = [];
for (const [key] of store.data.entries()) {
if (key.startsWith('pdf:')) result.push(store.get(key));
}
return result.sort((a, b) => a.display_name.localeCompare(b.display_name));
}
export function get_pdf(id) {
return store.get(`pdf:${id}`) ?? null;
}
export function set_pdf(pdf) {
store.set(`pdf:${pdf.id}`, pdf);
}
export function delete_pdf(id) {
return store.delete(`pdf:${id}`);
}
// --- Grid images ---
export function list_grid_images() {
const result = [];
for (const [key] of store.data.entries()) {
if (key.startsWith('g:')) result.push(store.get(key));
}
return result.sort((a, b) => b.created_at - a.created_at);
}
export function get_grid_image(id) {
return store.get(`g:${id}`) ?? null;
}
export function set_grid_image(grid) {
store.set(`g:${grid.id}`, grid);
}
export function delete_grid_image(id) {
return store.delete(`g:${id}`);
}