feat: libs 0009-B — footprint serve + read wiring (GPL backend + standalone): extForKind .kicad_mod read/write, kind-filtered listLibs, LibsSource.listLibs(kind) threaded + boot per-tool kind; footprint-browse-remote e2e green (opens real capped 10.0.3 fp); bump pcbjam-shared

This commit is contained in:
Gergő Törcsvári 2026-06-14 07:55:24 +02:00
commit 2c52637b1a
No known key found for this signature in database
GPG key ID: 8E75F2CDE64E5322
10 changed files with 163 additions and 26 deletions

View file

@ -121,7 +121,8 @@ async function doBoot(opts: BootOptions): Promise<void> {
installLibsProvider(libsSource, log);
try {
// Ensure the owner has at least one writable user lib to save items into.
let libsList = await libsSource.listLibs();
// Pass the tool's kind so origins are filtered to the right domain.
let libsList = await libsSource.listLibs(libKind);
if (libsSource.createLib && !libsList.some((l) => l.type === "user")) {
const created = await libsSource.createLib(DEFAULT_USER_LIB_NAME);
if (created) {

View file

@ -30,8 +30,8 @@ export function remoteLibsSource(
`${encodeURIComponent(kind)}/${encodeURIComponent(name)}`;
return {
async listLibs(): Promise<LibInfo[]> {
const res = await client.listLibs();
async listLibs(kind?: string): Promise<LibInfo[]> {
const res = await client.listLibs({ query: { kind } });
if (res.status !== 200) return [];
return res.body.map((l) => ({
id: l.id,

View file

@ -21,8 +21,13 @@ export interface LibItemInfo {
}
export interface LibsSource {
/** Libraries to expose to the editor (one sym-lib-table row each). */
listLibs(): Promise<LibInfo[]>;
/**
* Libraries to expose to the editor (one lib-table row each). `kind` (the
* current tool's item kind, "symbol" | "footprint") filters origins to those
* holding that kind; user libs are kind-agnostic containers, always listed.
* Omitted all libs.
*/
listLibs(kind?: string): Promise<LibInfo[]>;
/** Items in a library (by lib id). */
listItems(libId: string): Promise<LibItemInfo[]>;
/**

View file

@ -36,16 +36,17 @@ function withSpikeKindLib(
const isSpike = (libId: string) => libId === spec.id;
return {
async listLibs(): Promise<LibInfo[]> {
async listLibs(kind?: string): Promise<LibInfo[]> {
// Resilient to a missing backend: the spike must boot standalone (the
// writable lib is in-memory), so an unreachable inner source just yields
// no origins rather than failing the whole table.
let base: LibInfo[] = [];
try {
base = inner ? await inner.listLibs() : [];
base = inner ? await inner.listLibs(kind) : [];
} catch (e) {
log(`[libs] spike: inner listLibs failed, origins omitted: ${String(e)}`);
}
// The spike lib is the writable target for its kind (mimics a user lib).
return [...base, { id: spec.id, name: spec.name, type: "user" }];
},

View file

@ -58,8 +58,9 @@ const SYMBOLS: Record<string, string> = {
export function staticLibsSource(): LibsSource {
return {
async listLibs(): Promise<LibInfo[]> {
return [STATIC_LIB];
async listLibs(kind?: string): Promise<LibInfo[]> {
// The built-in example lib is symbols-only.
return !kind || kind === "symbol" ? [STATIC_LIB] : [];
},
async listItems(libId: string): Promise<LibItemInfo[]> {
if (libId !== STATIC_LIB.id) return [];