diff --git a/docs/tasks/archives.mdx b/docs/tasks/archives.mdx
index ba345e16..f557edfb 100644
--- a/docs/tasks/archives.mdx
+++ b/docs/tasks/archives.mdx
@@ -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`:
@@ -35,5 +36,11 @@ _Working stores_ and _archives_ provide a standard way to save and restore the s
+
+
+
+
+
+
diff --git a/docs/tasks/build.mdx b/docs/tasks/build.mdx
index c5db6648..8549a03a 100644
--- a/docs/tasks/build.mdx
+++ b/docs/tasks/build.mdx
@@ -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';
@@ -30,5 +31,11 @@ import RustBuild from './rust/_rust-build.md';
+
+
+
+
+
+
diff --git a/docs/tasks/get-resources.mdx b/docs/tasks/get-resources.mdx
index 9d113561..19224534 100644
--- a/docs/tasks/get-resources.mdx
+++ b/docs/tasks/get-resources.mdx
@@ -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.
@@ -32,4 +33,10 @@ Manifest data can include binary resources such as thumbnail and icon images whi
+
+
+
+
+
+
diff --git a/docs/tasks/intents.mdx b/docs/tasks/intents.mdx
index 752a1714..7b222216 100644
--- a/docs/tasks/intents.mdx
+++ b/docs/tasks/intents.mdx
@@ -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.
@@ -41,5 +42,11 @@ There are three types of intents, shown here:
+
+
+
+
+
+
diff --git a/docs/tasks/node/_node-archives.mdx b/docs/tasks/node/_node-archives.mdx
new file mode 100644
index 00000000..c3813441
--- /dev/null
+++ b/docs/tasks/node/_node-archives.mdx
@@ -0,0 +1,114 @@
+import TOCInline from '@theme/TOCInline';
+
+
+
+### 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).
diff --git a/docs/tasks/node/_node-build.md b/docs/tasks/node/_node-build.md
index 6271fe8d..b1fb5335 100644
--- a/docs/tasks/node/_node-build.md
+++ b/docs/tasks/node/_node-build.md
@@ -1,171 +1,106 @@
-This is an example of how to assign a manifest to an asset and sign the claim using Node.js:
+Use the `Builder` and `LocalSigner` classes from `@contentauth/c2pa-node` to assemble manifest data and sign an asset.
-```ts
+### Create a builder
+
+```typescript
import { Builder } from '@contentauth/c2pa-node';
-// Create a new builder
+// Default settings
const builder = Builder.new();
-// Create with custom settings
-const settings = {
- builder: {
- generate_c2pa_archive: true
- }
-};
-const builder = Builder.new(settings);
+// With settings (JSON object or string; see [Settings](../settings.mdx))
+const withSettings = Builder.new({
+ builder: { generate_c2pa_archive: true },
+});
+
+// From an existing manifest definition (see manifest JSON reference)
+const fromDefinition = Builder.withJson({
+ claim_generator_info: [{ name: 'my-app', version: '1.0.0' }],
+ title: 'My image',
+ format: 'image/jpeg',
+ assertions: [],
+ resources: { resources: {} },
+});
+```
-// Or create from an existing manifest definition
-const builder = Builder.withJson(manifestDefinition);
+### Add assertions and resources
-// Or create with both manifest and settings
-const builder = Builder.withJson(manifestDefinition, settings);
+```typescript
+builder.addAssertion('c2pa.actions', {
+ actions: [{ action: 'c2pa.created' }],
+});
-// Add assertions to the manifest
-builder.addAssertion('c2pa.actions', actionsAssertion);
+await builder.addResource('resource://example/thumb', {
+ buffer: thumbnailBytes,
+ mimeType: 'image/jpeg',
+});
+```
-// Add resources
-await builder.addResource('resource://example', resourceAsset);
+### Sign with a local certificate and key
-// Sign the manifest
-const manifest = builder.sign(signer, inputAsset, outputAsset);
-```
+`LocalSigner.newSigner` takes the signing certificate (PEM), private key (PEM), algorithm (`es256`, `ps256`, `ed25519`, etc.), and an optional RFC 3161 timestamp URL.
-Use the `c2pa.sign()` method to sign an ingredient, either locally if you have a signing certificate and key available, or by using a remote signing API.
+```typescript
+import { Builder, LocalSigner } from '@contentauth/c2pa-node';
+import { readFile } from 'node:fs/promises';
-## Signing a stream
+const cert = await readFile('signer.pem');
+const key = await readFile('signer.key');
+const signer = LocalSigner.newSigner(cert, key, 'es256');
-If you have an asset file's data loaded into a stream, you can use it to sign the asset
+const builder = Builder.withJson({
+ claim_generator_info: [{ name: 'my-app', version: '1.0.0' }],
+ title: 'output.jpg',
+ format: 'image/jpeg',
+ assertions: [],
+ resources: { resources: {} },
+});
-**NOTE**: Signing using a stream is currently supported only for `image/jpeg` and `image/png` data. For all other file types, use the [file-based approach](#signing-files) .
+builder.setIntent('edit');
-```ts
-import { readFile } from 'node:fs/promises';
-import { createC2pa, createTestSigner } from 'c2pa-node';
+// Output to a file
+builder.sign(signer, { path: 'input.jpg' }, { path: 'signed.jpg' });
+```
-// read an asset into a buffer
-const buffer = await readFile('to-be-signed.jpg');
-const asset: Asset = { buffer, mimeType: 'image/jpeg' };
+### Sign to an in-memory buffer
-// build a manifest to use for signing
-const manifest = new ManifestBuilder(
- {
- claim_generator: 'my-app/1.0.0',
- format: 'image/jpeg',
- title: 'buffer_signer.jpg',
- assertions: [
- {
- label: 'c2pa.actions',
- data: {
- actions: [
- {
- action: 'c2pa.created',
- },
- ],
- },
- },
- {
- label: 'com.custom.my-assertion',
- data: {
- description: 'My custom test assertion',
- version: '1.0.0',
- },
- },
- ],
- },
- { vendor: 'cai' },
-);
+Use a destination object with `buffer: null`; after `sign`, the signed asset bytes are written into `dest.buffer`.
-// create a signing function
-async function sign(asset, manifest) {
- const signer = await createTestSigner();
- const c2pa = createC2pa({
- signer,
- });
-
- const { signedAsset, signedManifest } = await c2pa.sign({
- asset,
- manifest,
- });
-}
-
-// sign
-await sign(asset, manifest);
+```typescript
+const dest: { buffer: Buffer | null } = { buffer: null };
+builder.sign(signer, { path: 'input.jpg' }, dest);
+const signedBytes = dest.buffer;
```
-**Remote signing**
+### Callback signing (`signAsync`)
-If you have access to a web service that performs signing, you can use it to sign remotely; for example:
+For signing in hardware, a remote service, or other custom flows, use `CallbackSigner` and `signAsync`:
-```ts
+```typescript
+import { Builder, CallbackSigner } from '@contentauth/c2pa-node';
import { readFile } from 'node:fs/promises';
-import { fetch, Headers } from 'node-fetch';
-import { createC2pa, SigningAlgorithm } from 'c2pa-node';
-
-function createRemoteSigner() {
- return {
- type: 'remote',
- async reserveSize() {
- const url = `https://my.signing.service/box-size`;
- const res = await fetch(url);
- const data = (await res.json()) as { boxSize: number };
- return data.boxSize;
- },
- async sign({ reserveSize, toBeSigned }) {
- const url = `https://my.signing.service/sign?boxSize=${reserveSize}`;
- const res = await fetch(url, {
- method: 'POST',
- headers: new Headers({
- 'Content-Type': 'application/octet-stream',
- }),
- body: toBeSigned,
- });
- return res.buffer();
- },
- };
-}
-
-async function sign(asset, manifest) {
- const signer = createRemoteSigner();
- const c2pa = createC2pa({
- signer,
- });
-
- const { signedAsset, signedManifest } = await c2pa.sign({
- asset,
- manifest,
- });
-}
-
-const buffer = await readFile('to-be-signed.jpg');
-const asset: Asset = { buffer, mimeType: 'image/jpeg' };
-
-const manifest = new ManifestBuilder(
+
+const cert = await readFile('signer.pem');
+
+const callbackSigner = CallbackSigner.newSigner(
{
- claim_generator: 'my-app/1.0.0',
- format: 'image/jpeg',
- title: 'buffer_signer.jpg',
- assertions: [
- {
- label: 'c2pa.actions',
- data: {
- actions: [
- {
- action: 'c2pa.created',
- },
- ],
- },
- },
- {
- label: 'com.custom.my-assertion',
- data: {
- description: 'My custom test assertion',
- version: '1.0.0',
- },
- },
- ],
+ alg: 'es256',
+ certs: [cert],
+ reserveSize: 1024,
+ },
+ async (data: Buffer) => {
+ return customSign(data);
},
- { vendor: 'cai' },
);
-await sign(asset, manifest);
-```
\ No newline at end of file
+const builder = Builder.new();
+await builder.signAsync(
+ callbackSigner,
+ { path: 'input.jpg' },
+ { path: 'signed.jpg' },
+);
+```
+
+Replace `customSign` with your implementation that returns the detached signature bytes for the C2PA claim.
+
+For identity assertions (CAWG), see `IdentityAssertionBuilder` and `IdentityAssertionSigner` in the [c2pa-node-v2 README](https://github.com/contentauth/c2pa-node-v2#identity-assertion-components).
diff --git a/docs/tasks/node/_node-get-resources.md b/docs/tasks/node/_node-get-resources.md
index 68006e78..4f5a0e54 100644
--- a/docs/tasks/node/_node-get-resources.md
+++ b/docs/tasks/node/_node-get-resources.md
@@ -1,10 +1,74 @@
-The example below shows how to get resources from manifest data using the Node.js library.
+Binary resources (thumbnails, icons, linked manifest blobs) are referenced by URI strings in the active manifest. Use `Reader.resourceToAsset` to copy a resource to a file path or to a buffer.
-```js
-import { createC2pa } from 'c2pa-node';
-import { readFile } from 'node:fs/promises';
+### Write a resource to a file
-const c2pa = createC2pa();
+```typescript
+import { Reader } from '@contentauth/c2pa-node';
+import path from 'node:path';
-// TBD
-```
\ No newline at end of file
+async function writeThumbnail(
+ assetPath: string,
+ outputPath: string,
+): Promise {
+ const reader = await Reader.fromAsset({ path: assetPath });
+ if (!reader) {
+ throw new Error('No C2PA manifest found for this asset.');
+ }
+
+ const manifest = reader.getActive();
+ const uri = manifest?.thumbnail?.identifier;
+ if (!uri) {
+ throw new Error('Active manifest has no thumbnail.');
+ }
+
+ await reader.resourceToAsset(uri, { path: path.resolve(outputPath) });
+}
+```
+
+### Read a resource into a buffer
+
+Pass a destination object with `buffer: null`. The implementation fills `buffer` after the call.
+
+```typescript
+import { Reader } from '@contentauth/c2pa-node';
+
+async function readResourceToBuffer(
+ assetPath: string,
+ uri: string,
+): Promise {
+ const reader = await Reader.fromAsset({ path: assetPath });
+ if (!reader) {
+ throw new Error('No C2PA manifest found.');
+ }
+
+ const dest: { buffer: Buffer | null } = { buffer: null };
+ await reader.resourceToAsset(uri, dest);
+ if (!dest.buffer) {
+ throw new Error('Resource could not be read.');
+ }
+ return dest.buffer;
+}
+```
+
+### Discover URIs from JSON
+
+You can inspect `reader.json()` for the full manifest store, or use `getActive()` for the active manifest only. Ingredient thumbnails use the same `identifier` pattern as the claim thumbnail.
+
+```typescript
+import { Reader } from '@contentauth/c2pa-node';
+
+const reader = await Reader.fromAsset({ path: 'signed.jpg' });
+if (!reader) {
+ process.exit(0);
+}
+
+const store = reader.json();
+console.log(JSON.stringify(store, null, 2));
+
+const active = reader.getActive();
+for (const ing of active?.ingredients ?? []) {
+ if (ing.thumbnail?.identifier) {
+ console.log('Ingredient thumbnail URI:', ing.thumbnail.identifier);
+ }
+}
+```
diff --git a/docs/tasks/node/_node-intents.md b/docs/tasks/node/_node-intents.md
new file mode 100644
index 00000000..fdc9e6e5
--- /dev/null
+++ b/docs/tasks/node/_node-intents.md
@@ -0,0 +1,94 @@
+### Setting the intent
+
+In Node.js, call `setIntent` on a `Builder` from `@contentauth/c2pa-node`. The intent shapes validation, default actions, and whether a parent ingredient is required.
+
+```typescript
+import { Builder } from '@contentauth/c2pa-node';
+
+const builder = Builder.new();
+
+// Runtime intent (Create, Edit, or Update)
+builder.setIntent({
+ create:
+ 'http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia',
+});
+```
+
+You can also set `edit` or `update` with a string:
+
+```typescript
+builder.setIntent('edit');
+builder.setIntent('update');
+```
+
+### Create intent
+
+Use a `create` intent for new digital creations. You must supply a [digital source type](https://c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_digital_source_type) URI. The manifest must not have a parent ingredient; the SDK can add a `c2pa.created` action when appropriate.
+
+```typescript
+import { Builder, LocalSigner } from '@contentauth/c2pa-node';
+import { readFile } from 'node:fs/promises';
+
+const builder = Builder.new();
+builder.setIntent({
+ create:
+ 'http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture',
+});
+
+const signer = LocalSigner.newSigner(
+ await readFile('signer.pem'),
+ await readFile('signer.key'),
+ 'es256',
+);
+
+builder.sign(
+ signer,
+ { path: 'source.jpg' },
+ { path: 'signed.jpg' },
+);
+```
+
+### Edit intent
+
+Use `edit` when modifying existing content. If you do not add a parent ingredient, one can be created from the source asset you pass to `sign`.
+
+```typescript
+import { Builder } from '@contentauth/c2pa-node';
+
+const builder = Builder.new();
+builder.setIntent('edit');
+```
+
+To supply the parent explicitly, add an ingredient JSON string and optional asset buffer (see [Adding manifest data](../build.mdx)):
+
+```typescript
+import { Builder } from '@contentauth/c2pa-node';
+import { readFile } from 'node:fs/promises';
+
+const builder = Builder.new();
+builder.setIntent('edit');
+
+const parentJson = JSON.stringify({
+ title: 'Original Photo',
+ relationship: 'parentOf',
+ format: 'image/jpeg',
+});
+
+await builder.addIngredient(parentJson, {
+ buffer: await readFile('original.jpg'),
+ mimeType: 'image/jpeg',
+});
+```
+
+### Update intent
+
+Use `update` for restricted, metadata-oriented changes: typically a single parent ingredient and no changes to the parent’s hashed content.
+
+```typescript
+import { Builder } from '@contentauth/c2pa-node';
+
+const builder = Builder.new();
+builder.setIntent('update');
+```
+
+For more detail on intent semantics, see the [c2pa-rs `Builder` documentation](https://docs.rs/c2pa/latest/c2pa/struct.Builder.html).
diff --git a/docs/tasks/node/_node-read.md b/docs/tasks/node/_node-read.md
index 3c2e2485..06b90c38 100644
--- a/docs/tasks/node/_node-read.md
+++ b/docs/tasks/node/_node-read.md
@@ -42,7 +42,10 @@ import { Reader } from '@contentauth/c2pa-node';
async function readFromBuffer(filePath: string): Promise {
const buffer = await fs.readFile(filePath);
- const reader = await Reader.fromAsset({ buffer, mimeType: 'jpeg' }); // adjust mimeType as needed
+ const reader = await Reader.fromAsset({
+ buffer,
+ mimeType: 'image/jpeg',
+ });
if (!reader) {
console.log('No C2PA manifest found.');
return;
diff --git a/docs/tasks/node/_node-settings.md b/docs/tasks/node/_node-settings.md
index 459689c1..04b71f3d 100644
--- a/docs/tasks/node/_node-settings.md
+++ b/docs/tasks/node/_node-settings.md
@@ -1,29 +1,61 @@
-```ts
+The Node.js library does not expose a `Context` type. Instead, you pass **per-instance** settings: a JavaScript object, a JSON string, or file contents (JSON or TOML) from `loadSettingsFromFile`, as the second argument to `Reader.fromAsset`, `Reader.fromManifestDataAndAsset`, `Builder.new`, `Builder.withJson`, or `Builder.fromArchive`.
+
+For the full settings schema, see [SDK object reference — Settings](../../manifest/json-ref/settings-schema).
+
+### Inline settings
+
+```typescript
+import { Reader } from '@contentauth/c2pa-node';
+
+const settings = {
+ verify: {
+ verify_after_reading: false,
+ verify_trust: true,
+ },
+};
+
+const reader = await Reader.fromAsset({ path: 'image.jpg' }, settings);
+```
+
+`Builder` accepts the same shape (or a JSON string):
+
+```typescript
+import { Builder } from '@contentauth/c2pa-node';
+
+const builder = Builder.new({
+ builder: { generate_c2pa_archive: true },
+});
+```
+
+### Helper functions
+
+Use the helpers from `@contentauth/c2pa-node` to build typed fragments, merge them, and serialize to JSON (camelCase keys are converted to snake_case for the Rust-backed SDK):
+
+```typescript
import {
+ Builder,
+ Reader,
createTrustSettings,
createCawgTrustSettings,
createVerifySettings,
mergeSettings,
settingsToJson,
loadSettingsFromFile,
- loadSettingsFromUrl
+ loadSettingsFromUrl,
} from '@contentauth/c2pa-node';
-// Create trust settings
const trustSettings = createTrustSettings({
verifyTrustList: true,
- userAnchors: "path/to/user-anchors.pem",
- trustAnchors: "path/to/trust-anchors.pem",
- allowedList: "path/to/allowed-list.pem"
+ userAnchors: 'path/to/user-anchors.pem',
+ trustAnchors: 'path/to/trust-anchors.pem',
+ allowedList: 'path/to/allowed-list.pem',
});
-// Create CAWG trust settings
const cawgTrustSettings = createCawgTrustSettings({
verifyTrustList: true,
- trustAnchors: "path/to/cawg-anchors.pem"
+ trustAnchors: 'path/to/cawg-anchors.pem',
});
-// Create verify settings
const verifySettings = createVerifySettings({
verifyAfterReading: false,
verifyAfterSign: false,
@@ -32,20 +64,23 @@ const verifySettings = createVerifySettings({
ocspFetch: true,
remoteManifestFetch: true,
skipIngredientConflictResolution: false,
- strictV1Validation: false
+ strictV1Validation: false,
});
-// Merge multiple settings
-const combinedSettings = mergeSettings(trustSettings, verifySettings);
+const combined = mergeSettings(trustSettings, verifySettings, cawgTrustSettings);
+const asJson = settingsToJson(combined);
+```
+
+### Load settings from a file or URL
-// Convert settings to JSON string
-const jsonString = settingsToJson(combinedSettings);
+```typescript
+import { Reader, Builder, loadSettingsFromFile, loadSettingsFromUrl } from '@contentauth/c2pa-node';
-// Load settings from file (JSON or TOML)
const fileSettings = await loadSettingsFromFile('./c2pa-settings.toml');
-const reader = await Reader.fromAsset(inputAsset, fileSettings);
+const reader = await Reader.fromAsset({ path: 'image.jpg' }, fileSettings);
-// Load settings from URL
const urlSettings = await loadSettingsFromUrl('https://example.com/c2pa-settings.json');
const builder = Builder.new(urlSettings);
-```
\ No newline at end of file
+```
+
+Only use HTTPS URLs you trust for `loadSettingsFromUrl`.
diff --git a/docs/tasks/node/_node-wip.md b/docs/tasks/node/_node-wip.md
deleted file mode 100644
index ca2cd717..00000000
--- a/docs/tasks/node/_node-wip.md
+++ /dev/null
@@ -1,3 +0,0 @@
-:::note
-The Node.js library is being revised. The documentation will be updated as soon as possible with the latest changes.
-:::
\ No newline at end of file
diff --git a/docs/tasks/read.mdx b/docs/tasks/read.mdx
index fe80cc31..43b55d3d 100644
--- a/docs/tasks/read.mdx
+++ b/docs/tasks/read.mdx
@@ -10,6 +10,7 @@ import TabItem from '@theme/TabItem';
import PythonRead from './python/_python-read.md';
import CppRead from './cpp/_cpp-read.md';
import RustRead from './rust/_rust-read.md';
+import NodeRead from './node/_node-read.md';
@@ -31,4 +32,10 @@ import RustRead from './rust/_rust-read.md';
+
+
+
+
+
+
diff --git a/docs/tasks/settings.mdx b/docs/tasks/settings.mdx
index acd23431..b0d3d5c5 100644
--- a/docs/tasks/settings.mdx
+++ b/docs/tasks/settings.mdx
@@ -10,6 +10,7 @@ import TabItem from '@theme/TabItem';
import PythonRead from './python/_python-settings.md';
import CppRead from './cpp/_cpp-settings.md';
import RustRead from './rust/_rust-settings.md';
+import NodeSettings from './node/_node-settings.md';
Regardless of which language you're working in, you use the `Context` and `Settings` classes to control SDK behavior including verification, trust anchors, thumbnails, signing, and more.
@@ -92,4 +93,10 @@ For Boolean values, use JSON `true` and `false`, not the strings `"true"` and `"
+
+
+
+
+
+