@heyanon-arp/sdk 0.0.2

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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +147 -0
  3. package/dist/assets.d.ts +101 -0
  4. package/dist/attestation/attestation.d.ts +29 -0
  5. package/dist/attestation/index.d.ts +2 -0
  6. package/dist/attestation/scrypt-proof.d.ts +28 -0
  7. package/dist/canonical/canonicalize.d.ts +33 -0
  8. package/dist/canonical/index.d.ts +1 -0
  9. package/dist/challenge/challenge.d.ts +11 -0
  10. package/dist/challenge/index.d.ts +1 -0
  11. package/dist/cosignature/cosign.d.ts +35 -0
  12. package/dist/cosignature/index.d.ts +2 -0
  13. package/dist/did/document.d.ts +30 -0
  14. package/dist/did/format.d.ts +23 -0
  15. package/dist/did/index.d.ts +2 -0
  16. package/dist/envelope/index.d.ts +4 -0
  17. package/dist/envelope/sign.d.ts +28 -0
  18. package/dist/envelope/verify.d.ts +37 -0
  19. package/dist/escrow/caip19.d.ts +41 -0
  20. package/dist/escrow/condition-hash.d.ts +79 -0
  21. package/dist/escrow/create-lock.d.ts +39 -0
  22. package/dist/escrow/index.d.ts +4 -0
  23. package/dist/escrow/lock-id.d.ts +67 -0
  24. package/dist/index.d.ts +38 -0
  25. package/dist/index.js +853 -0
  26. package/dist/index.mjs +761 -0
  27. package/dist/keys/base58btc.d.ts +10 -0
  28. package/dist/keys/ed25519.d.ts +33 -0
  29. package/dist/keys/index.d.ts +3 -0
  30. package/dist/purpose.d.ts +52 -0
  31. package/dist/server-chain/chain.d.ts +52 -0
  32. package/dist/server-chain/index.d.ts +2 -0
  33. package/dist/settlement/index.d.ts +4 -0
  34. package/dist/settlement/settlement.d.ts +111 -0
  35. package/dist/settlement/token-program.d.ts +72 -0
  36. package/dist/types/body.d.ts +263 -0
  37. package/dist/types/envelope.d.ts +121 -0
  38. package/dist/types/identity.d.ts +62 -0
  39. package/dist/types/index.d.ts +5 -0
  40. package/dist/utils/index.d.ts +3 -0
  41. package/dist/utils/nonce.d.ts +9 -0
  42. package/dist/utils/timestamp.d.ts +17 -0
  43. package/dist/utils/uuid.d.ts +10 -0
  44. package/dist/webhook/index.d.ts +2 -0
  45. package/dist/webhook/webhook.d.ts +38 -0
  46. package/package.json +58 -0
