# SDK source API

A typed interface to the local Yapwing CLI. The CLI connects to the owning app
when a project is open, and takes the same owner lock when it is closed. The
SDK never evaluates a project file or rewrites JSON behind the app.

The SDK is private source and is not a public npm package. The build commands
below require an authorized checkout of this directory; use the [bundled CLI](/docs/cli)
when you do not have source access.

Build with the pinned dependencies:

~~~sh
npm ci
npm run build
npm test
~~~

Run these commands in this directory. Node.js 22 or newer is recommended.
The packaged CLI must be on PATH, or set YAPWING_CLI to its absolute path.
A CLI built from source also needs the core library and speech paths described
in `docs/development.md`.

~~~ts
import { ProjectClient } from "@yapwing/project";

const client = new ProjectClient("/absolute/my-video");
const { snapshot } = await client.inspect();
const first = snapshot.renderPlan.words.find(unit => unit.kind === "word");
if (!first) throw new Error("Wait for transcription, then inspect again.");

const request = client.request(snapshot, "edit-a-persisted-unique-id", [
  { type: "cut_units", unitIds: [first.id] },
]);
await client.check(request);
const { receipt } = await client.apply(request);
console.log(receipt.committedRevision);
~~~

Keep the complete request and its operation ID until success is known. After a
transport interruption, retry exactly that request: the durable receipt prevents
a duplicate edit even if its expected revision is now old. Reusing an ID with a
different request fails. A new edit needs a new ID and a newly inspected revision.

A correction changes caption/transcript text while retaining its audio coverage:

~~~ts
const { snapshot } = await client.inspect();
const word = snapshot.renderPlan.words.find(unit => unit.kind === "word");
if (!word) throw new Error("No recognized speech.");
const correction = client.request(snapshot, "correct-persisted-id", [{
  type: "correct_words",
  occurrenceId: word.occurrenceId,
  atomIds: word.atomIds,
  text: "Corrected spelling",
}]);
await client.check(correction);
await client.apply(correction);
~~~

The core validates correction scope and length. Corrections cannot create
recorded speech or new timing. Some recognizer tokens share one observed timing
range; those tokens form one indivisible unit. Cutting a unit removes precisely
its represented coverage. Listen to real footage to judge the recognized text
and the sound of each cut; `native/speech/README.md` describes that check.

The project methods are init, import, collect, transcribe and export. The
library methods follow below. All mutations take an inspected projectId and expectedRevision; import/collect also require a
stable operationId. Import waits for transcription by default. Setting wait to
false requires an open app to own the background job. Transcribe always waits.
Export preserves existing output files; choose a new filename.
With a CLI from the current private development source, its receipt's
`loudness` reports the measured level and the one gain that brought the mix to
−14 LUFS.

`search` and `preview` need a CLI from the current private development source.
`search({query, limit?, shows?})` finds sentences said in library videos and
returns `{hits, revision}`; `shows: true` adds picture matches once the person
has downloaded the optional picture model, and `shows.state` says whether
pictures were searched. `preview({range?, frames?, audio?, projectId?,
expectedRevision?})` renders stills (and an optional AAC snippet) of the current
edit into a new temporary folder without changing the project. Both are
read-only; see [the agent guide](/docs/agent-requests).

Use `import(paths, {...mutation, library: true})` to register sources without
placing clips. `projection: "equirectangular"` explicitly marks a prepared 2:1
sphere. `library({query, offset, limit})` reads verified cached metadata
and corrected speech without starting analysis.
`analyze({...revision, assetId?, wait?})` retries derived analysis;
`linkPrepared(rawId, preparedId, revision)` associates an imported raw recording
with its prepared video. These methods return `{items, total, nextOffset,
revision}`; follow nextOffset until null. Linking and analysis have no authored
edit receipt. See [the library guide](/docs/library).

Import replies also include `importedAssetIDs` in accepted command order. Library
aliases coalesce; repeated timeline placements retain repeated IDs. The IDs stay
the same on replay even when the returned snapshot includes later edits. Use
these IDs to link a prepared video, since flat and spherical interpretations can
share a path. Older CLIs omit this field; treat exact selection identity as
unavailable instead of guessing it from paths or asset order.

Inspect returns { snapshot, statuses }. TranscriptionIncompleteError preserves
that inspection after a successful import with failed speech work; the media
remains in the project. YapwingError.code exposes structured validation errors.
UncertainOperationError means the transport cannot establish whether an operation
completed; it does not mean the operation was rolled back.

The executable cut example in `examples/cut-unit.ts` saves its request before
applying it and can resume after interruption. The generated types in
`src/generated.ts` mirror the
[project and command format](/docs/project-format); commands and render
plans are validated by the Rust core.
