@hashproof/sdk 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +248 -0
- package/dist/index.cjs +335 -0
- package/dist/index.d.cts +231 -0
- package/dist/index.d.ts +231 -0
- package/dist/index.js +307 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# @hashproof/sdk
|
|
2
|
+
|
|
3
|
+
> Published as `@hashproof/sdk` on npm. The source directory is `packages/sdk-js` (legacy name).
|
|
4
|
+
|
|
5
|
+
Official JavaScript/TypeScript SDK for the [Hashproof](https://hashproof.ai) Content Provenance API.
|
|
6
|
+
|
|
7
|
+
Hashproof provides content provenance infrastructure built on the C2PA standard. This SDK wraps the REST API with a type-safe client for storing, resolving, verifying, and signing digital assets.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @hashproof/sdk
|
|
13
|
+
# or
|
|
14
|
+
pnpm add @hashproof/sdk
|
|
15
|
+
# or
|
|
16
|
+
yarn add @hashproof/sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { HashproofClient } from '@hashproof/sdk';
|
|
23
|
+
import { readFileSync } from 'node:fs';
|
|
24
|
+
|
|
25
|
+
const client = new HashproofClient({ apiKey: 'hpsk_...' });
|
|
26
|
+
|
|
27
|
+
// Verify a file's provenance
|
|
28
|
+
const file = readFileSync('photo.jpg');
|
|
29
|
+
const result = await client.verify(file);
|
|
30
|
+
|
|
31
|
+
if (result.hasProvenance) {
|
|
32
|
+
console.log(`Provenance found via: ${result.source}`);
|
|
33
|
+
console.log(`Trust status: ${result.trustStatus}`);
|
|
34
|
+
console.log(`Signer: ${result.manifest?.signatureInfo.subject}`);
|
|
35
|
+
} else {
|
|
36
|
+
console.log('No provenance found for this file.');
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Configuration
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
const client = new HashproofClient({
|
|
44
|
+
apiKey: 'hpsk_...', // Required. Your Hashproof API key.
|
|
45
|
+
baseUrl: 'https://api.hashproof.ai', // Optional. Defaults to production.
|
|
46
|
+
timeout: 30000, // Optional. Request timeout in ms.
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## API Reference
|
|
51
|
+
|
|
52
|
+
### `store(file, options?)`
|
|
53
|
+
|
|
54
|
+
Upload a digital asset and extract/store its C2PA manifest. Perceptual fingerprints are computed automatically.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
const result = await client.store(fileBuffer, { title: 'Press Photo' });
|
|
58
|
+
console.log(result.manifestId);
|
|
59
|
+
console.log(result.softBindings); // computed perceptual hashes
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Parameters:**
|
|
63
|
+
| Name | Type | Description |
|
|
64
|
+
|------|------|-------------|
|
|
65
|
+
| `file` | `Buffer \| Blob` | The digital asset to store |
|
|
66
|
+
| `options.title` | `string` | Optional human-readable title |
|
|
67
|
+
|
|
68
|
+
**Returns:** `Promise<StoreResult>`
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
### `resolve(file)` / `resolve(fingerprint, algorithm?)`
|
|
73
|
+
|
|
74
|
+
Resolve provenance for a file or pre-computed fingerprint. Finds matching manifests via perceptual hashing (soft binding).
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
// By file upload
|
|
78
|
+
const result = await client.resolve(imageBuffer);
|
|
79
|
+
|
|
80
|
+
// By pre-computed fingerprint (no upload needed)
|
|
81
|
+
const result = await client.resolve('a1b2c3d4...', 'phash-dct-64');
|
|
82
|
+
|
|
83
|
+
for (const match of result.matches) {
|
|
84
|
+
console.log(`${match.similarity * 100}% similar — ${match.manifest.title}`);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Parameters (file overload):**
|
|
89
|
+
| Name | Type | Description |
|
|
90
|
+
|------|------|-------------|
|
|
91
|
+
| `file` | `Buffer \| Blob` | The file to resolve |
|
|
92
|
+
|
|
93
|
+
**Parameters (fingerprint overload):**
|
|
94
|
+
| Name | Type | Description |
|
|
95
|
+
|------|------|-------------|
|
|
96
|
+
| `fingerprint` | `string` | Hex-encoded perceptual hash |
|
|
97
|
+
| `algorithm` | `string` | Algorithm name (default: `phash-dct-64`) |
|
|
98
|
+
|
|
99
|
+
**Returns:** `Promise<ResolveResult>`
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### `verify(file)`
|
|
104
|
+
|
|
105
|
+
One-call provenance verification. Checks embedded C2PA manifests, hard binding (hash match), and soft binding (perceptual hash resolution).
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
const result = await client.verify(imageBuffer);
|
|
109
|
+
console.log(result.hasProvenance); // boolean
|
|
110
|
+
console.log(result.source); // 'embedded' | 'resolved' | 'none'
|
|
111
|
+
console.log(result.trustStatus); // 'trusted' | 'untrusted' | 'unknown'
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Parameters:**
|
|
115
|
+
| Name | Type | Description |
|
|
116
|
+
|------|------|-------------|
|
|
117
|
+
| `file` | `Buffer \| Blob` | The file to verify |
|
|
118
|
+
|
|
119
|
+
**Returns:** `Promise<VerifyResult>`
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### `getManifest(id)`
|
|
124
|
+
|
|
125
|
+
Retrieve a manifest by its UUID.
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const manifest = await client.getManifest('550e8400-...');
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Returns:** `Promise<ManifestData>`
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### `getManifestByHash(hash)`
|
|
136
|
+
|
|
137
|
+
Retrieve a manifest by its hard binding hash (SHA-256 of the original asset).
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
const manifest = await client.getManifestByHash('e3b0c44298fc...');
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Returns:** `Promise<ManifestData>`
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
### `listManifests(options?)`
|
|
148
|
+
|
|
149
|
+
List manifests with pagination and search.
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const page = await client.listManifests({ page: 1, perPage: 50, search: 'photo' });
|
|
153
|
+
console.log(`${page.total} total manifests`);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Parameters:**
|
|
157
|
+
| Name | Type | Description |
|
|
158
|
+
|------|------|-------------|
|
|
159
|
+
| `options.page` | `number` | Page number (default: 1) |
|
|
160
|
+
| `options.perPage` | `number` | Results per page (default: 20) |
|
|
161
|
+
| `options.search` | `string` | Filter by title |
|
|
162
|
+
|
|
163
|
+
**Returns:** `Promise<PaginatedResponse<ManifestData>>`
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
### `sign(file, options?)`
|
|
168
|
+
|
|
169
|
+
Sign a digital asset with a C2PA manifest using Hashproof managed signing. Requires the `sign` scope on your API key.
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
const result = await client.sign(imageBuffer, { title: 'Press Photo' });
|
|
173
|
+
console.log(result.manifestId);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Parameters:**
|
|
177
|
+
| Name | Type | Description |
|
|
178
|
+
|------|------|-------------|
|
|
179
|
+
| `file` | `Buffer \| Blob` | The file to sign |
|
|
180
|
+
| `options.title` | `string` | Optional title |
|
|
181
|
+
|
|
182
|
+
**Returns:** `Promise<SignResult>`
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
### `computeFingerprint(file, algorithm?)`
|
|
187
|
+
|
|
188
|
+
Compute a perceptual fingerprint without resolving. Useful for offline computation followed by later resolution.
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
const fp = await client.computeFingerprint(imageBuffer);
|
|
192
|
+
console.log(fp.fingerprint); // hex string
|
|
193
|
+
console.log(fp.algorithm); // 'phash-dct-64'
|
|
194
|
+
|
|
195
|
+
// Later, resolve without re-uploading:
|
|
196
|
+
const matches = await client.resolve(fp.fingerprint, fp.algorithm);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Parameters:**
|
|
200
|
+
| Name | Type | Description |
|
|
201
|
+
|------|------|-------------|
|
|
202
|
+
| `file` | `Buffer \| Blob` | The file to fingerprint |
|
|
203
|
+
| `algorithm` | `string` | Algorithm (default: `phash-dct-64`) |
|
|
204
|
+
|
|
205
|
+
**Returns:** `Promise<FingerprintResult>`
|
|
206
|
+
|
|
207
|
+
## Error Handling
|
|
208
|
+
|
|
209
|
+
All API errors are thrown as `HashproofApiError` instances:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
import { HashproofClient, HashproofApiError } from '@hashproof/sdk';
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
await client.getManifest('nonexistent');
|
|
216
|
+
} catch (err) {
|
|
217
|
+
if (err instanceof HashproofApiError) {
|
|
218
|
+
console.error(err.message); // "Manifest not found"
|
|
219
|
+
console.error(err.statusCode); // 404
|
|
220
|
+
console.error(err.code); // "NOT_FOUND"
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## TypeScript
|
|
226
|
+
|
|
227
|
+
All types are exported from the package for full type safety:
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
import type {
|
|
231
|
+
ManifestData,
|
|
232
|
+
VerifyResult,
|
|
233
|
+
ResolveResult,
|
|
234
|
+
ValidationStatus,
|
|
235
|
+
PaginatedResponse,
|
|
236
|
+
} from '@hashproof/sdk';
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Supported Runtimes
|
|
240
|
+
|
|
241
|
+
- Node.js 18+ (uses native `fetch`)
|
|
242
|
+
- Deno
|
|
243
|
+
- Bun
|
|
244
|
+
- Modern browsers (via bundler)
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
HashproofApiError: () => HashproofApiError,
|
|
24
|
+
HashproofClient: () => HashproofClient
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/types.ts
|
|
29
|
+
var HashproofApiError = class extends Error {
|
|
30
|
+
/** HTTP status code. */
|
|
31
|
+
statusCode;
|
|
32
|
+
/** Machine-readable error code. */
|
|
33
|
+
code;
|
|
34
|
+
/** Additional error details. */
|
|
35
|
+
details;
|
|
36
|
+
constructor(message, statusCode, code, details) {
|
|
37
|
+
super(message);
|
|
38
|
+
this.name = "HashproofApiError";
|
|
39
|
+
this.statusCode = statusCode;
|
|
40
|
+
this.code = code;
|
|
41
|
+
this.details = details;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/index.ts
|
|
46
|
+
var DEFAULT_BASE_URL = "https://api.hashproof.ai";
|
|
47
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
48
|
+
var HashproofClient = class {
|
|
49
|
+
apiKey;
|
|
50
|
+
baseUrl;
|
|
51
|
+
timeout;
|
|
52
|
+
/**
|
|
53
|
+
* Create a new HashproofClient instance.
|
|
54
|
+
*
|
|
55
|
+
* @param options - Client configuration options.
|
|
56
|
+
* @param options.apiKey - Your Hashproof API key (starts with `hpsk_`).
|
|
57
|
+
* @param options.baseUrl - Base URL for the API. Defaults to `https://api.hashproof.ai`.
|
|
58
|
+
* @param options.timeout - Request timeout in milliseconds. Defaults to 30000.
|
|
59
|
+
* @throws {Error} If no API key is provided.
|
|
60
|
+
*/
|
|
61
|
+
constructor(options) {
|
|
62
|
+
if (!options.apiKey) {
|
|
63
|
+
throw new Error('Hashproof API key is required. Pass { apiKey: "hpsk_..." } to the constructor.');
|
|
64
|
+
}
|
|
65
|
+
this.apiKey = options.apiKey;
|
|
66
|
+
this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
67
|
+
this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
68
|
+
}
|
|
69
|
+
// ============================================================
|
|
70
|
+
// Manifest Operations
|
|
71
|
+
// ============================================================
|
|
72
|
+
/**
|
|
73
|
+
* Store a C2PA manifest by uploading a digital asset.
|
|
74
|
+
*
|
|
75
|
+
* The API extracts the embedded C2PA manifest from the file,
|
|
76
|
+
* computes perceptual fingerprints (soft bindings), and stores
|
|
77
|
+
* everything for future resolution and verification.
|
|
78
|
+
*
|
|
79
|
+
* @param file - The file to store as a Buffer or Blob.
|
|
80
|
+
* @param options - Optional parameters.
|
|
81
|
+
* @param options.title - A human-readable title for the asset.
|
|
82
|
+
* @returns The stored manifest data along with computed soft bindings.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* const result = await client.store(fileBuffer, { title: 'My Photo' });
|
|
87
|
+
* console.log(result.manifestId);
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
async store(file, options) {
|
|
91
|
+
const formData = new FormData();
|
|
92
|
+
const blob = file instanceof Blob ? file : new Blob([file]);
|
|
93
|
+
formData.append("file", blob, "upload");
|
|
94
|
+
if (options?.title) {
|
|
95
|
+
formData.append("title", options.title);
|
|
96
|
+
}
|
|
97
|
+
return this.request("POST", "/v1/manifests", formData);
|
|
98
|
+
}
|
|
99
|
+
async resolve(fileOrFingerprint, algorithm) {
|
|
100
|
+
if (typeof fileOrFingerprint === "string") {
|
|
101
|
+
const params = new URLSearchParams({ fingerprint: fileOrFingerprint });
|
|
102
|
+
if (algorithm) params.set("algorithm", algorithm);
|
|
103
|
+
return this.request("GET", `/v1/resolve?${params.toString()}`);
|
|
104
|
+
}
|
|
105
|
+
const formData = new FormData();
|
|
106
|
+
const blob = fileOrFingerprint instanceof Blob ? fileOrFingerprint : new Blob([fileOrFingerprint]);
|
|
107
|
+
formData.append("file", blob, "upload");
|
|
108
|
+
if (algorithm) {
|
|
109
|
+
formData.append("algorithm", algorithm);
|
|
110
|
+
}
|
|
111
|
+
return this.request("POST", "/v1/resolve", formData);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Verify the provenance of a digital asset.
|
|
115
|
+
*
|
|
116
|
+
* This is the main one-call verification endpoint. It checks:
|
|
117
|
+
* 1. Embedded C2PA manifests in the file
|
|
118
|
+
* 2. Hard binding (SHA-256 hash match) against stored manifests
|
|
119
|
+
* 3. Soft binding (perceptual hash) resolution
|
|
120
|
+
*
|
|
121
|
+
* @param file - The file to verify as a Buffer or Blob.
|
|
122
|
+
* @returns Verification result including provenance source, manifest data, and trust status.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* const result = await client.verify(imageBuffer);
|
|
127
|
+
* if (result.hasProvenance) {
|
|
128
|
+
* console.log(`Source: ${result.source}, Trust: ${result.trustStatus}`);
|
|
129
|
+
* }
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
async verify(file) {
|
|
133
|
+
const formData = new FormData();
|
|
134
|
+
const blob = file instanceof Blob ? file : new Blob([file]);
|
|
135
|
+
formData.append("file", blob, "upload");
|
|
136
|
+
return this.request("POST", "/v1/verify", formData);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Retrieve a manifest by its ID.
|
|
140
|
+
*
|
|
141
|
+
* @param id - The manifest UUID.
|
|
142
|
+
* @returns The full manifest data.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* const manifest = await client.getManifest('550e8400-e29b-41d4-a716-446655440000');
|
|
147
|
+
* console.log(manifest.title, manifest.validationStatus);
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
async getManifest(id) {
|
|
151
|
+
return this.request("GET", `/v1/manifests/${encodeURIComponent(id)}`);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Retrieve a manifest by its hard binding hash (SHA-256).
|
|
155
|
+
*
|
|
156
|
+
* @param hash - The SHA-256 hash of the original asset.
|
|
157
|
+
* @returns The matching manifest data.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```ts
|
|
161
|
+
* const manifest = await client.getManifestByHash('e3b0c44298fc1c149afbf4c8996fb924...');
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
async getManifestByHash(hash) {
|
|
165
|
+
const params = new URLSearchParams({ hash });
|
|
166
|
+
return this.request("GET", `/v1/manifests?${params.toString()}`);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* List manifests with optional pagination and search.
|
|
170
|
+
*
|
|
171
|
+
* @param options - Pagination and search options.
|
|
172
|
+
* @param options.page - Page number (1-indexed). Defaults to 1.
|
|
173
|
+
* @param options.perPage - Results per page. Defaults to 20.
|
|
174
|
+
* @param options.search - Search term to filter manifests by title.
|
|
175
|
+
* @returns A paginated list of manifests.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* const page = await client.listManifests({ page: 1, search: 'photo' });
|
|
180
|
+
* console.log(`${page.total} manifests found`);
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
async listManifests(options) {
|
|
184
|
+
const params = new URLSearchParams();
|
|
185
|
+
if (options?.page) params.set("page", String(options.page));
|
|
186
|
+
if (options?.perPage) params.set("perPage", String(options.perPage));
|
|
187
|
+
if (options?.search) params.set("search", options.search);
|
|
188
|
+
const query = params.toString();
|
|
189
|
+
return this.request(
|
|
190
|
+
"GET",
|
|
191
|
+
`/v1/manifests${query ? `?${query}` : ""}`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
// ============================================================
|
|
195
|
+
// Signing
|
|
196
|
+
// ============================================================
|
|
197
|
+
/**
|
|
198
|
+
* Sign a digital asset with a C2PA manifest using Hashproof's managed signing.
|
|
199
|
+
*
|
|
200
|
+
* This is the "Let's Encrypt for C2PA" endpoint -- you upload a file and
|
|
201
|
+
* Hashproof creates a signed C2PA manifest on your behalf, without you
|
|
202
|
+
* needing to manage certificates or PKI.
|
|
203
|
+
*
|
|
204
|
+
* Requires the `sign` scope on your API key.
|
|
205
|
+
*
|
|
206
|
+
* @param file - The file to sign as a Buffer or Blob.
|
|
207
|
+
* @param options - Optional parameters.
|
|
208
|
+
* @param options.title - A human-readable title for the asset.
|
|
209
|
+
* @returns The signing result including the new manifest ID.
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* const result = await client.sign(imageBuffer, { title: 'Press Photo 2024' });
|
|
214
|
+
* console.log(result.manifestId);
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
async sign(file, options) {
|
|
218
|
+
const formData = new FormData();
|
|
219
|
+
const blob = file instanceof Blob ? file : new Blob([file]);
|
|
220
|
+
formData.append("file", blob, "upload");
|
|
221
|
+
if (options?.title) {
|
|
222
|
+
formData.append("title", options.title);
|
|
223
|
+
}
|
|
224
|
+
return this.request("POST", "/v1/sign", formData);
|
|
225
|
+
}
|
|
226
|
+
// ============================================================
|
|
227
|
+
// Fingerprinting
|
|
228
|
+
// ============================================================
|
|
229
|
+
/**
|
|
230
|
+
* Compute a perceptual fingerprint for a file without resolving.
|
|
231
|
+
*
|
|
232
|
+
* Useful when you want to compute and store a fingerprint client-side
|
|
233
|
+
* for later resolution via `resolve(fingerprint, algorithm)`.
|
|
234
|
+
*
|
|
235
|
+
* @param file - The file to fingerprint as a Buffer or Blob.
|
|
236
|
+
* @param algorithm - The algorithm to use. Defaults to `phash-dct-64`.
|
|
237
|
+
* @returns The computed fingerprint, algorithm, and bit length.
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```ts
|
|
241
|
+
* const fp = await client.computeFingerprint(imageBuffer, 'phash-dct-64');
|
|
242
|
+
* console.log(fp.fingerprint); // hex string
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
async computeFingerprint(file, algorithm) {
|
|
246
|
+
const formData = new FormData();
|
|
247
|
+
const blob = file instanceof Blob ? file : new Blob([file]);
|
|
248
|
+
formData.append("file", blob, "upload");
|
|
249
|
+
if (algorithm) {
|
|
250
|
+
formData.append("algorithm", algorithm);
|
|
251
|
+
}
|
|
252
|
+
return this.request("POST", "/v1/fingerprint", formData);
|
|
253
|
+
}
|
|
254
|
+
// ============================================================
|
|
255
|
+
// Internal HTTP Client
|
|
256
|
+
// ============================================================
|
|
257
|
+
/**
|
|
258
|
+
* Make an authenticated HTTP request to the Hashproof API.
|
|
259
|
+
* @internal
|
|
260
|
+
*/
|
|
261
|
+
async request(method, path, body) {
|
|
262
|
+
const url = `${this.baseUrl}${path}`;
|
|
263
|
+
const headers = {
|
|
264
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
265
|
+
Accept: "application/json"
|
|
266
|
+
};
|
|
267
|
+
let requestBody;
|
|
268
|
+
if (body instanceof FormData) {
|
|
269
|
+
requestBody = body;
|
|
270
|
+
} else if (body) {
|
|
271
|
+
headers["Content-Type"] = "application/json";
|
|
272
|
+
requestBody = JSON.stringify(body);
|
|
273
|
+
}
|
|
274
|
+
const controller = new AbortController();
|
|
275
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
276
|
+
let response;
|
|
277
|
+
try {
|
|
278
|
+
response = await fetch(url, {
|
|
279
|
+
method,
|
|
280
|
+
headers,
|
|
281
|
+
body: requestBody,
|
|
282
|
+
signal: controller.signal
|
|
283
|
+
});
|
|
284
|
+
} catch (err) {
|
|
285
|
+
clearTimeout(timeoutId);
|
|
286
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
287
|
+
throw new HashproofApiError(
|
|
288
|
+
`Request timed out after ${this.timeout}ms`,
|
|
289
|
+
0,
|
|
290
|
+
"TIMEOUT"
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
throw new HashproofApiError(
|
|
294
|
+
`Network error: ${err instanceof Error ? err.message : String(err)}`,
|
|
295
|
+
0,
|
|
296
|
+
"NETWORK_ERROR"
|
|
297
|
+
);
|
|
298
|
+
} finally {
|
|
299
|
+
clearTimeout(timeoutId);
|
|
300
|
+
}
|
|
301
|
+
const responseBody = await response.text();
|
|
302
|
+
let parsed;
|
|
303
|
+
try {
|
|
304
|
+
parsed = JSON.parse(responseBody);
|
|
305
|
+
} catch {
|
|
306
|
+
if (!response.ok) {
|
|
307
|
+
throw new HashproofApiError(
|
|
308
|
+
`HTTP ${response.status}: ${responseBody.slice(0, 200)}`,
|
|
309
|
+
response.status,
|
|
310
|
+
"UNEXPECTED_RESPONSE"
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
throw new HashproofApiError(
|
|
314
|
+
"Failed to parse API response as JSON",
|
|
315
|
+
response.status,
|
|
316
|
+
"PARSE_ERROR"
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
if (!response.ok) {
|
|
320
|
+
const errBody = parsed;
|
|
321
|
+
throw new HashproofApiError(
|
|
322
|
+
errBody.error || `HTTP ${response.status}`,
|
|
323
|
+
errBody.statusCode || response.status,
|
|
324
|
+
errBody.code || "API_ERROR",
|
|
325
|
+
errBody.details
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
return parsed;
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
332
|
+
0 && (module.exports = {
|
|
333
|
+
HashproofApiError,
|
|
334
|
+
HashproofClient
|
|
335
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import * as _hashproof_shared from '@hashproof/shared';
|
|
2
|
+
import { ResolveResult, VerifyResult, ManifestData, PaginatedResponse } from '@hashproof/shared';
|
|
3
|
+
export { ApiError, ApiKey, ApiScope, Assertion, ComplianceDetail, ComplianceReport, HardBinding, Ingredient, ManifestData, MerkleAnchor, MerkleProof, PaginatedResponse, ResolveMatch, ResolveResult, SignatureInfo, SoftBinding, SoftBindingAlgorithm, SubscriptionTier, UsageSummary, ValidationError, ValidationResult, ValidationStatus, VerifyResult } from '@hashproof/shared';
|
|
4
|
+
|
|
5
|
+
/** Options for constructing the HashproofClient. */
|
|
6
|
+
interface HashproofClientOptions {
|
|
7
|
+
/** Your Hashproof API key (starts with hpsk_). */
|
|
8
|
+
apiKey: string;
|
|
9
|
+
/** Base URL for the API. Defaults to https://api.hashproof.ai. */
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
/** Request timeout in milliseconds. Defaults to 30000. */
|
|
12
|
+
timeout?: number;
|
|
13
|
+
}
|
|
14
|
+
/** Result returned from the store() method. */
|
|
15
|
+
interface StoreResult {
|
|
16
|
+
manifestId: string;
|
|
17
|
+
manifest: _hashproof_shared.ManifestData;
|
|
18
|
+
softBindings: Array<{
|
|
19
|
+
algorithm: string;
|
|
20
|
+
value: string;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
/** Result returned from the sign() method. */
|
|
24
|
+
interface SignResult {
|
|
25
|
+
manifestId: string;
|
|
26
|
+
manifest: _hashproof_shared.ManifestData;
|
|
27
|
+
signedAssetUrl: string | null;
|
|
28
|
+
message: string;
|
|
29
|
+
}
|
|
30
|
+
/** Result returned from the computeFingerprint() method. */
|
|
31
|
+
interface FingerprintResult {
|
|
32
|
+
fingerprint: string;
|
|
33
|
+
algorithm: _hashproof_shared.SoftBindingAlgorithm;
|
|
34
|
+
bitLength: number;
|
|
35
|
+
}
|
|
36
|
+
/** Error thrown by the SDK for API error responses. */
|
|
37
|
+
declare class HashproofApiError extends Error {
|
|
38
|
+
/** HTTP status code. */
|
|
39
|
+
readonly statusCode: number;
|
|
40
|
+
/** Machine-readable error code. */
|
|
41
|
+
readonly code: string;
|
|
42
|
+
/** Additional error details. */
|
|
43
|
+
readonly details?: Record<string, unknown>;
|
|
44
|
+
constructor(message: string, statusCode: number, code: string, details?: Record<string, unknown>);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Official JavaScript/TypeScript client for the Hashproof Content Provenance API.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { HashproofClient } from '@hashproof/sdk';
|
|
53
|
+
*
|
|
54
|
+
* const client = new HashproofClient({ apiKey: 'hpsk_...' });
|
|
55
|
+
* const result = await client.verify(fileBuffer);
|
|
56
|
+
* console.log(result.hasProvenance);
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
declare class HashproofClient {
|
|
60
|
+
private readonly apiKey;
|
|
61
|
+
private readonly baseUrl;
|
|
62
|
+
private readonly timeout;
|
|
63
|
+
/**
|
|
64
|
+
* Create a new HashproofClient instance.
|
|
65
|
+
*
|
|
66
|
+
* @param options - Client configuration options.
|
|
67
|
+
* @param options.apiKey - Your Hashproof API key (starts with `hpsk_`).
|
|
68
|
+
* @param options.baseUrl - Base URL for the API. Defaults to `https://api.hashproof.ai`.
|
|
69
|
+
* @param options.timeout - Request timeout in milliseconds. Defaults to 30000.
|
|
70
|
+
* @throws {Error} If no API key is provided.
|
|
71
|
+
*/
|
|
72
|
+
constructor(options: HashproofClientOptions);
|
|
73
|
+
/**
|
|
74
|
+
* Store a C2PA manifest by uploading a digital asset.
|
|
75
|
+
*
|
|
76
|
+
* The API extracts the embedded C2PA manifest from the file,
|
|
77
|
+
* computes perceptual fingerprints (soft bindings), and stores
|
|
78
|
+
* everything for future resolution and verification.
|
|
79
|
+
*
|
|
80
|
+
* @param file - The file to store as a Buffer or Blob.
|
|
81
|
+
* @param options - Optional parameters.
|
|
82
|
+
* @param options.title - A human-readable title for the asset.
|
|
83
|
+
* @returns The stored manifest data along with computed soft bindings.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* const result = await client.store(fileBuffer, { title: 'My Photo' });
|
|
88
|
+
* console.log(result.manifestId);
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
store(file: Buffer | Blob, options?: {
|
|
92
|
+
title?: string;
|
|
93
|
+
}): Promise<StoreResult>;
|
|
94
|
+
/**
|
|
95
|
+
* Resolve provenance for a file or fingerprint.
|
|
96
|
+
*
|
|
97
|
+
* When called with a Buffer/Blob, the file is uploaded and a perceptual
|
|
98
|
+
* fingerprint is computed server-side, then matched against the manifest
|
|
99
|
+
* repository.
|
|
100
|
+
*
|
|
101
|
+
* When called with a fingerprint string, a lightweight lookup is performed
|
|
102
|
+
* without any file upload.
|
|
103
|
+
*
|
|
104
|
+
* @param fileOrFingerprint - A file (Buffer/Blob) or a hex fingerprint string.
|
|
105
|
+
* @param algorithm - The soft binding algorithm to use (default: `phash-dct-64`).
|
|
106
|
+
* @returns Matching manifests sorted by similarity.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* // Resolve by file upload
|
|
111
|
+
* const result = await client.resolve(imageBuffer);
|
|
112
|
+
*
|
|
113
|
+
* // Resolve by pre-computed fingerprint
|
|
114
|
+
* const result = await client.resolve('a1b2c3d4e5f6...', 'phash-dct-64');
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
resolve(file: Buffer | Blob): Promise<ResolveResult>;
|
|
118
|
+
resolve(fingerprint: string, algorithm?: string): Promise<ResolveResult>;
|
|
119
|
+
/**
|
|
120
|
+
* Verify the provenance of a digital asset.
|
|
121
|
+
*
|
|
122
|
+
* This is the main one-call verification endpoint. It checks:
|
|
123
|
+
* 1. Embedded C2PA manifests in the file
|
|
124
|
+
* 2. Hard binding (SHA-256 hash match) against stored manifests
|
|
125
|
+
* 3. Soft binding (perceptual hash) resolution
|
|
126
|
+
*
|
|
127
|
+
* @param file - The file to verify as a Buffer or Blob.
|
|
128
|
+
* @returns Verification result including provenance source, manifest data, and trust status.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* const result = await client.verify(imageBuffer);
|
|
133
|
+
* if (result.hasProvenance) {
|
|
134
|
+
* console.log(`Source: ${result.source}, Trust: ${result.trustStatus}`);
|
|
135
|
+
* }
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
verify(file: Buffer | Blob): Promise<VerifyResult>;
|
|
139
|
+
/**
|
|
140
|
+
* Retrieve a manifest by its ID.
|
|
141
|
+
*
|
|
142
|
+
* @param id - The manifest UUID.
|
|
143
|
+
* @returns The full manifest data.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* const manifest = await client.getManifest('550e8400-e29b-41d4-a716-446655440000');
|
|
148
|
+
* console.log(manifest.title, manifest.validationStatus);
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
getManifest(id: string): Promise<ManifestData>;
|
|
152
|
+
/**
|
|
153
|
+
* Retrieve a manifest by its hard binding hash (SHA-256).
|
|
154
|
+
*
|
|
155
|
+
* @param hash - The SHA-256 hash of the original asset.
|
|
156
|
+
* @returns The matching manifest data.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* const manifest = await client.getManifestByHash('e3b0c44298fc1c149afbf4c8996fb924...');
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
getManifestByHash(hash: string): Promise<ManifestData>;
|
|
164
|
+
/**
|
|
165
|
+
* List manifests with optional pagination and search.
|
|
166
|
+
*
|
|
167
|
+
* @param options - Pagination and search options.
|
|
168
|
+
* @param options.page - Page number (1-indexed). Defaults to 1.
|
|
169
|
+
* @param options.perPage - Results per page. Defaults to 20.
|
|
170
|
+
* @param options.search - Search term to filter manifests by title.
|
|
171
|
+
* @returns A paginated list of manifests.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* const page = await client.listManifests({ page: 1, search: 'photo' });
|
|
176
|
+
* console.log(`${page.total} manifests found`);
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
listManifests(options?: {
|
|
180
|
+
page?: number;
|
|
181
|
+
perPage?: number;
|
|
182
|
+
search?: string;
|
|
183
|
+
}): Promise<PaginatedResponse<ManifestData>>;
|
|
184
|
+
/**
|
|
185
|
+
* Sign a digital asset with a C2PA manifest using Hashproof's managed signing.
|
|
186
|
+
*
|
|
187
|
+
* This is the "Let's Encrypt for C2PA" endpoint -- you upload a file and
|
|
188
|
+
* Hashproof creates a signed C2PA manifest on your behalf, without you
|
|
189
|
+
* needing to manage certificates or PKI.
|
|
190
|
+
*
|
|
191
|
+
* Requires the `sign` scope on your API key.
|
|
192
|
+
*
|
|
193
|
+
* @param file - The file to sign as a Buffer or Blob.
|
|
194
|
+
* @param options - Optional parameters.
|
|
195
|
+
* @param options.title - A human-readable title for the asset.
|
|
196
|
+
* @returns The signing result including the new manifest ID.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* const result = await client.sign(imageBuffer, { title: 'Press Photo 2024' });
|
|
201
|
+
* console.log(result.manifestId);
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
sign(file: Buffer | Blob, options?: {
|
|
205
|
+
title?: string;
|
|
206
|
+
}): Promise<SignResult>;
|
|
207
|
+
/**
|
|
208
|
+
* Compute a perceptual fingerprint for a file without resolving.
|
|
209
|
+
*
|
|
210
|
+
* Useful when you want to compute and store a fingerprint client-side
|
|
211
|
+
* for later resolution via `resolve(fingerprint, algorithm)`.
|
|
212
|
+
*
|
|
213
|
+
* @param file - The file to fingerprint as a Buffer or Blob.
|
|
214
|
+
* @param algorithm - The algorithm to use. Defaults to `phash-dct-64`.
|
|
215
|
+
* @returns The computed fingerprint, algorithm, and bit length.
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```ts
|
|
219
|
+
* const fp = await client.computeFingerprint(imageBuffer, 'phash-dct-64');
|
|
220
|
+
* console.log(fp.fingerprint); // hex string
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
computeFingerprint(file: Buffer | Blob, algorithm?: string): Promise<FingerprintResult>;
|
|
224
|
+
/**
|
|
225
|
+
* Make an authenticated HTTP request to the Hashproof API.
|
|
226
|
+
* @internal
|
|
227
|
+
*/
|
|
228
|
+
private request;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export { type FingerprintResult, HashproofApiError, HashproofClient, type HashproofClientOptions, type SignResult, type StoreResult };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import * as _hashproof_shared from '@hashproof/shared';
|
|
2
|
+
import { ResolveResult, VerifyResult, ManifestData, PaginatedResponse } from '@hashproof/shared';
|
|
3
|
+
export { ApiError, ApiKey, ApiScope, Assertion, ComplianceDetail, ComplianceReport, HardBinding, Ingredient, ManifestData, MerkleAnchor, MerkleProof, PaginatedResponse, ResolveMatch, ResolveResult, SignatureInfo, SoftBinding, SoftBindingAlgorithm, SubscriptionTier, UsageSummary, ValidationError, ValidationResult, ValidationStatus, VerifyResult } from '@hashproof/shared';
|
|
4
|
+
|
|
5
|
+
/** Options for constructing the HashproofClient. */
|
|
6
|
+
interface HashproofClientOptions {
|
|
7
|
+
/** Your Hashproof API key (starts with hpsk_). */
|
|
8
|
+
apiKey: string;
|
|
9
|
+
/** Base URL for the API. Defaults to https://api.hashproof.ai. */
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
/** Request timeout in milliseconds. Defaults to 30000. */
|
|
12
|
+
timeout?: number;
|
|
13
|
+
}
|
|
14
|
+
/** Result returned from the store() method. */
|
|
15
|
+
interface StoreResult {
|
|
16
|
+
manifestId: string;
|
|
17
|
+
manifest: _hashproof_shared.ManifestData;
|
|
18
|
+
softBindings: Array<{
|
|
19
|
+
algorithm: string;
|
|
20
|
+
value: string;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
/** Result returned from the sign() method. */
|
|
24
|
+
interface SignResult {
|
|
25
|
+
manifestId: string;
|
|
26
|
+
manifest: _hashproof_shared.ManifestData;
|
|
27
|
+
signedAssetUrl: string | null;
|
|
28
|
+
message: string;
|
|
29
|
+
}
|
|
30
|
+
/** Result returned from the computeFingerprint() method. */
|
|
31
|
+
interface FingerprintResult {
|
|
32
|
+
fingerprint: string;
|
|
33
|
+
algorithm: _hashproof_shared.SoftBindingAlgorithm;
|
|
34
|
+
bitLength: number;
|
|
35
|
+
}
|
|
36
|
+
/** Error thrown by the SDK for API error responses. */
|
|
37
|
+
declare class HashproofApiError extends Error {
|
|
38
|
+
/** HTTP status code. */
|
|
39
|
+
readonly statusCode: number;
|
|
40
|
+
/** Machine-readable error code. */
|
|
41
|
+
readonly code: string;
|
|
42
|
+
/** Additional error details. */
|
|
43
|
+
readonly details?: Record<string, unknown>;
|
|
44
|
+
constructor(message: string, statusCode: number, code: string, details?: Record<string, unknown>);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Official JavaScript/TypeScript client for the Hashproof Content Provenance API.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { HashproofClient } from '@hashproof/sdk';
|
|
53
|
+
*
|
|
54
|
+
* const client = new HashproofClient({ apiKey: 'hpsk_...' });
|
|
55
|
+
* const result = await client.verify(fileBuffer);
|
|
56
|
+
* console.log(result.hasProvenance);
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
declare class HashproofClient {
|
|
60
|
+
private readonly apiKey;
|
|
61
|
+
private readonly baseUrl;
|
|
62
|
+
private readonly timeout;
|
|
63
|
+
/**
|
|
64
|
+
* Create a new HashproofClient instance.
|
|
65
|
+
*
|
|
66
|
+
* @param options - Client configuration options.
|
|
67
|
+
* @param options.apiKey - Your Hashproof API key (starts with `hpsk_`).
|
|
68
|
+
* @param options.baseUrl - Base URL for the API. Defaults to `https://api.hashproof.ai`.
|
|
69
|
+
* @param options.timeout - Request timeout in milliseconds. Defaults to 30000.
|
|
70
|
+
* @throws {Error} If no API key is provided.
|
|
71
|
+
*/
|
|
72
|
+
constructor(options: HashproofClientOptions);
|
|
73
|
+
/**
|
|
74
|
+
* Store a C2PA manifest by uploading a digital asset.
|
|
75
|
+
*
|
|
76
|
+
* The API extracts the embedded C2PA manifest from the file,
|
|
77
|
+
* computes perceptual fingerprints (soft bindings), and stores
|
|
78
|
+
* everything for future resolution and verification.
|
|
79
|
+
*
|
|
80
|
+
* @param file - The file to store as a Buffer or Blob.
|
|
81
|
+
* @param options - Optional parameters.
|
|
82
|
+
* @param options.title - A human-readable title for the asset.
|
|
83
|
+
* @returns The stored manifest data along with computed soft bindings.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* const result = await client.store(fileBuffer, { title: 'My Photo' });
|
|
88
|
+
* console.log(result.manifestId);
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
store(file: Buffer | Blob, options?: {
|
|
92
|
+
title?: string;
|
|
93
|
+
}): Promise<StoreResult>;
|
|
94
|
+
/**
|
|
95
|
+
* Resolve provenance for a file or fingerprint.
|
|
96
|
+
*
|
|
97
|
+
* When called with a Buffer/Blob, the file is uploaded and a perceptual
|
|
98
|
+
* fingerprint is computed server-side, then matched against the manifest
|
|
99
|
+
* repository.
|
|
100
|
+
*
|
|
101
|
+
* When called with a fingerprint string, a lightweight lookup is performed
|
|
102
|
+
* without any file upload.
|
|
103
|
+
*
|
|
104
|
+
* @param fileOrFingerprint - A file (Buffer/Blob) or a hex fingerprint string.
|
|
105
|
+
* @param algorithm - The soft binding algorithm to use (default: `phash-dct-64`).
|
|
106
|
+
* @returns Matching manifests sorted by similarity.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* // Resolve by file upload
|
|
111
|
+
* const result = await client.resolve(imageBuffer);
|
|
112
|
+
*
|
|
113
|
+
* // Resolve by pre-computed fingerprint
|
|
114
|
+
* const result = await client.resolve('a1b2c3d4e5f6...', 'phash-dct-64');
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
resolve(file: Buffer | Blob): Promise<ResolveResult>;
|
|
118
|
+
resolve(fingerprint: string, algorithm?: string): Promise<ResolveResult>;
|
|
119
|
+
/**
|
|
120
|
+
* Verify the provenance of a digital asset.
|
|
121
|
+
*
|
|
122
|
+
* This is the main one-call verification endpoint. It checks:
|
|
123
|
+
* 1. Embedded C2PA manifests in the file
|
|
124
|
+
* 2. Hard binding (SHA-256 hash match) against stored manifests
|
|
125
|
+
* 3. Soft binding (perceptual hash) resolution
|
|
126
|
+
*
|
|
127
|
+
* @param file - The file to verify as a Buffer or Blob.
|
|
128
|
+
* @returns Verification result including provenance source, manifest data, and trust status.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* const result = await client.verify(imageBuffer);
|
|
133
|
+
* if (result.hasProvenance) {
|
|
134
|
+
* console.log(`Source: ${result.source}, Trust: ${result.trustStatus}`);
|
|
135
|
+
* }
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
verify(file: Buffer | Blob): Promise<VerifyResult>;
|
|
139
|
+
/**
|
|
140
|
+
* Retrieve a manifest by its ID.
|
|
141
|
+
*
|
|
142
|
+
* @param id - The manifest UUID.
|
|
143
|
+
* @returns The full manifest data.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* const manifest = await client.getManifest('550e8400-e29b-41d4-a716-446655440000');
|
|
148
|
+
* console.log(manifest.title, manifest.validationStatus);
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
getManifest(id: string): Promise<ManifestData>;
|
|
152
|
+
/**
|
|
153
|
+
* Retrieve a manifest by its hard binding hash (SHA-256).
|
|
154
|
+
*
|
|
155
|
+
* @param hash - The SHA-256 hash of the original asset.
|
|
156
|
+
* @returns The matching manifest data.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* const manifest = await client.getManifestByHash('e3b0c44298fc1c149afbf4c8996fb924...');
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
getManifestByHash(hash: string): Promise<ManifestData>;
|
|
164
|
+
/**
|
|
165
|
+
* List manifests with optional pagination and search.
|
|
166
|
+
*
|
|
167
|
+
* @param options - Pagination and search options.
|
|
168
|
+
* @param options.page - Page number (1-indexed). Defaults to 1.
|
|
169
|
+
* @param options.perPage - Results per page. Defaults to 20.
|
|
170
|
+
* @param options.search - Search term to filter manifests by title.
|
|
171
|
+
* @returns A paginated list of manifests.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* const page = await client.listManifests({ page: 1, search: 'photo' });
|
|
176
|
+
* console.log(`${page.total} manifests found`);
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
listManifests(options?: {
|
|
180
|
+
page?: number;
|
|
181
|
+
perPage?: number;
|
|
182
|
+
search?: string;
|
|
183
|
+
}): Promise<PaginatedResponse<ManifestData>>;
|
|
184
|
+
/**
|
|
185
|
+
* Sign a digital asset with a C2PA manifest using Hashproof's managed signing.
|
|
186
|
+
*
|
|
187
|
+
* This is the "Let's Encrypt for C2PA" endpoint -- you upload a file and
|
|
188
|
+
* Hashproof creates a signed C2PA manifest on your behalf, without you
|
|
189
|
+
* needing to manage certificates or PKI.
|
|
190
|
+
*
|
|
191
|
+
* Requires the `sign` scope on your API key.
|
|
192
|
+
*
|
|
193
|
+
* @param file - The file to sign as a Buffer or Blob.
|
|
194
|
+
* @param options - Optional parameters.
|
|
195
|
+
* @param options.title - A human-readable title for the asset.
|
|
196
|
+
* @returns The signing result including the new manifest ID.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* const result = await client.sign(imageBuffer, { title: 'Press Photo 2024' });
|
|
201
|
+
* console.log(result.manifestId);
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
sign(file: Buffer | Blob, options?: {
|
|
205
|
+
title?: string;
|
|
206
|
+
}): Promise<SignResult>;
|
|
207
|
+
/**
|
|
208
|
+
* Compute a perceptual fingerprint for a file without resolving.
|
|
209
|
+
*
|
|
210
|
+
* Useful when you want to compute and store a fingerprint client-side
|
|
211
|
+
* for later resolution via `resolve(fingerprint, algorithm)`.
|
|
212
|
+
*
|
|
213
|
+
* @param file - The file to fingerprint as a Buffer or Blob.
|
|
214
|
+
* @param algorithm - The algorithm to use. Defaults to `phash-dct-64`.
|
|
215
|
+
* @returns The computed fingerprint, algorithm, and bit length.
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```ts
|
|
219
|
+
* const fp = await client.computeFingerprint(imageBuffer, 'phash-dct-64');
|
|
220
|
+
* console.log(fp.fingerprint); // hex string
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
computeFingerprint(file: Buffer | Blob, algorithm?: string): Promise<FingerprintResult>;
|
|
224
|
+
/**
|
|
225
|
+
* Make an authenticated HTTP request to the Hashproof API.
|
|
226
|
+
* @internal
|
|
227
|
+
*/
|
|
228
|
+
private request;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export { type FingerprintResult, HashproofApiError, HashproofClient, type HashproofClientOptions, type SignResult, type StoreResult };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var HashproofApiError = class extends Error {
|
|
3
|
+
/** HTTP status code. */
|
|
4
|
+
statusCode;
|
|
5
|
+
/** Machine-readable error code. */
|
|
6
|
+
code;
|
|
7
|
+
/** Additional error details. */
|
|
8
|
+
details;
|
|
9
|
+
constructor(message, statusCode, code, details) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "HashproofApiError";
|
|
12
|
+
this.statusCode = statusCode;
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.details = details;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// src/index.ts
|
|
19
|
+
var DEFAULT_BASE_URL = "https://api.hashproof.ai";
|
|
20
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
21
|
+
var HashproofClient = class {
|
|
22
|
+
apiKey;
|
|
23
|
+
baseUrl;
|
|
24
|
+
timeout;
|
|
25
|
+
/**
|
|
26
|
+
* Create a new HashproofClient instance.
|
|
27
|
+
*
|
|
28
|
+
* @param options - Client configuration options.
|
|
29
|
+
* @param options.apiKey - Your Hashproof API key (starts with `hpsk_`).
|
|
30
|
+
* @param options.baseUrl - Base URL for the API. Defaults to `https://api.hashproof.ai`.
|
|
31
|
+
* @param options.timeout - Request timeout in milliseconds. Defaults to 30000.
|
|
32
|
+
* @throws {Error} If no API key is provided.
|
|
33
|
+
*/
|
|
34
|
+
constructor(options) {
|
|
35
|
+
if (!options.apiKey) {
|
|
36
|
+
throw new Error('Hashproof API key is required. Pass { apiKey: "hpsk_..." } to the constructor.');
|
|
37
|
+
}
|
|
38
|
+
this.apiKey = options.apiKey;
|
|
39
|
+
this.baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
40
|
+
this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
41
|
+
}
|
|
42
|
+
// ============================================================
|
|
43
|
+
// Manifest Operations
|
|
44
|
+
// ============================================================
|
|
45
|
+
/**
|
|
46
|
+
* Store a C2PA manifest by uploading a digital asset.
|
|
47
|
+
*
|
|
48
|
+
* The API extracts the embedded C2PA manifest from the file,
|
|
49
|
+
* computes perceptual fingerprints (soft bindings), and stores
|
|
50
|
+
* everything for future resolution and verification.
|
|
51
|
+
*
|
|
52
|
+
* @param file - The file to store as a Buffer or Blob.
|
|
53
|
+
* @param options - Optional parameters.
|
|
54
|
+
* @param options.title - A human-readable title for the asset.
|
|
55
|
+
* @returns The stored manifest data along with computed soft bindings.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const result = await client.store(fileBuffer, { title: 'My Photo' });
|
|
60
|
+
* console.log(result.manifestId);
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
async store(file, options) {
|
|
64
|
+
const formData = new FormData();
|
|
65
|
+
const blob = file instanceof Blob ? file : new Blob([file]);
|
|
66
|
+
formData.append("file", blob, "upload");
|
|
67
|
+
if (options?.title) {
|
|
68
|
+
formData.append("title", options.title);
|
|
69
|
+
}
|
|
70
|
+
return this.request("POST", "/v1/manifests", formData);
|
|
71
|
+
}
|
|
72
|
+
async resolve(fileOrFingerprint, algorithm) {
|
|
73
|
+
if (typeof fileOrFingerprint === "string") {
|
|
74
|
+
const params = new URLSearchParams({ fingerprint: fileOrFingerprint });
|
|
75
|
+
if (algorithm) params.set("algorithm", algorithm);
|
|
76
|
+
return this.request("GET", `/v1/resolve?${params.toString()}`);
|
|
77
|
+
}
|
|
78
|
+
const formData = new FormData();
|
|
79
|
+
const blob = fileOrFingerprint instanceof Blob ? fileOrFingerprint : new Blob([fileOrFingerprint]);
|
|
80
|
+
formData.append("file", blob, "upload");
|
|
81
|
+
if (algorithm) {
|
|
82
|
+
formData.append("algorithm", algorithm);
|
|
83
|
+
}
|
|
84
|
+
return this.request("POST", "/v1/resolve", formData);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Verify the provenance of a digital asset.
|
|
88
|
+
*
|
|
89
|
+
* This is the main one-call verification endpoint. It checks:
|
|
90
|
+
* 1. Embedded C2PA manifests in the file
|
|
91
|
+
* 2. Hard binding (SHA-256 hash match) against stored manifests
|
|
92
|
+
* 3. Soft binding (perceptual hash) resolution
|
|
93
|
+
*
|
|
94
|
+
* @param file - The file to verify as a Buffer or Blob.
|
|
95
|
+
* @returns Verification result including provenance source, manifest data, and trust status.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* const result = await client.verify(imageBuffer);
|
|
100
|
+
* if (result.hasProvenance) {
|
|
101
|
+
* console.log(`Source: ${result.source}, Trust: ${result.trustStatus}`);
|
|
102
|
+
* }
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
async verify(file) {
|
|
106
|
+
const formData = new FormData();
|
|
107
|
+
const blob = file instanceof Blob ? file : new Blob([file]);
|
|
108
|
+
formData.append("file", blob, "upload");
|
|
109
|
+
return this.request("POST", "/v1/verify", formData);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Retrieve a manifest by its ID.
|
|
113
|
+
*
|
|
114
|
+
* @param id - The manifest UUID.
|
|
115
|
+
* @returns The full manifest data.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* const manifest = await client.getManifest('550e8400-e29b-41d4-a716-446655440000');
|
|
120
|
+
* console.log(manifest.title, manifest.validationStatus);
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
async getManifest(id) {
|
|
124
|
+
return this.request("GET", `/v1/manifests/${encodeURIComponent(id)}`);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Retrieve a manifest by its hard binding hash (SHA-256).
|
|
128
|
+
*
|
|
129
|
+
* @param hash - The SHA-256 hash of the original asset.
|
|
130
|
+
* @returns The matching manifest data.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```ts
|
|
134
|
+
* const manifest = await client.getManifestByHash('e3b0c44298fc1c149afbf4c8996fb924...');
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
async getManifestByHash(hash) {
|
|
138
|
+
const params = new URLSearchParams({ hash });
|
|
139
|
+
return this.request("GET", `/v1/manifests?${params.toString()}`);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* List manifests with optional pagination and search.
|
|
143
|
+
*
|
|
144
|
+
* @param options - Pagination and search options.
|
|
145
|
+
* @param options.page - Page number (1-indexed). Defaults to 1.
|
|
146
|
+
* @param options.perPage - Results per page. Defaults to 20.
|
|
147
|
+
* @param options.search - Search term to filter manifests by title.
|
|
148
|
+
* @returns A paginated list of manifests.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* const page = await client.listManifests({ page: 1, search: 'photo' });
|
|
153
|
+
* console.log(`${page.total} manifests found`);
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
async listManifests(options) {
|
|
157
|
+
const params = new URLSearchParams();
|
|
158
|
+
if (options?.page) params.set("page", String(options.page));
|
|
159
|
+
if (options?.perPage) params.set("perPage", String(options.perPage));
|
|
160
|
+
if (options?.search) params.set("search", options.search);
|
|
161
|
+
const query = params.toString();
|
|
162
|
+
return this.request(
|
|
163
|
+
"GET",
|
|
164
|
+
`/v1/manifests${query ? `?${query}` : ""}`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
// ============================================================
|
|
168
|
+
// Signing
|
|
169
|
+
// ============================================================
|
|
170
|
+
/**
|
|
171
|
+
* Sign a digital asset with a C2PA manifest using Hashproof's managed signing.
|
|
172
|
+
*
|
|
173
|
+
* This is the "Let's Encrypt for C2PA" endpoint -- you upload a file and
|
|
174
|
+
* Hashproof creates a signed C2PA manifest on your behalf, without you
|
|
175
|
+
* needing to manage certificates or PKI.
|
|
176
|
+
*
|
|
177
|
+
* Requires the `sign` scope on your API key.
|
|
178
|
+
*
|
|
179
|
+
* @param file - The file to sign as a Buffer or Blob.
|
|
180
|
+
* @param options - Optional parameters.
|
|
181
|
+
* @param options.title - A human-readable title for the asset.
|
|
182
|
+
* @returns The signing result including the new manifest ID.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```ts
|
|
186
|
+
* const result = await client.sign(imageBuffer, { title: 'Press Photo 2024' });
|
|
187
|
+
* console.log(result.manifestId);
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
async sign(file, options) {
|
|
191
|
+
const formData = new FormData();
|
|
192
|
+
const blob = file instanceof Blob ? file : new Blob([file]);
|
|
193
|
+
formData.append("file", blob, "upload");
|
|
194
|
+
if (options?.title) {
|
|
195
|
+
formData.append("title", options.title);
|
|
196
|
+
}
|
|
197
|
+
return this.request("POST", "/v1/sign", formData);
|
|
198
|
+
}
|
|
199
|
+
// ============================================================
|
|
200
|
+
// Fingerprinting
|
|
201
|
+
// ============================================================
|
|
202
|
+
/**
|
|
203
|
+
* Compute a perceptual fingerprint for a file without resolving.
|
|
204
|
+
*
|
|
205
|
+
* Useful when you want to compute and store a fingerprint client-side
|
|
206
|
+
* for later resolution via `resolve(fingerprint, algorithm)`.
|
|
207
|
+
*
|
|
208
|
+
* @param file - The file to fingerprint as a Buffer or Blob.
|
|
209
|
+
* @param algorithm - The algorithm to use. Defaults to `phash-dct-64`.
|
|
210
|
+
* @returns The computed fingerprint, algorithm, and bit length.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```ts
|
|
214
|
+
* const fp = await client.computeFingerprint(imageBuffer, 'phash-dct-64');
|
|
215
|
+
* console.log(fp.fingerprint); // hex string
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
async computeFingerprint(file, algorithm) {
|
|
219
|
+
const formData = new FormData();
|
|
220
|
+
const blob = file instanceof Blob ? file : new Blob([file]);
|
|
221
|
+
formData.append("file", blob, "upload");
|
|
222
|
+
if (algorithm) {
|
|
223
|
+
formData.append("algorithm", algorithm);
|
|
224
|
+
}
|
|
225
|
+
return this.request("POST", "/v1/fingerprint", formData);
|
|
226
|
+
}
|
|
227
|
+
// ============================================================
|
|
228
|
+
// Internal HTTP Client
|
|
229
|
+
// ============================================================
|
|
230
|
+
/**
|
|
231
|
+
* Make an authenticated HTTP request to the Hashproof API.
|
|
232
|
+
* @internal
|
|
233
|
+
*/
|
|
234
|
+
async request(method, path, body) {
|
|
235
|
+
const url = `${this.baseUrl}${path}`;
|
|
236
|
+
const headers = {
|
|
237
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
238
|
+
Accept: "application/json"
|
|
239
|
+
};
|
|
240
|
+
let requestBody;
|
|
241
|
+
if (body instanceof FormData) {
|
|
242
|
+
requestBody = body;
|
|
243
|
+
} else if (body) {
|
|
244
|
+
headers["Content-Type"] = "application/json";
|
|
245
|
+
requestBody = JSON.stringify(body);
|
|
246
|
+
}
|
|
247
|
+
const controller = new AbortController();
|
|
248
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
249
|
+
let response;
|
|
250
|
+
try {
|
|
251
|
+
response = await fetch(url, {
|
|
252
|
+
method,
|
|
253
|
+
headers,
|
|
254
|
+
body: requestBody,
|
|
255
|
+
signal: controller.signal
|
|
256
|
+
});
|
|
257
|
+
} catch (err) {
|
|
258
|
+
clearTimeout(timeoutId);
|
|
259
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
260
|
+
throw new HashproofApiError(
|
|
261
|
+
`Request timed out after ${this.timeout}ms`,
|
|
262
|
+
0,
|
|
263
|
+
"TIMEOUT"
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
throw new HashproofApiError(
|
|
267
|
+
`Network error: ${err instanceof Error ? err.message : String(err)}`,
|
|
268
|
+
0,
|
|
269
|
+
"NETWORK_ERROR"
|
|
270
|
+
);
|
|
271
|
+
} finally {
|
|
272
|
+
clearTimeout(timeoutId);
|
|
273
|
+
}
|
|
274
|
+
const responseBody = await response.text();
|
|
275
|
+
let parsed;
|
|
276
|
+
try {
|
|
277
|
+
parsed = JSON.parse(responseBody);
|
|
278
|
+
} catch {
|
|
279
|
+
if (!response.ok) {
|
|
280
|
+
throw new HashproofApiError(
|
|
281
|
+
`HTTP ${response.status}: ${responseBody.slice(0, 200)}`,
|
|
282
|
+
response.status,
|
|
283
|
+
"UNEXPECTED_RESPONSE"
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
throw new HashproofApiError(
|
|
287
|
+
"Failed to parse API response as JSON",
|
|
288
|
+
response.status,
|
|
289
|
+
"PARSE_ERROR"
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
if (!response.ok) {
|
|
293
|
+
const errBody = parsed;
|
|
294
|
+
throw new HashproofApiError(
|
|
295
|
+
errBody.error || `HTTP ${response.status}`,
|
|
296
|
+
errBody.statusCode || response.status,
|
|
297
|
+
errBody.code || "API_ERROR",
|
|
298
|
+
errBody.details
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
return parsed;
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
export {
|
|
305
|
+
HashproofApiError,
|
|
306
|
+
HashproofClient
|
|
307
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hashproof/sdk",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Official JavaScript/TypeScript SDK for the Hashproof Content Provenance API",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@hashproof/shared": "0.1.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"typescript": "^5.4.0",
|
|
29
|
+
"tsup": "^8.0.0",
|
|
30
|
+
"vitest": "^1.3.0",
|
|
31
|
+
"@types/node": "^20.11.0"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"hashproof",
|
|
35
|
+
"c2pa",
|
|
36
|
+
"content-provenance",
|
|
37
|
+
"content-authenticity",
|
|
38
|
+
"sdk"
|
|
39
|
+
],
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/hashproof/hashproof",
|
|
44
|
+
"directory": "packages/sdk-js"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --out-dir dist",
|
|
48
|
+
"build:tsc": "tsc",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"test:watch": "vitest",
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"lint": "eslint src/"
|
|
53
|
+
}
|
|
54
|
+
}
|