notaryos 1.0.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 +127 -0
- package/dist/index.d.mts +237 -0
- package/dist/index.d.ts +237 -0
- package/dist/index.js +307 -0
- package/dist/index.mjs +275 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# NotaryOS SDK for TypeScript
|
|
2
|
+
|
|
3
|
+
Cryptographic receipts for AI agent actions. Issue, verify, and audit agent behavior with Ed25519 signatures.
|
|
4
|
+
|
|
5
|
+
**Zero dependencies.** Uses native `fetch()` and Web Crypto API. Works in Node 18+, Deno, Bun, and modern browsers.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install notaryos
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
### Issue a Receipt (3 lines)
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { NotaryClient } from 'notaryos';
|
|
19
|
+
|
|
20
|
+
const notary = new NotaryClient({ apiKey: 'notary_live_xxx' });
|
|
21
|
+
const receipt = await notary.issue('data_processing', { key: 'value' });
|
|
22
|
+
console.log(receipt.verify_url); // https://api.agenttownsquare.com/v1/notary/r/abc123
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Verify a Receipt (no API key needed)
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { verifyReceipt } from 'notaryos';
|
|
29
|
+
|
|
30
|
+
const isValid = await verifyReceipt(receiptJson);
|
|
31
|
+
// true
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Full Example
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { NotaryClient } from 'notaryos';
|
|
38
|
+
|
|
39
|
+
const notary = new NotaryClient({ apiKey: 'notary_live_xxx' });
|
|
40
|
+
|
|
41
|
+
// Issue a receipt for an agent action
|
|
42
|
+
const receipt = await notary.issue('financial.transfer', {
|
|
43
|
+
from: 'billing-agent',
|
|
44
|
+
to: 'ledger-agent',
|
|
45
|
+
amount: 150.00,
|
|
46
|
+
currency: 'USD',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Verify it
|
|
50
|
+
const result = await notary.verify(receipt);
|
|
51
|
+
console.log(result.valid); // true
|
|
52
|
+
console.log(result.signature_ok); // true
|
|
53
|
+
|
|
54
|
+
// Check service health
|
|
55
|
+
const status = await notary.status();
|
|
56
|
+
console.log(status.status); // "active"
|
|
57
|
+
|
|
58
|
+
// Get public key for offline verification
|
|
59
|
+
const keyInfo = await notary.publicKey();
|
|
60
|
+
console.log(keyInfo.public_key_pem);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API Reference
|
|
64
|
+
|
|
65
|
+
### `NotaryClient`
|
|
66
|
+
|
|
67
|
+
| Method | Auth | Description |
|
|
68
|
+
|--------|------|-------------|
|
|
69
|
+
| `issue(actionType, payload, options?)` | API Key | Issue a signed receipt |
|
|
70
|
+
| `verify(receipt)` | API Key | Verify a receipt |
|
|
71
|
+
| `verifyById(receiptId)` | API Key | Verify by receipt ID |
|
|
72
|
+
| `status()` | API Key | Service health check |
|
|
73
|
+
| `publicKey()` | API Key | Get Ed25519 public key |
|
|
74
|
+
| `me()` | API Key | Authenticated agent info |
|
|
75
|
+
|
|
76
|
+
### `verifyReceipt(receipt, baseUrl?)`
|
|
77
|
+
|
|
78
|
+
Public verification without API key. Returns `boolean`.
|
|
79
|
+
|
|
80
|
+
### `computeHash(payload)`
|
|
81
|
+
|
|
82
|
+
SHA-256 hash matching server-side computation. Returns hex string.
|
|
83
|
+
|
|
84
|
+
## Configuration
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
const notary = new NotaryClient({
|
|
88
|
+
apiKey: 'notary_live_xxx', // Required
|
|
89
|
+
baseUrl: 'https://...', // Default: https://api.agenttownsquare.com
|
|
90
|
+
timeout: 30_000, // Default: 30s
|
|
91
|
+
maxRetries: 2, // Default: 2
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Error Handling
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { NotaryClient, AuthenticationError, RateLimitError, ValidationError } from 'notaryos';
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
const receipt = await notary.issue('action', payload);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
if (err instanceof AuthenticationError) {
|
|
104
|
+
// Invalid API key
|
|
105
|
+
} else if (err instanceof RateLimitError) {
|
|
106
|
+
// Wait err.retryAfter seconds
|
|
107
|
+
} else if (err instanceof ValidationError) {
|
|
108
|
+
// Check err.details
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Get an API Key
|
|
114
|
+
|
|
115
|
+
1. Sign up at [notaryos.org](https://notaryos.org)
|
|
116
|
+
2. Generate an API key from the dashboard
|
|
117
|
+
3. Keys start with `notary_live_` (production) or `notary_test_` (sandbox)
|
|
118
|
+
|
|
119
|
+
## Links
|
|
120
|
+
|
|
121
|
+
- [NotaryOS Documentation](https://notaryos.org/docs)
|
|
122
|
+
- [API Reference](https://api.agenttownsquare.com/v1/notary/status)
|
|
123
|
+
- [Public Verification](https://notaryos.org/verify)
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NotaryOS SDK - Cryptographic receipts for AI agent actions.
|
|
3
|
+
*
|
|
4
|
+
* Issue, verify, and audit agent behavior with Ed25519 signatures.
|
|
5
|
+
* Zero dependencies. Uses native fetch() and Web Crypto API.
|
|
6
|
+
*
|
|
7
|
+
* Quick start:
|
|
8
|
+
*
|
|
9
|
+
* import { NotaryClient } from 'notaryos';
|
|
10
|
+
* const notary = new NotaryClient({ apiKey: 'notary_live_xxx' });
|
|
11
|
+
* const receipt = await notary.issue('my_action', { key: 'value' });
|
|
12
|
+
*
|
|
13
|
+
* Verify without API key:
|
|
14
|
+
*
|
|
15
|
+
* import { verifyReceipt } from 'notaryos';
|
|
16
|
+
* const isValid = await verifyReceipt(receiptJson);
|
|
17
|
+
*
|
|
18
|
+
* @packageDocumentation
|
|
19
|
+
*/
|
|
20
|
+
declare const SDK_VERSION = "1.0.0";
|
|
21
|
+
/** Client configuration options. */
|
|
22
|
+
interface NotaryConfig {
|
|
23
|
+
/** Your Notary API key (notary_live_xxx or notary_test_xxx). */
|
|
24
|
+
apiKey: string;
|
|
25
|
+
/** API base URL (default: https://api.agenttownsquare.com). */
|
|
26
|
+
baseUrl?: string;
|
|
27
|
+
/** Request timeout in milliseconds (default: 30000). */
|
|
28
|
+
timeout?: number;
|
|
29
|
+
/** Max retry attempts on transient failures (default: 2). */
|
|
30
|
+
maxRetries?: number;
|
|
31
|
+
}
|
|
32
|
+
/** A signed Notary receipt. */
|
|
33
|
+
interface Receipt {
|
|
34
|
+
receipt_id: string;
|
|
35
|
+
timestamp: string;
|
|
36
|
+
agent_id: string;
|
|
37
|
+
action_type: string;
|
|
38
|
+
payload_hash: string;
|
|
39
|
+
signature: string;
|
|
40
|
+
signature_type: string;
|
|
41
|
+
key_id: string;
|
|
42
|
+
kid?: string;
|
|
43
|
+
alg?: string;
|
|
44
|
+
schema_version?: string;
|
|
45
|
+
chain_sequence?: number;
|
|
46
|
+
previous_receipt_hash?: string | null;
|
|
47
|
+
receipt_hash?: string;
|
|
48
|
+
verify_url?: string;
|
|
49
|
+
}
|
|
50
|
+
/** Result of receipt verification. */
|
|
51
|
+
interface VerificationResult {
|
|
52
|
+
valid: boolean;
|
|
53
|
+
signature_ok: boolean;
|
|
54
|
+
structure_ok: boolean;
|
|
55
|
+
chain_ok?: boolean | null;
|
|
56
|
+
reason: string;
|
|
57
|
+
details: Record<string, unknown>;
|
|
58
|
+
from_cache?: boolean;
|
|
59
|
+
}
|
|
60
|
+
/** Notary service status. */
|
|
61
|
+
interface ServiceStatus {
|
|
62
|
+
status: string;
|
|
63
|
+
signature_type: string;
|
|
64
|
+
key_id: string;
|
|
65
|
+
has_public_key: boolean;
|
|
66
|
+
capabilities: string[];
|
|
67
|
+
timestamp: string;
|
|
68
|
+
}
|
|
69
|
+
/** Public key for offline verification. */
|
|
70
|
+
interface PublicKeyInfo {
|
|
71
|
+
key_id: string;
|
|
72
|
+
signature_type: string;
|
|
73
|
+
public_key_pem: string;
|
|
74
|
+
verification_note: string;
|
|
75
|
+
}
|
|
76
|
+
/** Result of a receipt lookup by hash. */
|
|
77
|
+
interface LookupResult {
|
|
78
|
+
found: boolean;
|
|
79
|
+
receipt: Receipt | null;
|
|
80
|
+
verification: VerificationResult | null;
|
|
81
|
+
meta: Record<string, unknown> | null;
|
|
82
|
+
}
|
|
83
|
+
/** Authenticated agent information. */
|
|
84
|
+
interface AgentInfo {
|
|
85
|
+
agent_id: string;
|
|
86
|
+
agent_name: string;
|
|
87
|
+
tier: string;
|
|
88
|
+
scopes: string[];
|
|
89
|
+
rate_limit_per_minute: number;
|
|
90
|
+
}
|
|
91
|
+
/** Options for issuing receipts. */
|
|
92
|
+
interface IssueOptions {
|
|
93
|
+
/** Hash of previous receipt for chaining. */
|
|
94
|
+
previousReceiptHash?: string;
|
|
95
|
+
/** Additional metadata. */
|
|
96
|
+
metadata?: Record<string, unknown>;
|
|
97
|
+
}
|
|
98
|
+
/** Base error for all NotaryOS SDK errors. */
|
|
99
|
+
declare class NotaryError extends Error {
|
|
100
|
+
code: string;
|
|
101
|
+
status: number;
|
|
102
|
+
details: Record<string, unknown>;
|
|
103
|
+
constructor(message: string, code?: string, status?: number, details?: Record<string, unknown>);
|
|
104
|
+
}
|
|
105
|
+
/** Invalid or missing API key. */
|
|
106
|
+
declare class AuthenticationError extends NotaryError {
|
|
107
|
+
constructor(message: string, code?: string);
|
|
108
|
+
}
|
|
109
|
+
/** Rate limit exceeded. */
|
|
110
|
+
declare class RateLimitError extends NotaryError {
|
|
111
|
+
retryAfter?: number;
|
|
112
|
+
constructor(message: string, retryAfter?: number);
|
|
113
|
+
}
|
|
114
|
+
/** Request validation failed. */
|
|
115
|
+
declare class ValidationError extends NotaryError {
|
|
116
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* NotaryOS API client.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const notary = new NotaryClient({ apiKey: 'notary_live_xxx' });
|
|
124
|
+
*
|
|
125
|
+
* // Issue a receipt
|
|
126
|
+
* const receipt = await notary.issue('data_processing', { key: 'value' });
|
|
127
|
+
*
|
|
128
|
+
* // Verify a receipt
|
|
129
|
+
* const result = await notary.verify(receipt);
|
|
130
|
+
* console.log(result.valid); // true
|
|
131
|
+
*
|
|
132
|
+
* // Check service health
|
|
133
|
+
* const status = await notary.status();
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
declare class NotaryClient {
|
|
137
|
+
private apiKey;
|
|
138
|
+
private baseUrl;
|
|
139
|
+
private timeout;
|
|
140
|
+
private maxRetries;
|
|
141
|
+
static readonly DEFAULT_BASE_URL = "https://api.agenttownsquare.com";
|
|
142
|
+
static readonly DEFAULT_TIMEOUT = 30000;
|
|
143
|
+
constructor(config: NotaryConfig);
|
|
144
|
+
private request;
|
|
145
|
+
private sleep;
|
|
146
|
+
/**
|
|
147
|
+
* Issue a signed receipt for an action.
|
|
148
|
+
*
|
|
149
|
+
* @param actionType - Type of action (e.g., "data_processing", "api_call")
|
|
150
|
+
* @param payload - Action payload to be receipted
|
|
151
|
+
* @param options - Optional chaining and metadata
|
|
152
|
+
* @returns A signed Receipt
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const receipt = await notary.issue('transfer', { amount: 100, to: 'agent-b' });
|
|
157
|
+
* console.log(receipt.receipt_id);
|
|
158
|
+
* console.log(receipt.verify_url); // https://...notary/r/abc123
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
issue(actionType: string, payload: Record<string, unknown>, options?: IssueOptions): Promise<Receipt>;
|
|
162
|
+
/**
|
|
163
|
+
* Verify a receipt's signature and integrity.
|
|
164
|
+
*
|
|
165
|
+
* @param receipt - Receipt object or raw receipt dict
|
|
166
|
+
* @returns VerificationResult with validity details
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```typescript
|
|
170
|
+
* const result = await notary.verify(receipt);
|
|
171
|
+
* if (result.valid) {
|
|
172
|
+
* console.log('Receipt is authentic');
|
|
173
|
+
* }
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
verify(receipt: Receipt | Record<string, unknown>): Promise<VerificationResult>;
|
|
177
|
+
/** Verify a receipt by its ID (server-side lookup). */
|
|
178
|
+
verifyById(receiptId: string): Promise<VerificationResult>;
|
|
179
|
+
/**
|
|
180
|
+
* Get Notary service status.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const status = await notary.status();
|
|
185
|
+
* console.log(status.status); // "active"
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
status(): Promise<ServiceStatus>;
|
|
189
|
+
/** Get the public key for offline verification. */
|
|
190
|
+
publicKey(): Promise<PublicKeyInfo>;
|
|
191
|
+
/** Get authenticated agent info. */
|
|
192
|
+
me(): Promise<AgentInfo>;
|
|
193
|
+
/**
|
|
194
|
+
* Look up a receipt by hash (public endpoint, no API key required for lookup).
|
|
195
|
+
*
|
|
196
|
+
* @param receiptHash - Full or partial receipt hash (min 16 chars)
|
|
197
|
+
* @returns Lookup result with receipt, verification, and meta
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* const result = await notary.lookup('abc123def456...');
|
|
202
|
+
* if (result.found && result.verification?.valid) {
|
|
203
|
+
* console.log('Receipt is valid!');
|
|
204
|
+
* }
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
lookup(receiptHash: string): Promise<LookupResult>;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Quick receipt verification without API key.
|
|
211
|
+
*
|
|
212
|
+
* Uses the public /verify endpoint — no authentication needed.
|
|
213
|
+
*
|
|
214
|
+
* @param receipt - Receipt JSON object
|
|
215
|
+
* @param baseUrl - API base URL (default: production)
|
|
216
|
+
* @returns true if the receipt is valid
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```typescript
|
|
220
|
+
* import { verifyReceipt } from 'notaryos';
|
|
221
|
+
*
|
|
222
|
+
* const isValid = await verifyReceipt(receiptJson);
|
|
223
|
+
* console.log(isValid); // true
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
declare function verifyReceipt(receipt: Record<string, unknown>, baseUrl?: string): Promise<boolean>;
|
|
227
|
+
/**
|
|
228
|
+
* Compute SHA-256 hash of a payload using Web Crypto API.
|
|
229
|
+
*
|
|
230
|
+
* Matches the server-side hashing for independent verification.
|
|
231
|
+
*
|
|
232
|
+
* @param payload - String or JSON-serializable object
|
|
233
|
+
* @returns Hex-encoded SHA-256 digest
|
|
234
|
+
*/
|
|
235
|
+
declare function computeHash(payload: Record<string, unknown> | string): Promise<string>;
|
|
236
|
+
|
|
237
|
+
export { type AgentInfo, AuthenticationError, type IssueOptions, type LookupResult, NotaryClient, type NotaryConfig, NotaryError, type PublicKeyInfo, RateLimitError, type Receipt, SDK_VERSION, type ServiceStatus, ValidationError, type VerificationResult, computeHash, verifyReceipt };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NotaryOS SDK - Cryptographic receipts for AI agent actions.
|
|
3
|
+
*
|
|
4
|
+
* Issue, verify, and audit agent behavior with Ed25519 signatures.
|
|
5
|
+
* Zero dependencies. Uses native fetch() and Web Crypto API.
|
|
6
|
+
*
|
|
7
|
+
* Quick start:
|
|
8
|
+
*
|
|
9
|
+
* import { NotaryClient } from 'notaryos';
|
|
10
|
+
* const notary = new NotaryClient({ apiKey: 'notary_live_xxx' });
|
|
11
|
+
* const receipt = await notary.issue('my_action', { key: 'value' });
|
|
12
|
+
*
|
|
13
|
+
* Verify without API key:
|
|
14
|
+
*
|
|
15
|
+
* import { verifyReceipt } from 'notaryos';
|
|
16
|
+
* const isValid = await verifyReceipt(receiptJson);
|
|
17
|
+
*
|
|
18
|
+
* @packageDocumentation
|
|
19
|
+
*/
|
|
20
|
+
declare const SDK_VERSION = "1.0.0";
|
|
21
|
+
/** Client configuration options. */
|
|
22
|
+
interface NotaryConfig {
|
|
23
|
+
/** Your Notary API key (notary_live_xxx or notary_test_xxx). */
|
|
24
|
+
apiKey: string;
|
|
25
|
+
/** API base URL (default: https://api.agenttownsquare.com). */
|
|
26
|
+
baseUrl?: string;
|
|
27
|
+
/** Request timeout in milliseconds (default: 30000). */
|
|
28
|
+
timeout?: number;
|
|
29
|
+
/** Max retry attempts on transient failures (default: 2). */
|
|
30
|
+
maxRetries?: number;
|
|
31
|
+
}
|
|
32
|
+
/** A signed Notary receipt. */
|
|
33
|
+
interface Receipt {
|
|
34
|
+
receipt_id: string;
|
|
35
|
+
timestamp: string;
|
|
36
|
+
agent_id: string;
|
|
37
|
+
action_type: string;
|
|
38
|
+
payload_hash: string;
|
|
39
|
+
signature: string;
|
|
40
|
+
signature_type: string;
|
|
41
|
+
key_id: string;
|
|
42
|
+
kid?: string;
|
|
43
|
+
alg?: string;
|
|
44
|
+
schema_version?: string;
|
|
45
|
+
chain_sequence?: number;
|
|
46
|
+
previous_receipt_hash?: string | null;
|
|
47
|
+
receipt_hash?: string;
|
|
48
|
+
verify_url?: string;
|
|
49
|
+
}
|
|
50
|
+
/** Result of receipt verification. */
|
|
51
|
+
interface VerificationResult {
|
|
52
|
+
valid: boolean;
|
|
53
|
+
signature_ok: boolean;
|
|
54
|
+
structure_ok: boolean;
|
|
55
|
+
chain_ok?: boolean | null;
|
|
56
|
+
reason: string;
|
|
57
|
+
details: Record<string, unknown>;
|
|
58
|
+
from_cache?: boolean;
|
|
59
|
+
}
|
|
60
|
+
/** Notary service status. */
|
|
61
|
+
interface ServiceStatus {
|
|
62
|
+
status: string;
|
|
63
|
+
signature_type: string;
|
|
64
|
+
key_id: string;
|
|
65
|
+
has_public_key: boolean;
|
|
66
|
+
capabilities: string[];
|
|
67
|
+
timestamp: string;
|
|
68
|
+
}
|
|
69
|
+
/** Public key for offline verification. */
|
|
70
|
+
interface PublicKeyInfo {
|
|
71
|
+
key_id: string;
|
|
72
|
+
signature_type: string;
|
|
73
|
+
public_key_pem: string;
|
|
74
|
+
verification_note: string;
|
|
75
|
+
}
|
|
76
|
+
/** Result of a receipt lookup by hash. */
|
|
77
|
+
interface LookupResult {
|
|
78
|
+
found: boolean;
|
|
79
|
+
receipt: Receipt | null;
|
|
80
|
+
verification: VerificationResult | null;
|
|
81
|
+
meta: Record<string, unknown> | null;
|
|
82
|
+
}
|
|
83
|
+
/** Authenticated agent information. */
|
|
84
|
+
interface AgentInfo {
|
|
85
|
+
agent_id: string;
|
|
86
|
+
agent_name: string;
|
|
87
|
+
tier: string;
|
|
88
|
+
scopes: string[];
|
|
89
|
+
rate_limit_per_minute: number;
|
|
90
|
+
}
|
|
91
|
+
/** Options for issuing receipts. */
|
|
92
|
+
interface IssueOptions {
|
|
93
|
+
/** Hash of previous receipt for chaining. */
|
|
94
|
+
previousReceiptHash?: string;
|
|
95
|
+
/** Additional metadata. */
|
|
96
|
+
metadata?: Record<string, unknown>;
|
|
97
|
+
}
|
|
98
|
+
/** Base error for all NotaryOS SDK errors. */
|
|
99
|
+
declare class NotaryError extends Error {
|
|
100
|
+
code: string;
|
|
101
|
+
status: number;
|
|
102
|
+
details: Record<string, unknown>;
|
|
103
|
+
constructor(message: string, code?: string, status?: number, details?: Record<string, unknown>);
|
|
104
|
+
}
|
|
105
|
+
/** Invalid or missing API key. */
|
|
106
|
+
declare class AuthenticationError extends NotaryError {
|
|
107
|
+
constructor(message: string, code?: string);
|
|
108
|
+
}
|
|
109
|
+
/** Rate limit exceeded. */
|
|
110
|
+
declare class RateLimitError extends NotaryError {
|
|
111
|
+
retryAfter?: number;
|
|
112
|
+
constructor(message: string, retryAfter?: number);
|
|
113
|
+
}
|
|
114
|
+
/** Request validation failed. */
|
|
115
|
+
declare class ValidationError extends NotaryError {
|
|
116
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* NotaryOS API client.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const notary = new NotaryClient({ apiKey: 'notary_live_xxx' });
|
|
124
|
+
*
|
|
125
|
+
* // Issue a receipt
|
|
126
|
+
* const receipt = await notary.issue('data_processing', { key: 'value' });
|
|
127
|
+
*
|
|
128
|
+
* // Verify a receipt
|
|
129
|
+
* const result = await notary.verify(receipt);
|
|
130
|
+
* console.log(result.valid); // true
|
|
131
|
+
*
|
|
132
|
+
* // Check service health
|
|
133
|
+
* const status = await notary.status();
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
declare class NotaryClient {
|
|
137
|
+
private apiKey;
|
|
138
|
+
private baseUrl;
|
|
139
|
+
private timeout;
|
|
140
|
+
private maxRetries;
|
|
141
|
+
static readonly DEFAULT_BASE_URL = "https://api.agenttownsquare.com";
|
|
142
|
+
static readonly DEFAULT_TIMEOUT = 30000;
|
|
143
|
+
constructor(config: NotaryConfig);
|
|
144
|
+
private request;
|
|
145
|
+
private sleep;
|
|
146
|
+
/**
|
|
147
|
+
* Issue a signed receipt for an action.
|
|
148
|
+
*
|
|
149
|
+
* @param actionType - Type of action (e.g., "data_processing", "api_call")
|
|
150
|
+
* @param payload - Action payload to be receipted
|
|
151
|
+
* @param options - Optional chaining and metadata
|
|
152
|
+
* @returns A signed Receipt
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const receipt = await notary.issue('transfer', { amount: 100, to: 'agent-b' });
|
|
157
|
+
* console.log(receipt.receipt_id);
|
|
158
|
+
* console.log(receipt.verify_url); // https://...notary/r/abc123
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
issue(actionType: string, payload: Record<string, unknown>, options?: IssueOptions): Promise<Receipt>;
|
|
162
|
+
/**
|
|
163
|
+
* Verify a receipt's signature and integrity.
|
|
164
|
+
*
|
|
165
|
+
* @param receipt - Receipt object or raw receipt dict
|
|
166
|
+
* @returns VerificationResult with validity details
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```typescript
|
|
170
|
+
* const result = await notary.verify(receipt);
|
|
171
|
+
* if (result.valid) {
|
|
172
|
+
* console.log('Receipt is authentic');
|
|
173
|
+
* }
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
verify(receipt: Receipt | Record<string, unknown>): Promise<VerificationResult>;
|
|
177
|
+
/** Verify a receipt by its ID (server-side lookup). */
|
|
178
|
+
verifyById(receiptId: string): Promise<VerificationResult>;
|
|
179
|
+
/**
|
|
180
|
+
* Get Notary service status.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const status = await notary.status();
|
|
185
|
+
* console.log(status.status); // "active"
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
status(): Promise<ServiceStatus>;
|
|
189
|
+
/** Get the public key for offline verification. */
|
|
190
|
+
publicKey(): Promise<PublicKeyInfo>;
|
|
191
|
+
/** Get authenticated agent info. */
|
|
192
|
+
me(): Promise<AgentInfo>;
|
|
193
|
+
/**
|
|
194
|
+
* Look up a receipt by hash (public endpoint, no API key required for lookup).
|
|
195
|
+
*
|
|
196
|
+
* @param receiptHash - Full or partial receipt hash (min 16 chars)
|
|
197
|
+
* @returns Lookup result with receipt, verification, and meta
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* const result = await notary.lookup('abc123def456...');
|
|
202
|
+
* if (result.found && result.verification?.valid) {
|
|
203
|
+
* console.log('Receipt is valid!');
|
|
204
|
+
* }
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
lookup(receiptHash: string): Promise<LookupResult>;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Quick receipt verification without API key.
|
|
211
|
+
*
|
|
212
|
+
* Uses the public /verify endpoint — no authentication needed.
|
|
213
|
+
*
|
|
214
|
+
* @param receipt - Receipt JSON object
|
|
215
|
+
* @param baseUrl - API base URL (default: production)
|
|
216
|
+
* @returns true if the receipt is valid
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```typescript
|
|
220
|
+
* import { verifyReceipt } from 'notaryos';
|
|
221
|
+
*
|
|
222
|
+
* const isValid = await verifyReceipt(receiptJson);
|
|
223
|
+
* console.log(isValid); // true
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
declare function verifyReceipt(receipt: Record<string, unknown>, baseUrl?: string): Promise<boolean>;
|
|
227
|
+
/**
|
|
228
|
+
* Compute SHA-256 hash of a payload using Web Crypto API.
|
|
229
|
+
*
|
|
230
|
+
* Matches the server-side hashing for independent verification.
|
|
231
|
+
*
|
|
232
|
+
* @param payload - String or JSON-serializable object
|
|
233
|
+
* @returns Hex-encoded SHA-256 digest
|
|
234
|
+
*/
|
|
235
|
+
declare function computeHash(payload: Record<string, unknown> | string): Promise<string>;
|
|
236
|
+
|
|
237
|
+
export { type AgentInfo, AuthenticationError, type IssueOptions, type LookupResult, NotaryClient, type NotaryConfig, NotaryError, type PublicKeyInfo, RateLimitError, type Receipt, SDK_VERSION, type ServiceStatus, ValidationError, type VerificationResult, computeHash, verifyReceipt };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
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
|
+
AuthenticationError: () => AuthenticationError,
|
|
24
|
+
NotaryClient: () => NotaryClient,
|
|
25
|
+
NotaryError: () => NotaryError,
|
|
26
|
+
RateLimitError: () => RateLimitError,
|
|
27
|
+
SDK_VERSION: () => SDK_VERSION,
|
|
28
|
+
ValidationError: () => ValidationError,
|
|
29
|
+
computeHash: () => computeHash,
|
|
30
|
+
verifyReceipt: () => verifyReceipt
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(index_exports);
|
|
33
|
+
var SDK_VERSION = "1.0.0";
|
|
34
|
+
var NotaryError = class extends Error {
|
|
35
|
+
constructor(message, code = "", status = 0, details = {}) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "NotaryError";
|
|
38
|
+
this.code = code;
|
|
39
|
+
this.status = status;
|
|
40
|
+
this.details = details;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var AuthenticationError = class extends NotaryError {
|
|
44
|
+
constructor(message, code = "ERR_INVALID_API_KEY") {
|
|
45
|
+
super(message, code, 401);
|
|
46
|
+
this.name = "AuthenticationError";
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var RateLimitError = class extends NotaryError {
|
|
50
|
+
constructor(message, retryAfter) {
|
|
51
|
+
super(message, "ERR_RATE_LIMIT_EXCEEDED", 429);
|
|
52
|
+
this.name = "RateLimitError";
|
|
53
|
+
this.retryAfter = retryAfter;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var ValidationError = class extends NotaryError {
|
|
57
|
+
constructor(message, details = {}) {
|
|
58
|
+
super(message, "ERR_VALIDATION_FAILED", 422, details);
|
|
59
|
+
this.name = "ValidationError";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var _NotaryClient = class _NotaryClient {
|
|
63
|
+
constructor(config) {
|
|
64
|
+
const { apiKey, baseUrl, timeout, maxRetries } = config;
|
|
65
|
+
if (!apiKey || !(apiKey.startsWith("notary_live_") || apiKey.startsWith("notary_test_"))) {
|
|
66
|
+
throw new AuthenticationError(
|
|
67
|
+
"Invalid API key format. Keys must start with notary_live_ or notary_test_"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
this.apiKey = apiKey;
|
|
71
|
+
this.baseUrl = (baseUrl || _NotaryClient.DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
72
|
+
this.timeout = timeout || _NotaryClient.DEFAULT_TIMEOUT;
|
|
73
|
+
this.maxRetries = maxRetries ?? 2;
|
|
74
|
+
}
|
|
75
|
+
async request(method, path, body) {
|
|
76
|
+
const url = `${this.baseUrl}/v1/notary${path}`;
|
|
77
|
+
const headers = {
|
|
78
|
+
"X-API-Key": this.apiKey,
|
|
79
|
+
"Content-Type": "application/json",
|
|
80
|
+
"User-Agent": `notary-typescript-sdk/${SDK_VERSION}`
|
|
81
|
+
};
|
|
82
|
+
let lastError = null;
|
|
83
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
84
|
+
const controller = new AbortController();
|
|
85
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
86
|
+
try {
|
|
87
|
+
const response = await fetch(url, {
|
|
88
|
+
method,
|
|
89
|
+
headers,
|
|
90
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
91
|
+
signal: controller.signal
|
|
92
|
+
});
|
|
93
|
+
clearTimeout(timeoutId);
|
|
94
|
+
if (response.ok) {
|
|
95
|
+
const text = await response.text();
|
|
96
|
+
return text ? JSON.parse(text) : {};
|
|
97
|
+
}
|
|
98
|
+
let errorData = {};
|
|
99
|
+
try {
|
|
100
|
+
errorData = await response.json();
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
const errorInfo = errorData.error || { message: response.statusText, code: "" };
|
|
104
|
+
const errorMsg = errorInfo.message || response.statusText;
|
|
105
|
+
const errorCode = errorInfo.code || "";
|
|
106
|
+
if (response.status === 401) {
|
|
107
|
+
throw new AuthenticationError(errorMsg, errorCode);
|
|
108
|
+
}
|
|
109
|
+
if (response.status === 429) {
|
|
110
|
+
const retryAfter = parseInt(response.headers.get("Retry-After") || "60", 10);
|
|
111
|
+
if (attempt < this.maxRetries) {
|
|
112
|
+
await this.sleep(Math.min(retryAfter * 1e3, 5e3));
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
throw new RateLimitError(errorMsg, retryAfter);
|
|
116
|
+
}
|
|
117
|
+
if (response.status === 422) {
|
|
118
|
+
throw new ValidationError(errorMsg, errorInfo.details || {});
|
|
119
|
+
}
|
|
120
|
+
if (response.status >= 500 && attempt < this.maxRetries) {
|
|
121
|
+
await this.sleep(2 ** attempt * 1e3);
|
|
122
|
+
lastError = new NotaryError(errorMsg, errorCode, response.status);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
throw new NotaryError(errorMsg, errorCode, response.status, errorInfo.details || {});
|
|
126
|
+
} catch (err) {
|
|
127
|
+
clearTimeout(timeoutId);
|
|
128
|
+
if (err instanceof NotaryError) throw err;
|
|
129
|
+
if (attempt < this.maxRetries) {
|
|
130
|
+
await this.sleep(2 ** attempt * 1e3);
|
|
131
|
+
lastError = err;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
throw new NotaryError(
|
|
135
|
+
`Connection failed: ${err.message}`,
|
|
136
|
+
"ERR_CONNECTION"
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
throw lastError || new NotaryError("Request failed", "ERR_UNKNOWN");
|
|
141
|
+
}
|
|
142
|
+
sleep(ms) {
|
|
143
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Issue a signed receipt for an action.
|
|
147
|
+
*
|
|
148
|
+
* @param actionType - Type of action (e.g., "data_processing", "api_call")
|
|
149
|
+
* @param payload - Action payload to be receipted
|
|
150
|
+
* @param options - Optional chaining and metadata
|
|
151
|
+
* @returns A signed Receipt
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* const receipt = await notary.issue('transfer', { amount: 100, to: 'agent-b' });
|
|
156
|
+
* console.log(receipt.receipt_id);
|
|
157
|
+
* console.log(receipt.verify_url); // https://...notary/r/abc123
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
async issue(actionType, payload, options = {}) {
|
|
161
|
+
const body = {
|
|
162
|
+
action_type: actionType,
|
|
163
|
+
payload
|
|
164
|
+
};
|
|
165
|
+
if (options.previousReceiptHash) {
|
|
166
|
+
body.previous_receipt_hash = options.previousReceiptHash;
|
|
167
|
+
}
|
|
168
|
+
if (options.metadata) {
|
|
169
|
+
body.metadata = options.metadata;
|
|
170
|
+
}
|
|
171
|
+
const response = await this.request("POST", "/issue", body);
|
|
172
|
+
return {
|
|
173
|
+
...response.receipt,
|
|
174
|
+
receipt_hash: response.receipt_hash,
|
|
175
|
+
verify_url: response.verify_url,
|
|
176
|
+
chain_sequence: response.chain_position
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Verify a receipt's signature and integrity.
|
|
181
|
+
*
|
|
182
|
+
* @param receipt - Receipt object or raw receipt dict
|
|
183
|
+
* @returns VerificationResult with validity details
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* const result = await notary.verify(receipt);
|
|
188
|
+
* if (result.valid) {
|
|
189
|
+
* console.log('Receipt is authentic');
|
|
190
|
+
* }
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
async verify(receipt) {
|
|
194
|
+
return this.request("POST", "/verify", { receipt });
|
|
195
|
+
}
|
|
196
|
+
/** Verify a receipt by its ID (server-side lookup). */
|
|
197
|
+
async verifyById(receiptId) {
|
|
198
|
+
return this.request("POST", "/verify", { receipt_id: receiptId });
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Get Notary service status.
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```typescript
|
|
205
|
+
* const status = await notary.status();
|
|
206
|
+
* console.log(status.status); // "active"
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
async status() {
|
|
210
|
+
return this.request("GET", "/status");
|
|
211
|
+
}
|
|
212
|
+
/** Get the public key for offline verification. */
|
|
213
|
+
async publicKey() {
|
|
214
|
+
return this.request("GET", "/public-key");
|
|
215
|
+
}
|
|
216
|
+
/** Get authenticated agent info. */
|
|
217
|
+
async me() {
|
|
218
|
+
return this.request("GET", "/agents/me");
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Look up a receipt by hash (public endpoint, no API key required for lookup).
|
|
222
|
+
*
|
|
223
|
+
* @param receiptHash - Full or partial receipt hash (min 16 chars)
|
|
224
|
+
* @returns Lookup result with receipt, verification, and meta
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* const result = await notary.lookup('abc123def456...');
|
|
229
|
+
* if (result.found && result.verification?.valid) {
|
|
230
|
+
* console.log('Receipt is valid!');
|
|
231
|
+
* }
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
async lookup(receiptHash) {
|
|
235
|
+
const url = `${this.baseUrl}/v1/notary/r/${receiptHash}`;
|
|
236
|
+
const controller = new AbortController();
|
|
237
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
238
|
+
try {
|
|
239
|
+
const response = await fetch(url, {
|
|
240
|
+
method: "GET",
|
|
241
|
+
headers: {
|
|
242
|
+
"Content-Type": "application/json",
|
|
243
|
+
"User-Agent": `notary-typescript-sdk/${SDK_VERSION}`
|
|
244
|
+
},
|
|
245
|
+
signal: controller.signal
|
|
246
|
+
});
|
|
247
|
+
clearTimeout(timeoutId);
|
|
248
|
+
if (response.status === 404) {
|
|
249
|
+
return { found: false, receipt: null, verification: null, meta: null };
|
|
250
|
+
}
|
|
251
|
+
if (!response.ok) {
|
|
252
|
+
throw new NotaryError(
|
|
253
|
+
response.statusText,
|
|
254
|
+
"ERR_LOOKUP",
|
|
255
|
+
response.status
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
return await response.json();
|
|
259
|
+
} catch (err) {
|
|
260
|
+
clearTimeout(timeoutId);
|
|
261
|
+
if (err instanceof NotaryError) throw err;
|
|
262
|
+
throw new NotaryError(
|
|
263
|
+
`Connection failed: ${err.message}`,
|
|
264
|
+
"ERR_CONNECTION"
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
_NotaryClient.DEFAULT_BASE_URL = "https://api.agenttownsquare.com";
|
|
270
|
+
_NotaryClient.DEFAULT_TIMEOUT = 3e4;
|
|
271
|
+
var NotaryClient = _NotaryClient;
|
|
272
|
+
async function verifyReceipt(receipt, baseUrl = NotaryClient.DEFAULT_BASE_URL) {
|
|
273
|
+
try {
|
|
274
|
+
const response = await fetch(`${baseUrl.replace(/\/+$/, "")}/v1/notary/verify`, {
|
|
275
|
+
method: "POST",
|
|
276
|
+
headers: { "Content-Type": "application/json" },
|
|
277
|
+
body: JSON.stringify({ receipt })
|
|
278
|
+
});
|
|
279
|
+
if (!response.ok) return false;
|
|
280
|
+
const result = await response.json();
|
|
281
|
+
return result.valid === true;
|
|
282
|
+
} catch {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async function computeHash(payload) {
|
|
287
|
+
const data = typeof payload === "string" ? payload : JSON.stringify(payload, Object.keys(payload).sort());
|
|
288
|
+
const encoded = new TextEncoder().encode(data);
|
|
289
|
+
const buffer = await crypto.subtle.digest("SHA-256", encoded);
|
|
290
|
+
const bytes = new Uint8Array(buffer);
|
|
291
|
+
let hex = "";
|
|
292
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
293
|
+
hex += bytes[i].toString(16).padStart(2, "0");
|
|
294
|
+
}
|
|
295
|
+
return hex;
|
|
296
|
+
}
|
|
297
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
298
|
+
0 && (module.exports = {
|
|
299
|
+
AuthenticationError,
|
|
300
|
+
NotaryClient,
|
|
301
|
+
NotaryError,
|
|
302
|
+
RateLimitError,
|
|
303
|
+
SDK_VERSION,
|
|
304
|
+
ValidationError,
|
|
305
|
+
computeHash,
|
|
306
|
+
verifyReceipt
|
|
307
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var SDK_VERSION = "1.0.0";
|
|
3
|
+
var NotaryError = class extends Error {
|
|
4
|
+
constructor(message, code = "", status = 0, details = {}) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "NotaryError";
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.details = details;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var AuthenticationError = class extends NotaryError {
|
|
13
|
+
constructor(message, code = "ERR_INVALID_API_KEY") {
|
|
14
|
+
super(message, code, 401);
|
|
15
|
+
this.name = "AuthenticationError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var RateLimitError = class extends NotaryError {
|
|
19
|
+
constructor(message, retryAfter) {
|
|
20
|
+
super(message, "ERR_RATE_LIMIT_EXCEEDED", 429);
|
|
21
|
+
this.name = "RateLimitError";
|
|
22
|
+
this.retryAfter = retryAfter;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var ValidationError = class extends NotaryError {
|
|
26
|
+
constructor(message, details = {}) {
|
|
27
|
+
super(message, "ERR_VALIDATION_FAILED", 422, details);
|
|
28
|
+
this.name = "ValidationError";
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var _NotaryClient = class _NotaryClient {
|
|
32
|
+
constructor(config) {
|
|
33
|
+
const { apiKey, baseUrl, timeout, maxRetries } = config;
|
|
34
|
+
if (!apiKey || !(apiKey.startsWith("notary_live_") || apiKey.startsWith("notary_test_"))) {
|
|
35
|
+
throw new AuthenticationError(
|
|
36
|
+
"Invalid API key format. Keys must start with notary_live_ or notary_test_"
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
this.apiKey = apiKey;
|
|
40
|
+
this.baseUrl = (baseUrl || _NotaryClient.DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
41
|
+
this.timeout = timeout || _NotaryClient.DEFAULT_TIMEOUT;
|
|
42
|
+
this.maxRetries = maxRetries ?? 2;
|
|
43
|
+
}
|
|
44
|
+
async request(method, path, body) {
|
|
45
|
+
const url = `${this.baseUrl}/v1/notary${path}`;
|
|
46
|
+
const headers = {
|
|
47
|
+
"X-API-Key": this.apiKey,
|
|
48
|
+
"Content-Type": "application/json",
|
|
49
|
+
"User-Agent": `notary-typescript-sdk/${SDK_VERSION}`
|
|
50
|
+
};
|
|
51
|
+
let lastError = null;
|
|
52
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
55
|
+
try {
|
|
56
|
+
const response = await fetch(url, {
|
|
57
|
+
method,
|
|
58
|
+
headers,
|
|
59
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
60
|
+
signal: controller.signal
|
|
61
|
+
});
|
|
62
|
+
clearTimeout(timeoutId);
|
|
63
|
+
if (response.ok) {
|
|
64
|
+
const text = await response.text();
|
|
65
|
+
return text ? JSON.parse(text) : {};
|
|
66
|
+
}
|
|
67
|
+
let errorData = {};
|
|
68
|
+
try {
|
|
69
|
+
errorData = await response.json();
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
const errorInfo = errorData.error || { message: response.statusText, code: "" };
|
|
73
|
+
const errorMsg = errorInfo.message || response.statusText;
|
|
74
|
+
const errorCode = errorInfo.code || "";
|
|
75
|
+
if (response.status === 401) {
|
|
76
|
+
throw new AuthenticationError(errorMsg, errorCode);
|
|
77
|
+
}
|
|
78
|
+
if (response.status === 429) {
|
|
79
|
+
const retryAfter = parseInt(response.headers.get("Retry-After") || "60", 10);
|
|
80
|
+
if (attempt < this.maxRetries) {
|
|
81
|
+
await this.sleep(Math.min(retryAfter * 1e3, 5e3));
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
throw new RateLimitError(errorMsg, retryAfter);
|
|
85
|
+
}
|
|
86
|
+
if (response.status === 422) {
|
|
87
|
+
throw new ValidationError(errorMsg, errorInfo.details || {});
|
|
88
|
+
}
|
|
89
|
+
if (response.status >= 500 && attempt < this.maxRetries) {
|
|
90
|
+
await this.sleep(2 ** attempt * 1e3);
|
|
91
|
+
lastError = new NotaryError(errorMsg, errorCode, response.status);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
throw new NotaryError(errorMsg, errorCode, response.status, errorInfo.details || {});
|
|
95
|
+
} catch (err) {
|
|
96
|
+
clearTimeout(timeoutId);
|
|
97
|
+
if (err instanceof NotaryError) throw err;
|
|
98
|
+
if (attempt < this.maxRetries) {
|
|
99
|
+
await this.sleep(2 ** attempt * 1e3);
|
|
100
|
+
lastError = err;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
throw new NotaryError(
|
|
104
|
+
`Connection failed: ${err.message}`,
|
|
105
|
+
"ERR_CONNECTION"
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
throw lastError || new NotaryError("Request failed", "ERR_UNKNOWN");
|
|
110
|
+
}
|
|
111
|
+
sleep(ms) {
|
|
112
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Issue a signed receipt for an action.
|
|
116
|
+
*
|
|
117
|
+
* @param actionType - Type of action (e.g., "data_processing", "api_call")
|
|
118
|
+
* @param payload - Action payload to be receipted
|
|
119
|
+
* @param options - Optional chaining and metadata
|
|
120
|
+
* @returns A signed Receipt
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const receipt = await notary.issue('transfer', { amount: 100, to: 'agent-b' });
|
|
125
|
+
* console.log(receipt.receipt_id);
|
|
126
|
+
* console.log(receipt.verify_url); // https://...notary/r/abc123
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
async issue(actionType, payload, options = {}) {
|
|
130
|
+
const body = {
|
|
131
|
+
action_type: actionType,
|
|
132
|
+
payload
|
|
133
|
+
};
|
|
134
|
+
if (options.previousReceiptHash) {
|
|
135
|
+
body.previous_receipt_hash = options.previousReceiptHash;
|
|
136
|
+
}
|
|
137
|
+
if (options.metadata) {
|
|
138
|
+
body.metadata = options.metadata;
|
|
139
|
+
}
|
|
140
|
+
const response = await this.request("POST", "/issue", body);
|
|
141
|
+
return {
|
|
142
|
+
...response.receipt,
|
|
143
|
+
receipt_hash: response.receipt_hash,
|
|
144
|
+
verify_url: response.verify_url,
|
|
145
|
+
chain_sequence: response.chain_position
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Verify a receipt's signature and integrity.
|
|
150
|
+
*
|
|
151
|
+
* @param receipt - Receipt object or raw receipt dict
|
|
152
|
+
* @returns VerificationResult with validity details
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const result = await notary.verify(receipt);
|
|
157
|
+
* if (result.valid) {
|
|
158
|
+
* console.log('Receipt is authentic');
|
|
159
|
+
* }
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
async verify(receipt) {
|
|
163
|
+
return this.request("POST", "/verify", { receipt });
|
|
164
|
+
}
|
|
165
|
+
/** Verify a receipt by its ID (server-side lookup). */
|
|
166
|
+
async verifyById(receiptId) {
|
|
167
|
+
return this.request("POST", "/verify", { receipt_id: receiptId });
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get Notary service status.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* const status = await notary.status();
|
|
175
|
+
* console.log(status.status); // "active"
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
async status() {
|
|
179
|
+
return this.request("GET", "/status");
|
|
180
|
+
}
|
|
181
|
+
/** Get the public key for offline verification. */
|
|
182
|
+
async publicKey() {
|
|
183
|
+
return this.request("GET", "/public-key");
|
|
184
|
+
}
|
|
185
|
+
/** Get authenticated agent info. */
|
|
186
|
+
async me() {
|
|
187
|
+
return this.request("GET", "/agents/me");
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Look up a receipt by hash (public endpoint, no API key required for lookup).
|
|
191
|
+
*
|
|
192
|
+
* @param receiptHash - Full or partial receipt hash (min 16 chars)
|
|
193
|
+
* @returns Lookup result with receipt, verification, and meta
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```typescript
|
|
197
|
+
* const result = await notary.lookup('abc123def456...');
|
|
198
|
+
* if (result.found && result.verification?.valid) {
|
|
199
|
+
* console.log('Receipt is valid!');
|
|
200
|
+
* }
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
async lookup(receiptHash) {
|
|
204
|
+
const url = `${this.baseUrl}/v1/notary/r/${receiptHash}`;
|
|
205
|
+
const controller = new AbortController();
|
|
206
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
207
|
+
try {
|
|
208
|
+
const response = await fetch(url, {
|
|
209
|
+
method: "GET",
|
|
210
|
+
headers: {
|
|
211
|
+
"Content-Type": "application/json",
|
|
212
|
+
"User-Agent": `notary-typescript-sdk/${SDK_VERSION}`
|
|
213
|
+
},
|
|
214
|
+
signal: controller.signal
|
|
215
|
+
});
|
|
216
|
+
clearTimeout(timeoutId);
|
|
217
|
+
if (response.status === 404) {
|
|
218
|
+
return { found: false, receipt: null, verification: null, meta: null };
|
|
219
|
+
}
|
|
220
|
+
if (!response.ok) {
|
|
221
|
+
throw new NotaryError(
|
|
222
|
+
response.statusText,
|
|
223
|
+
"ERR_LOOKUP",
|
|
224
|
+
response.status
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
return await response.json();
|
|
228
|
+
} catch (err) {
|
|
229
|
+
clearTimeout(timeoutId);
|
|
230
|
+
if (err instanceof NotaryError) throw err;
|
|
231
|
+
throw new NotaryError(
|
|
232
|
+
`Connection failed: ${err.message}`,
|
|
233
|
+
"ERR_CONNECTION"
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
_NotaryClient.DEFAULT_BASE_URL = "https://api.agenttownsquare.com";
|
|
239
|
+
_NotaryClient.DEFAULT_TIMEOUT = 3e4;
|
|
240
|
+
var NotaryClient = _NotaryClient;
|
|
241
|
+
async function verifyReceipt(receipt, baseUrl = NotaryClient.DEFAULT_BASE_URL) {
|
|
242
|
+
try {
|
|
243
|
+
const response = await fetch(`${baseUrl.replace(/\/+$/, "")}/v1/notary/verify`, {
|
|
244
|
+
method: "POST",
|
|
245
|
+
headers: { "Content-Type": "application/json" },
|
|
246
|
+
body: JSON.stringify({ receipt })
|
|
247
|
+
});
|
|
248
|
+
if (!response.ok) return false;
|
|
249
|
+
const result = await response.json();
|
|
250
|
+
return result.valid === true;
|
|
251
|
+
} catch {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
async function computeHash(payload) {
|
|
256
|
+
const data = typeof payload === "string" ? payload : JSON.stringify(payload, Object.keys(payload).sort());
|
|
257
|
+
const encoded = new TextEncoder().encode(data);
|
|
258
|
+
const buffer = await crypto.subtle.digest("SHA-256", encoded);
|
|
259
|
+
const bytes = new Uint8Array(buffer);
|
|
260
|
+
let hex = "";
|
|
261
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
262
|
+
hex += bytes[i].toString(16).padStart(2, "0");
|
|
263
|
+
}
|
|
264
|
+
return hex;
|
|
265
|
+
}
|
|
266
|
+
export {
|
|
267
|
+
AuthenticationError,
|
|
268
|
+
NotaryClient,
|
|
269
|
+
NotaryError,
|
|
270
|
+
RateLimitError,
|
|
271
|
+
SDK_VERSION,
|
|
272
|
+
ValidationError,
|
|
273
|
+
computeHash,
|
|
274
|
+
verifyReceipt
|
|
275
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "notaryos",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "NotaryOS SDK - Cryptographic receipts for AI agent actions. Issue, verify, and audit agent behavior with Ed25519 signatures.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"test": "node --test dist/test.js",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"notary",
|
|
28
|
+
"cryptographic",
|
|
29
|
+
"receipt",
|
|
30
|
+
"verification",
|
|
31
|
+
"ai",
|
|
32
|
+
"agent",
|
|
33
|
+
"ed25519",
|
|
34
|
+
"audit",
|
|
35
|
+
"accountability",
|
|
36
|
+
"a2a",
|
|
37
|
+
"agent-to-agent"
|
|
38
|
+
],
|
|
39
|
+
"author": {
|
|
40
|
+
"name": "Agent Town Square",
|
|
41
|
+
"email": "hello@agenttownsquare.com",
|
|
42
|
+
"url": "https://agenttownsquare.com"
|
|
43
|
+
},
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/hellothere012/notaryos"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://notaryos.org",
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/hellothere012/notaryos/issues"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18.0.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"tsup": "^8.0.0",
|
|
58
|
+
"typescript": "^5.3.0"
|
|
59
|
+
}
|
|
60
|
+
}
|