Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/tasks/archives.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import TabItem from '@theme/TabItem';
import Rustarchives from './rust/_rust-archives.mdx';
import Cpparchives from './cpp/_cpp-archives.mdx';
import Pythonarchives from './python/_python-archives.mdx';
import Nodearchives from './node/_node-archives.mdx';

_Working stores_ and _archives_ provide a standard way to save and restore the state of a `Builder`:

Expand All @@ -35,5 +36,11 @@ _Working stores_ and _archives_ provide a standard way to save and restore the s
<Pythonarchives name="python-archives" />

</TabItem>

<TabItem value="node" label="Node.js">

<Nodearchives name="node-archives" />

</TabItem>

</Tabs>
7 changes: 7 additions & 0 deletions docs/tasks/build.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import TabItem from '@theme/TabItem';
import PythonBuild from './python/_python-build.md';
import CppBuild from './cpp/_cpp-build.md';
import RustBuild from './rust/_rust-build.md';
import NodeBuild from './node/_node-build.md';

<Tabs groupId="programming-lang" queryString="lang">

Expand All @@ -30,5 +31,11 @@ import RustBuild from './rust/_rust-build.md';
<PythonBuild name="python-build" />

</TabItem>

<TabItem value="node" label="Node.js">

<NodeBuild name="node-build" />

</TabItem>

</Tabs>
7 changes: 7 additions & 0 deletions docs/tasks/get-resources.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import TabItem from '@theme/TabItem';
import PythonGetResources from './python/_python-get-resources.md';
import CppGetResources from './cpp/_cpp-get-resources.md';
import RustGetResources from './rust/_rust-get-resources.md';
import NodeGetResources from './node/_node-get-resources.md';

Manifest data can include binary resources such as thumbnail and icon images which are referenced by JUMBF URIs in manifest data.

Expand All @@ -32,4 +33,10 @@ Manifest data can include binary resources such as thumbnail and icon images whi

</TabItem>

<TabItem value="node" label="Node.js">

<NodeGetResources name="node-get-resources" />

</TabItem>

</Tabs>
7 changes: 7 additions & 0 deletions docs/tasks/intents.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import TabItem from '@theme/TabItem';
import Rustintents from './rust/_rust-intents.md';
import Cppintents from './cpp/_cpp-intents.md';
import Pythonintents from './python/_python-intents.md';
import Nodeintents from './node/_node-intents.md';

_Intents_ tell the `Builder` what kind of manifest you are creating. They enable validation, add required default actions, and help prevent invalid operations.

Expand Down Expand Up @@ -41,5 +42,11 @@ There are three types of intents, shown here:
<Pythonintents name="python-intents" />

</TabItem>

<TabItem value="node" label="Node.js">

<Nodeintents name="node-intents" />

</TabItem>

</Tabs>
114 changes: 114 additions & 0 deletions docs/tasks/node/_node-archives.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import TOCInline from '@theme/TOCInline';

<TOCInline toc={toc} />

### Saving a working store to an archive

Use `toArchive` to serialize the current `Builder` state (working store) to a file or to an in-memory buffer. The binary uses the standard C2PA JUMBF `application/c2pa` archive format (often stored with a `.c2pa` extension).

```typescript
import { Builder } from '@contentauth/c2pa-node';
import { readFile } from 'node:fs/promises';

const builder = Builder.new();

await builder.addIngredient(
JSON.stringify({
title: 'source.jpg',
relationship: 'parentOf',
format: 'image/jpeg',
}),
{ buffer: await readFile('source.jpg'), mimeType: 'image/jpeg' },
);

await builder.toArchive({ path: 'manifest.c2pa' });
```

Write the archive to a buffer:

```typescript
const archive: { buffer: Buffer | null } = { buffer: null };
await builder.toArchive(archive);
// archive.buffer is populated with the archive bytes
```

### Restoring a working store from an archive

Use `Builder.fromArchive` to construct a new `Builder` from archive bytes or a file path. Pass optional [settings](../settings.mdx) as the second argument when you need custom verification or builder behavior.

```typescript
import { Builder, LocalSigner } from '@contentauth/c2pa-node';
import { readFile } from 'node:fs/promises';

const restored = await Builder.fromArchive({ path: 'manifest.c2pa' });

const signer = LocalSigner.newSigner(
await readFile('signer.pem'),
await readFile('signer.key'),
'es256',
);

restored.sign(
signer,
{ path: 'asset.jpg' },
{ path: 'signed-asset.jpg' },
);
```

### Two-phase workflow

**Phase 1 — prepare** a manifest and ingredients, then save an archive:

```typescript
import { Builder } from '@contentauth/c2pa-node';
import { readFile } from 'node:fs/promises';

const builder = Builder.new();
await builder.addIngredient(
JSON.stringify({ title: 'sketch.png', relationship: 'componentOf' }),
{ buffer: await readFile('sketch.png'), mimeType: 'image/png' },
);
await builder.toArchive({ path: 'draft.c2pa' });
```

**Phase 2 — sign** after loading the archive:

```typescript
import { Builder, LocalSigner } from '@contentauth/c2pa-node';
import { readFile } from 'node:fs/promises';

const builder = await Builder.fromArchive({ path: 'draft.c2pa' });
const signer = LocalSigner.newSigner(
await readFile('signer.pem'),
await readFile('signer.key'),
'es256',
);

builder.sign(
signer,
{ path: 'artwork.jpg' },
{ path: 'signed-artwork.jpg' },
);
```

### Reading an archive with `Reader`

Archives are read like other assets by setting `mimeType` to `application/c2pa`. You can list ingredients and copy binary resources into a new `Builder` with `addResource` (see [Getting resources from a manifest](../get-resources.mdx)).

```typescript
import { Reader } from '@contentauth/c2pa-node';
import { readFile } from 'node:fs/promises';

const archiveBuffer = await readFile('ingredients.c2pa');
const reader = await Reader.fromAsset(
{ buffer: archiveBuffer, mimeType: 'application/c2pa' },
{ verify: { verify_after_reading: false } },
);

const active = reader?.getActive();
const ingredients = active?.ingredients ?? [];
```

### Ingredient archives

To build a reusable ingredient catalog, add ingredients (stable `instance_id` values help later lookup), then call `toArchive`. Consumers read the archive with `Reader` and merge selected ingredients into a signing `Builder`, transferring thumbnails and `manifest_data` URIs with `resourceToAsset` / `addResource` as in the [@contentauth/c2pa-node README](https://github.com/contentauth/c2pa-node-v2#adding-ingredients-from-archives-c2pa-files).
Loading
Loading