@@ -0,0 +1,121 @@
1
+ import type { PurposeValue } from '../purpose';
2
+ /**
3
+ * Wire-level types per [00-core/protocol.md](../../../00-core/protocol.md)
4
+ * and [00-core/schemas.md](../../../00-core/schemas.md).
5
+ *
6
+ * Body-type-specific shapes (handshake / contract / delegation / receipt
7
+ * / etc.) live alongside their handlers in the consumer code — keeping
8
+ * them out of this file avoids the SDK becoming a kitchen-sink of every
9
+ * message type. A consumer who needs typed bodies can extend `Envelope<T>`
10
+ * with their own `T extends Body`.
11
+ */
12
+ /** Hash string in protocol format `sha256:<64-char hex>`. */
13
+ export type Sha256Hex = `sha256:${string}`;
14
+ /** Ed25519 signature in protocol format `ed25519:<base64>`. */
15
+ export type Ed25519Sig = `ed25519:${string}`;
16
+ /** DID format `did:arp:<base58btc>`. */
17
+ export type Did = `did:arp:${string}`;
18
+ /**
19
+ * Client-signed `protected` block. All fields here are part of the
20
+ * signing input. Server-assigned chain fields (`relationship_event_index`,
21
+ * `prev_server_event_hash`) live OUTSIDE this block — clients MUST NOT
22
+ * sign them.
23
+ */
24
+ export interface ProtectedBlock {
25
+ protocol_version: 'arp/0.1';
26
+ purpose: PurposeValue;
27
+ message_id: string;
28
+ sender_did: Did;
29
+ recipient_did: Did;
30
+ /** UUID v4; null only on the first handshake. */
31
+ relationship_id: string | null;
32
+ sender_sequence: number;
33
+ sender_nonce: string;
34
+ timestamp: string;
35
+ expires_at: string;
36
+ body_hash: Sha256Hex;
37
+ attachments_hash: Sha256Hex | null;
38
+ delivery_id: string | null;
39
+ }
40
+ /** Body shape — `type` discriminator + per-type `content`. */
41
+ export interface Body<TContent = Record<string, unknown>> {
42
+ type: string;
43
+ content: TContent;
44
+ }
45
+ /**
46
+ * Optional attachments. Three top-level fields are SDK-aware:
47
+ * `co_signature` (semantic intent), `settlement_signatures`
48
+ * (financial authorisation), and `escrow_lock` (`delegation.offer`
49
+ * carries a pre-signed `create_lock` Solana tx). Other body-specific
50
+ * attachments live under their own keys and are passed through
51
+ * opaquely.
52
+ */
53
+ export interface Attachments {
54
+ co_signature?: CoSignature;
55
+ settlement_signatures?: SettlementSignatures;
56
+ escrow_lock?: EscrowLockAttachment;
57
+ [other: string]: unknown;
58
+ }
59
+ /**
60
+ * Attached by `delegation.offer` envelopes when the payer (the offer
61
+ * sender) wants to fund the lock as part of the same envelope.
62
+ *
63
+ * - `signed_tx_blob` is the base64-encoded full Solana tx with the
64
+ * payer's settlement key already a tx-level signer.
65
+ * - `lock_id` is the deterministic-from-delegation_id hex32, used
66
+ * for the server's idempotency-key check (server independently
67
+ * derives the same id via `deriveLockId`).
68
+ * - `amount` is the base-unit amount (decimal-as-string); must
69
+ * equal `toBaseUnits(body.content.amount, currency.decimals)`.
70
+ * - `asset_id` is the CAIP-19 currency the lock holds; must equal
71
+ * `body.content.currency.asset_id` (defence-in-depth).
72
+ * - `expiry` is the on-chain unix-seconds expiry; must satisfy the
73
+ * contract's MIN/MAX windows AND the spec's
74
+ * `deadline + DISPUTE_BUFFER` constraint.
75
+ *
76
+ * Server validation in `EnvelopeValidator` decodes the tx blob via
77
+ * Anchor IDL and cross-checks every field against the envelope body.
78
+ */
79
+ export interface EscrowLockAttachment {
80
+ signed_tx_blob: string;
81
+ lock_id: string;
82
+ amount: string;
83
+ asset_id: string;
84
+ expiry: number;
85
+ }
86
+ export interface CoSignature {
87
+ agent_did: Did;
88
+ purpose: PurposeValue;
89
+ payload_hash: Sha256Hex;
90
+ sig: Ed25519Sig;
91
+ }
92
+ export interface SettlementSignatures {
93
+ purpose: PurposeValue;
94
+ payer: SettlementParty;
95
+ payee: SettlementParty;
96
+ expires_at: number;
97
+ }
98
+ export interface SettlementParty {
99
+ settlement_pubkey: string;
100
+ sig: Ed25519Sig;
101
+ }
102
+ /** Top-level envelope as it appears on the wire. */
103
+ export interface Envelope<TBody extends Body = Body> {
104
+ protected: ProtectedBlock;
105
+ body: TBody;
106
+ attachments?: Attachments;
107
+ sender_signature: Ed25519Sig;
108
+ }
109
+ /**
110
+ * Server-side projection of an accepted event. Adds chain fields
111
+ * (server-assigned, NOT in signing input). Returned by the ingestion
112
+ * endpoint and persisted on the events table.
113
+ */
114
+ export interface PersistedEvent<TBody extends Body = Body> extends Envelope<TBody> {
115
+ event_id: string;
116
+ relationship_event_index: number;
117
+ prev_server_event_hash: string | null;
118
+ server_event_hash: string;
119
+ signed_message_hash: string;
120
+ server_timestamp: string;
121
+ }
@@ -0,0 +1,62 @@
1
+ import type { KeyMode } from '../did';
2
+ import type { Did } from './envelope';
3
+ /**
4
+ * Owner attestation methods per [00-core/identity.md](../../../00-core/identity.md).
5
+ *
6
+ * V1 ships `scrypt_password_proof` only; the others are reserved
7
+ * placeholders for forward-compat (V1.5 / V2).
8
+ */
9
+ export type OwnerSigningMethod = 'scrypt_password_proof' | 'ed25519_owner_key' | 'totp+passphrase';
10
+ /**
11
+ * `ARP-KEY-LINK-v1` payload — the canonical-JSON-hashed object an owner
12
+ * signs at registration. Carries the link between identity and settlement
13
+ * keys plus owner identity / method metadata.
14
+ */
15
+ export interface KeyLinkPayload {
16
+ purpose: 'ARP-KEY-LINK-v1';
17
+ agent_did: Did;
18
+ identity_public_key: string;
19
+ settlement_public_key: string;
20
+ key_mode: KeyMode;
21
+ owner_id: string;
22
+ owner_signing_method: OwnerSigningMethod;
23
+ link_method: 'manual' | 'imported' | 'derived_bip39';
24
+ created_at: string;
25
+ nonce: string;
26
+ }
27
+ /**
28
+ * `ARP-KEY-ROTATION-v1` payload — separate purpose from KEY-LINK
29
+ * because rotation breaks the `agent_did = base58btc(identity_pubkey)`
30
+ * invariant. Agent DID stays frozen; identity_public_key changes.
31
+ */
32
+ export interface KeyRotationPayload {
33
+ purpose: 'ARP-KEY-ROTATION-v1';
34
+ agent_did: Did;
35
+ current_identity_public_key: string;
36
+ new_identity_public_key: string;
37
+ settlement_public_key: string;
38
+ supersedes_attestation_id: string;
39
+ owner_id: string;
40
+ owner_signing_method: OwnerSigningMethod;
41
+ rotation_reason: 'scheduled' | 'compromise' | 'lost_device' | 'other';
42
+ created_at: string;
43
+ nonce: string;
44
+ }
45
+ /**
46
+ * `scrypt_password_proof` — the V1 owner attestation envelope. The
47
+ * signature is HMAC-SHA256(scrypt(password, salt), sha256(canonical(payload))),
48
+ * base64-encoded. NOT an Ed25519 signature; verification is
49
+ * server-side via the stored scrypt-derived key.
50
+ */
51
+ export interface ScryptPasswordAttestation<TPayload extends KeyLinkPayload | KeyRotationPayload = KeyLinkPayload> {
52
+ payload: TPayload;
53
+ sig: string;
54
+ scrypt_salt_id: string;
55
+ }
56
+ /** Standard scrypt parameters used for owner password proofs (V1). */
57
+ export declare const SCRYPT_PARAMS: {
58
+ readonly N: 32768;
59
+ readonly r: 8;
60
+ readonly p: 1;
61
+ readonly dkLen: 32;
62
+ };
@@ -0,0 +1,5 @@
1
+ export type { Sha256Hex, Ed25519Sig, Did, ProtectedBlock, Body, Attachments, CoSignature, SettlementSignatures, SettlementParty, EscrowLockAttachment, Envelope, PersistedEvent, } from './envelope';
2
+ export type { HandshakeBody, HandshakeContent, HandshakeResponseBody, HandshakeResponseContent, ContractBody, ContractContent, DelegationBody, DelegationContent, WorkRequestBody, WorkRequestContent, WorkResponseBody, WorkResponseContent, ReceiptBody, ReceiptContent, MemoryDeltaBody, MemoryDeltaContent, DisputeBody, DisputeContent, AnyBody, ReceiptCosignPayload, DisputeResponseCosignPayload, CosignPayload, DeclineReason, AssetIdentifier, } from './body';
3
+ export { DECLINE_REASONS, isDeclineReason } from './body';
4
+ export type { OwnerSigningMethod, KeyLinkPayload, KeyRotationPayload, ScryptPasswordAttestation } from './identity';
5
+ export { SCRYPT_PARAMS } from './identity';
@@ -0,0 +1,3 @@
1
+ export { uuidV4 } from './uuid';
2
+ export { senderNonce } from './nonce';
3
+ export { rfc3339, expiresAt } from './timestamp';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Generate a 16-byte random nonce, base64url-encoded without padding.
3
+ *
4
+ * Used in `protected.sender_nonce` and inside attestation payloads
5
+ * (`ARP-KEY-LINK-v1`, `ARP-KEY-ROTATION-v1`) to defend against
6
+ * accidental hash collisions and replay where two semantically
7
+ * distinct messages would otherwise hash to the same value.
8
+ */
9
+ export declare function senderNonce(): string;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Format a `Date` (or now) as RFC 3339 / ISO 8601 in UTC with second
3
+ * precision — matches `protected.timestamp` and `protected.expires_at`
4
+ * format expected by the protocol verifier.
5
+ *
6
+ * Intentional choices:
7
+ * - second precision (no `.SSS` milliseconds), matching how server
8
+ * timestamps render in audit logs / state machines
9
+ * - explicit `Z` suffix for UTC, no offset notation
10
+ */
11
+ export declare function rfc3339(at?: Date): string;
12
+ /**
13
+ * `expires_at` derived as `now + ttlSeconds`. The protocol caps
14
+ * envelope validity at 24 hours; callers who pass a longer TTL get
15
+ * a hard error rather than a silently-truncated value.
16
+ */
17
+ export declare function expiresAt(ttlSeconds: number, now?: Date): string;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * RFC 4122 UUID v4 generator.
3
+ *
4
+ * The protocol uses UUIDv4 for `message_id`, `relationship_id`,
5
+ * `challenge_id`, etc. Implemented locally rather than via
6
+ * `crypto.randomUUID()` so the SDK stays portable across environments
7
+ * that don't expose the global `crypto` (older runtimes, WebWorkers
8
+ * without crypto polyfills).
9
+ */
10
+ export declare function uuidV4(): string;
@@ -0,0 +1,2 @@
1
+ export { buildWebhookSignatureHeader, verifyWebhookSignatureHeader } from './webhook';
2
+ export type { WebhookSignableInput } from './webhook';
@@ -0,0 +1,38 @@
1
+ /**
2
+ * `ARP-WEBHOOK-v1` HMAC over the canonical webhook envelope. Used by
3
+ * the OutboxDeliveryWorker for the `X-ARP-Signature` header.
4
+ *
5
+ * Inputs (per backend's outbox spec):
6
+ * - delivery_id — outbox row id
7
+ * - recipient_did
8
+ * - envelope_message_id — envelope being delivered
9
+ * - server_event_hash — chain head at delivery time
10
+ * - attempt_n — 1-based retry counter
11
+ * - served_at — RFC3339, when this attempt was generated
12
+ *
13
+ * Each retry produces a different MAC because `attempt_n` and
14
+ * `served_at` participate in canonical input — replays of an old
15
+ * header on a fresh attempt fail HMAC verification.
16
+ */
17
+ export interface WebhookSignableInput {
18
+ delivery_id: string;
19
+ recipient_did: string;
20
+ envelope_message_id: string;
21
+ server_event_hash: string;
22
+ attempt_n: number;
23
+ served_at: string;
24
+ }
25
+ /**
26
+ * Compute `X-ARP-Signature` value: `<purpose>=<base64(HMAC-SHA256(secret, sha256(canonical_json(input))))>`.
27
+ *
28
+ * Recipients lookup their per-sender shared secret, recompute the
29
+ * HMAC over the same canonical input, and compare against the
30
+ * received header.
31
+ */
32
+ export declare function buildWebhookSignatureHeader(input: WebhookSignableInput, sharedSecret: Uint8Array): string;
33
+ /**
34
+ * Constant-time compare an inbound `X-ARP-Signature` header against
35
+ * the expected one. Returns `false` on shape mismatch, missing
36
+ * purpose label, or HMAC mismatch — never throws.
37
+ */
38
+ export declare function verifyWebhookSignatureHeader(headerValue: string, input: WebhookSignableInput, sharedSecret: Uint8Array): boolean;
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@heyanon-arp/sdk",
3
+ "version": "0.0.2",
4
+ "description": "TypeScript SDK for the Agent Relationship Protocol — canonical JSON, Ed25519 envelope sign/verify, did:arp identity, receipt co-signatures, scrypt key attestation, chain-audit helpers.",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "arp",
8
+ "agent-relationship-protocol",
9
+ "did",
10
+ "ed25519",
11
+ "jcs",
12
+ "canonical-json",
13
+ "envelope",
14
+ "cosignature",
15
+ "a2a"
16
+ ],
17
+ "main": "dist/index.js",
18
+ "module": "dist/index.mjs",
19
+ "types": "dist/index.d.ts",
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.mjs",
27
+ "require": "./dist/index.js"
28
+ }
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "LICENSE",
33
+ "README.md"
34
+ ],
35
+ "engines": {
36
+ "node": ">=22"
37
+ },
38
+ "dependencies": {
39
+ "@noble/ed25519": "^2.1.0",
40
+ "@noble/hashes": "^1.5.0",
41
+ "@scure/base": "^1.1.9",
42
+ "canonicalize": "^2.0.0"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^22.10.7",
46
+ "tslib": "^2.6.2",
47
+ "tsup": "^8.3.5",
48
+ "typescript": "^5.5.4",
49
+ "vitest": "^2.1.8"
50
+ },
51
+ "scripts": {
52
+ "build": "tsup",
53
+ "start": "tsup --watch",
54
+ "test": "vitest --run",
55
+ "test:watch": "vitest",
56
+ "lint": "biome check . --write"
57
+ }
58
+ }