addLibrary

tcmts.cli.libraries.addLibrary · #mdglre5p · term · runs on the server

uses tcmts.cli.libraries.withRecord, which uses Buffer

Add a library: fetch the namespace what names on source (a release, or a namespace hash), or the release source names as announced (@alice.dev/geo@1.2.0), with everything it names, and mount it read-only at at (default defaultMount), recorded beside it. It's called name, else after its package (libraryName): a library by hash has no package to be called after.

import { attestationsFor, attesterNames, printAttestations } from "#codebase/tcmts/cli/attest";
import { IDENT_PATH } from "#codebase/tcmts/cli/codebase";
import type { Codebase } from "#codebase/tcmts/cli/codebase";
import {
  announcedSpec, announcer, defaultMount, fetchAnnounced, fetchFromSources, librariesIn, libraryEffects, libraryLabel,
  libraryName, namesNow, printEffects, recordAt, recordFor, within, withRecord,
} from "#codebase/tcmts/cli/libraries";
import type { Library, LibraryEntry } from "#codebase/tcmts/cli/libraries";
import { bold, dim } from "#codebase/tcmts/cli/style";
import { UsageError } from "#codebase/tcmts/cli/ui";

export async function addLibrary(
  cb: Codebase,
  o: {
    name?: string | undefined;
    source: string;
    what?: string | undefined;
    at?: string | undefined;
  },
): Promise<Library> {
  const announced = announcedSpec(o.source, o.what);
  const release = announced ? announced.what : o.what;
  const name = o.name ?? (release && !release.startsWith("#") ? libraryName(release) : undefined);
  if (name === undefined)
    throw new UsageError(
      release
        ? `a library by hash has no package to be called after: say what to call it (--as <name>)`
        : `which library? tcm lib add ${o.source} <package>[@<version>] (or #<namespace hash> --as <name>)`,
    );
  if (!/^[A-Za-z_$][\w$]*$/.test(name))
    throw new UsageError(`'${name}' is not a valid library name (--as <name> calls it another)`);
  const names = namesNow(cb.store);
  const path =
    o.at ??
    defaultMount(
      names.map((n) => n.path),
      name,
      librariesIn(cb.store).map((l) => l.path),
    );
  if (!IDENT_PATH.test(path)) throw new UsageError(`'${path}' is not a valid name`);
  const inside = librariesIn(cb.store).find((l) => within(path, l.path));
  if (inside) throw new UsageError(`${path} is in the library ${inside.path}`);
  if (names.some((n) => within(n.path, path)))
    throw new UsageError(`${path} already has names; mount the library elsewhere with --at`);
  const got = announced
    ? await fetchAnnounced(cb, announced.who, announced.what ?? name)
    : { ...(await fetchFromSources(cb, [o.source], o.what ?? name)), sources: [o.source] };
  const { found, received } = got;
  const rows = cb.store
    .namespaceRows(found.namespace)
    .map((r) => ({ ...r, path: `${path}.${r.path}` }));
  if (!rows.length) throw new UsageError(`${libraryLabel(found)} names nothing`);
  const record = recordFor(path);
  const entry: LibraryEntry = {
    namespace: found.namespace,
    ...(found.release ? { release: found.release } : {}),
    sources: got.sources,
    ...("did" in got ? { did: got.did, ...(got.handle ? { handle: got.handle } : {}) } : {}),
  };
  const entries = { ...recordAt(cb.store, record), [path.slice(path.lastIndexOf(".") + 1)]: entry };
  cb.store.setBranchNames(
    cb.store.branch().name,
    [...withRecord(cb, names, record, entries), ...rows],
    `lib add ${path}`,
  );
  cb.refreshShim();
  console.log(
    `added ${bold(path)}: ${libraryLabel(entry)}${entry.did ? ` by ${announcer(entry)}` : ""} from ${got.from} ${dim(`(${rows.length} names${received ? `; ${received} definitions received, verified by re-hashing` : ""})`)}`,
  );
  printEffects(libraryEffects(cb, cb.store.namespaceRows(found.namespace)));
  // (what its author, and the people this codebase trusts, say of it)
  printAttestations(
    await attestationsFor(cb, [found.namespace], entry.did),
    attesterNames(cb, entry),
  );
  return { ...entry, path, record };
}

uses

used by