@orangecheck/agent-core 0.1.0 → 0.3.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/dist/canonical.d.mts +5 -2
- package/dist/canonical.d.ts +5 -2
- package/dist/canonical.js +22 -0
- package/dist/canonical.js.map +1 -1
- package/dist/canonical.mjs +20 -1
- package/dist/canonical.mjs.map +1 -1
- package/dist/index.d.mts +60 -5
- package/dist/index.d.ts +60 -5
- package/dist/index.js +356 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +347 -30
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.mts +65 -4
- package/dist/types.d.ts +65 -4
- package/dist/types.js.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +73 -69
- package/src/canonical.ts +23 -0
- package/src/index.ts +18 -0
- package/src/private-scope.test.ts +223 -0
- package/src/private-scope.ts +122 -0
- package/src/test-vectors.test.ts +358 -12
- package/src/types.ts +109 -4
- package/src/verify.ts +487 -40
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
declare const ENVELOPE_VERSION: 1;
|
|
2
|
-
type EnvelopeKind = 'agent-delegation' | 'agent-action' | 'agent-revocation';
|
|
2
|
+
type EnvelopeKind = 'agent-delegation' | 'agent-action' | 'agent-revocation' | 'agent-subdelegation';
|
|
3
3
|
interface ActorRef {
|
|
4
4
|
address: string;
|
|
5
5
|
alg: 'bip322';
|
|
@@ -18,13 +18,47 @@ interface DelegationRevocationRef {
|
|
|
18
18
|
holders: RevocationHolder[];
|
|
19
19
|
ref: string | null;
|
|
20
20
|
}
|
|
21
|
+
interface ScopesEncryptedEnvelope {
|
|
22
|
+
v: 2;
|
|
23
|
+
kind: 'identity';
|
|
24
|
+
id: string;
|
|
25
|
+
alg: {
|
|
26
|
+
kem: 'x25519';
|
|
27
|
+
aead: 'aes-256-gcm';
|
|
28
|
+
kdf: 'hkdf-sha256';
|
|
29
|
+
};
|
|
30
|
+
from: {
|
|
31
|
+
address: string;
|
|
32
|
+
attestation_id?: string;
|
|
33
|
+
};
|
|
34
|
+
recipients: Array<{
|
|
35
|
+
address: string;
|
|
36
|
+
device_id: string;
|
|
37
|
+
device_pk: string;
|
|
38
|
+
eph_pk: string;
|
|
39
|
+
wrapped_key: string;
|
|
40
|
+
nonce_kek: string;
|
|
41
|
+
}>;
|
|
42
|
+
ciphertext: string;
|
|
43
|
+
nonce_ct: string;
|
|
44
|
+
hint?: string;
|
|
45
|
+
created_at: string;
|
|
46
|
+
expires_at: string | null;
|
|
47
|
+
payment: unknown | null;
|
|
48
|
+
sig: {
|
|
49
|
+
alg: 'bip322';
|
|
50
|
+
pubkey: string;
|
|
51
|
+
value: string;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
21
54
|
interface DelegationEnvelope {
|
|
22
55
|
v: typeof ENVELOPE_VERSION;
|
|
23
56
|
kind: 'agent-delegation';
|
|
24
57
|
id: string;
|
|
25
58
|
principal: ActorRef;
|
|
26
59
|
agent: ActorRef;
|
|
27
|
-
scopes
|
|
60
|
+
scopes?: string[];
|
|
61
|
+
scopes_encrypted?: ScopesEncryptedEnvelope;
|
|
28
62
|
bond: DelegationBond | null;
|
|
29
63
|
issued_at: string;
|
|
30
64
|
expires_at: string;
|
|
@@ -77,6 +111,31 @@ interface ActionCanonicalInput {
|
|
|
77
111
|
delegation_id: string;
|
|
78
112
|
scope_exercised: string;
|
|
79
113
|
}
|
|
114
|
+
interface SubdelegationEnvelope {
|
|
115
|
+
v: typeof ENVELOPE_VERSION;
|
|
116
|
+
kind: 'agent-subdelegation';
|
|
117
|
+
id: string;
|
|
118
|
+
parent_id: string;
|
|
119
|
+
principal: ActorRef;
|
|
120
|
+
agent: ActorRef;
|
|
121
|
+
scopes?: string[];
|
|
122
|
+
scopes_encrypted?: ScopesEncryptedEnvelope;
|
|
123
|
+
issued_at: string;
|
|
124
|
+
expires_at: string;
|
|
125
|
+
nonce: string;
|
|
126
|
+
revocation: DelegationRevocationRef;
|
|
127
|
+
sig: Signature;
|
|
128
|
+
}
|
|
129
|
+
interface SubdelegationCanonicalInput {
|
|
130
|
+
parent_id: string;
|
|
131
|
+
principal: string;
|
|
132
|
+
agent: string;
|
|
133
|
+
scopes: string[];
|
|
134
|
+
issued_at: string;
|
|
135
|
+
expires_at: string;
|
|
136
|
+
nonce: string;
|
|
137
|
+
}
|
|
138
|
+
type ChainLink = DelegationEnvelope | SubdelegationEnvelope;
|
|
80
139
|
interface RevocationEnvelope {
|
|
81
140
|
v: typeof ENVELOPE_VERSION;
|
|
82
141
|
kind: 'agent-revocation';
|
|
@@ -94,7 +153,7 @@ interface RevocationCanonicalInput {
|
|
|
94
153
|
reason: string;
|
|
95
154
|
signed_at: string;
|
|
96
155
|
}
|
|
97
|
-
type AgentErrorCode = 'E_UNSUPPORTED_VERSION' | 'E_MALFORMED' | 'E_BAD_ID' | 'E_BAD_SIG' | 'E_BAD_SCOPE_GRAMMAR' | 'E_NOT_YET_VALID' | 'E_EXPIRED' | 'E_REVOKED' | 'E_DELEGATION_MISMATCH' | 'E_AGENT_MISMATCH' | 'E_OUT_OF_WINDOW' | 'E_SCOPE_DENIED' | 'E_BAD_ACTION_STAMP' | 'E_NO_BOND' | 'E_BOND_UNMET' | 'E_BOND_UNVERIFIED' | 'E_REVOKER_UNAUTHORIZED' | 'E_CALENDAR_UNREACHABLE';
|
|
156
|
+
type AgentErrorCode = 'E_UNSUPPORTED_VERSION' | 'E_MALFORMED' | 'E_BAD_ID' | 'E_BAD_SIG' | 'E_BAD_SCOPE_GRAMMAR' | 'E_NOT_YET_VALID' | 'E_EXPIRED' | 'E_REVOKED' | 'E_DELEGATION_MISMATCH' | 'E_AGENT_MISMATCH' | 'E_OUT_OF_WINDOW' | 'E_SCOPE_DENIED' | 'E_BAD_ACTION_STAMP' | 'E_NO_BOND' | 'E_BOND_UNMET' | 'E_BOND_UNVERIFIED' | 'E_REVOKER_UNAUTHORIZED' | 'E_CALENDAR_UNREACHABLE' | 'E_SUBDELEGATION_DEPTH_EXCEEDED' | 'E_SUBDELEGATION_PRINCIPAL_MISMATCH' | 'E_SUBDELEGATION_EXPIRES_EXTENDED' | 'E_SUBDELEGATION_SCOPE_ESCALATED' | 'E_SCOPES_BOTH_PROVIDED' | 'E_SCOPES_NEITHER_PROVIDED' | 'E_SCOPES_UNREADABLE' | 'E_BAD_LOCK_ENVELOPE';
|
|
98
157
|
interface VerifyOk<T> {
|
|
99
158
|
ok: true;
|
|
100
159
|
envelope: T;
|
|
@@ -108,8 +167,10 @@ interface VerifyErr {
|
|
|
108
167
|
}
|
|
109
168
|
type VerifyDelegationResult = VerifyOk<DelegationEnvelope> | VerifyErr;
|
|
110
169
|
type VerifyRevocationResult = VerifyOk<RevocationEnvelope> | VerifyErr;
|
|
170
|
+
type VerifySubdelegationResult = VerifyOk<SubdelegationEnvelope> | VerifyErr;
|
|
111
171
|
interface VerifyActionOkExtra {
|
|
112
172
|
delegation: DelegationEnvelope;
|
|
173
|
+
chain: SubdelegationEnvelope[];
|
|
113
174
|
scopeExercised: string;
|
|
114
175
|
anchor: {
|
|
115
176
|
status: 'none';
|
|
@@ -124,4 +185,4 @@ interface VerifyActionOkExtra {
|
|
|
124
185
|
}
|
|
125
186
|
type VerifyActionResult = (VerifyOk<ActionEnvelope> & VerifyActionOkExtra) | VerifyErr;
|
|
126
187
|
|
|
127
|
-
export { type ActionCanonicalInput, type ActionContent, type ActionEnvelope, type ActionOts, type ActorRef, type AgentErrorCode, type DelegationBond, type DelegationCanonicalInput, type DelegationEnvelope, type DelegationRevocationRef, ENVELOPE_VERSION, type EnvelopeKind, type RevocationCanonicalInput, type RevocationEnvelope, type RevocationHolder, type Signature, type VerifyActionOkExtra, type VerifyActionResult, type VerifyDelegationResult, type VerifyErr, type VerifyOk, type VerifyRevocationResult };
|
|
188
|
+
export { type ActionCanonicalInput, type ActionContent, type ActionEnvelope, type ActionOts, type ActorRef, type AgentErrorCode, type ChainLink, type DelegationBond, type DelegationCanonicalInput, type DelegationEnvelope, type DelegationRevocationRef, ENVELOPE_VERSION, type EnvelopeKind, type RevocationCanonicalInput, type RevocationEnvelope, type RevocationHolder, type ScopesEncryptedEnvelope, type Signature, type SubdelegationCanonicalInput, type SubdelegationEnvelope, type VerifyActionOkExtra, type VerifyActionResult, type VerifyDelegationResult, type VerifyErr, type VerifyOk, type VerifyRevocationResult, type VerifySubdelegationResult };
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"names":[],"mappings":";;;AAEO,IAAM,gBAAA,GAAmB","file":"types.js","sourcesContent":["// Wire types for OC Agent v1 envelopes. See SPEC.md §4, §5, §9.\n\nexport const ENVELOPE_VERSION = 1 as const;\n\nexport type EnvelopeKind
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"names":[],"mappings":";;;AAEO,IAAM,gBAAA,GAAmB","file":"types.js","sourcesContent":["// Wire types for OC Agent v1 envelopes. See SPEC.md §4, §5, §9.\n\nexport const ENVELOPE_VERSION = 1 as const;\n\nexport type EnvelopeKind =\n | 'agent-delegation'\n | 'agent-action'\n | 'agent-revocation'\n | 'agent-subdelegation';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Shared building blocks\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ActorRef {\n /** mainnet Bitcoin address (P2WPKH, P2TR, or P2PKH). */\n address: string;\n alg: 'bip322';\n}\n\nexport interface Signature {\n alg: 'bip322';\n pubkey: string; // equals the producing actor's address\n value: string; // base64 BIP-322 signature over hex(id)\n}\n\nexport type RevocationHolder = 'principal' | 'agent';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Delegation (SPEC §4)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface DelegationBond {\n /** Non-negative sats declared as bonded at issuance time. */\n sats: number;\n /** SHA-256 hex of the OrangeCheck canonical message signed by principal.address. */\n attestation_id: string;\n}\n\nexport interface DelegationRevocationRef {\n /** Who MAY publish a revocation. Default [\"principal\"]. */\n holders: RevocationHolder[];\n /** Optional Nostr-addressable pointer to a published revocation. Non-cryptographic. */\n ref: string | null;\n}\n\n/**\n * v1.2 private-scope mode: a wholesale OC Lock v2 LockEnvelope wrapping the\n * canonical scope list as its payload. We re-import the LockEnvelope type\n * structurally rather than depending on the @orangecheck/lock-core type — agent-\n * core's type surface stays loose so verifiers can be authored in either an\n * agent-only or full-family setup.\n */\nexport interface ScopesEncryptedEnvelope {\n v: 2;\n kind: 'identity';\n id: string;\n alg: { kem: 'x25519'; aead: 'aes-256-gcm'; kdf: 'hkdf-sha256' };\n from: { address: string; attestation_id?: string };\n recipients: Array<{\n address: string;\n device_id: string;\n device_pk: string;\n eph_pk: string;\n wrapped_key: string;\n nonce_kek: string;\n }>;\n ciphertext: string;\n nonce_ct: string;\n hint?: string;\n created_at: string;\n expires_at: string | null;\n payment: unknown | null;\n sig: { alg: 'bip322'; pubkey: string; value: string };\n}\n\nexport interface DelegationEnvelope {\n v: typeof ENVELOPE_VERSION;\n kind: 'agent-delegation';\n id: string; // 64-hex sha256(canonical_message)\n principal: ActorRef;\n agent: ActorRef;\n /**\n * v1.0 / v1.1 public mode: sorted lexicographically in the canonical\n * message; stored in sorted order on the envelope too.\n *\n * v1.2 private mode: this field is OMITTED from the envelope JSON;\n * `scopes_encrypted` is set instead. After decryption, the recovered\n * scope list takes this field's place in the in-memory envelope object\n * for the remainder of verification.\n */\n scopes?: string[];\n /**\n * v1.2 private mode (PRIVATE-SCOPE.md §1.1): an OC Lock v2 envelope\n * wrapping the canonical scope-list bytes as its payload, sealed to one\n * or more recipients (typically the agent ± named verifiers). MUTUALLY\n * EXCLUSIVE with `scopes`.\n */\n scopes_encrypted?: ScopesEncryptedEnvelope;\n bond: DelegationBond | null;\n issued_at: string; // ISO 8601 UTC\n expires_at: string; // ISO 8601 UTC\n nonce: string; // 32-hex random\n revocation: DelegationRevocationRef;\n sig: Signature;\n}\n\nexport interface DelegationCanonicalInput {\n principal: string;\n agent: string;\n scopes: string[]; // pre-canonicalized, pre-sorted\n bond_sats: number;\n /** 64-hex attestation id or the literal string \"none\". */\n bond_attestation: string;\n issued_at: string;\n expires_at: string;\n nonce: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Agent-action (SPEC §5) — strict extension of OC Stamp\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ActionContent {\n hash: string; // \"sha256:<64-hex>\"\n length: number;\n mime: string;\n ref: string | null;\n}\n\nexport interface ActionOts {\n status: 'pending' | 'confirmed';\n proof: string;\n calendars: string[];\n block_height: number | null;\n block_hash: string | null;\n upgraded_at: string | null;\n}\n\nexport interface ActionEnvelope {\n v: typeof ENVELOPE_VERSION;\n kind: 'agent-action';\n id: string;\n content: ActionContent;\n signer: ActorRef; // agent\n signed_at: string;\n delegation_id: string; // 64-hex\n scope_exercised: string; // a sub-scope of some granted scope\n ots: ActionOts | null;\n sig: Signature;\n}\n\nexport interface ActionCanonicalInput {\n address: string; // agent address\n content_hash: string;\n content_length: number;\n content_mime: string;\n signed_at: string;\n delegation_id: string;\n scope_exercised: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Sub-delegation (SUB-DELEGATION.md, v1.1)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SubdelegationEnvelope {\n v: typeof ENVELOPE_VERSION;\n kind: 'agent-subdelegation';\n id: string; // 64-hex sha256(canonical_message)\n parent_id: string; // 64-hex; the immediate parent envelope's id\n /** The sub-principal — equal to parent.agent.address. */\n principal: ActorRef;\n /** The recipient sub-agent. */\n agent: ActorRef;\n /**\n * v1.0 / v1.1 public mode: each scope MUST be a sub-scope of some scope\n * on the parent. v1.2 private mode: omitted; `scopes_encrypted` set.\n */\n scopes?: string[];\n /** v1.2 private mode — same shape as the root delegation field. */\n scopes_encrypted?: ScopesEncryptedEnvelope;\n issued_at: string; // ISO 8601 UTC; >= parent.issued_at\n expires_at: string; // ISO 8601 UTC; <= parent.expires_at\n nonce: string; // 32-hex random\n revocation: DelegationRevocationRef;\n sig: Signature;\n}\n\nexport interface SubdelegationCanonicalInput {\n parent_id: string;\n principal: string;\n agent: string;\n scopes: string[]; // pre-canonicalized, pre-sorted\n issued_at: string;\n expires_at: string;\n nonce: string;\n}\n\n/** Either a root or a sub envelope; chain links walk up to a root delegation. */\nexport type ChainLink = DelegationEnvelope | SubdelegationEnvelope;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Revocation (SPEC §9)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface RevocationEnvelope {\n v: typeof ENVELOPE_VERSION;\n kind: 'agent-revocation';\n id: string;\n delegation_id: string;\n signer: ActorRef;\n /** Short ASCII rationale, <= 128 bytes. Empty string if omitted. */\n reason: string;\n signed_at: string;\n ots: ActionOts | null;\n sig: Signature;\n}\n\nexport interface RevocationCanonicalInput {\n address: string;\n delegation_id: string;\n reason: string;\n signed_at: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Error codes (SPEC §11)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type AgentErrorCode =\n | 'E_UNSUPPORTED_VERSION'\n | 'E_MALFORMED'\n | 'E_BAD_ID'\n | 'E_BAD_SIG'\n | 'E_BAD_SCOPE_GRAMMAR'\n | 'E_NOT_YET_VALID'\n | 'E_EXPIRED'\n | 'E_REVOKED'\n | 'E_DELEGATION_MISMATCH'\n | 'E_AGENT_MISMATCH'\n | 'E_OUT_OF_WINDOW'\n | 'E_SCOPE_DENIED'\n | 'E_BAD_ACTION_STAMP'\n | 'E_NO_BOND'\n | 'E_BOND_UNMET'\n | 'E_BOND_UNVERIFIED'\n | 'E_REVOKER_UNAUTHORIZED'\n | 'E_CALENDAR_UNREACHABLE'\n | 'E_SUBDELEGATION_DEPTH_EXCEEDED'\n | 'E_SUBDELEGATION_PRINCIPAL_MISMATCH'\n | 'E_SUBDELEGATION_EXPIRES_EXTENDED'\n | 'E_SUBDELEGATION_SCOPE_ESCALATED'\n | 'E_SCOPES_BOTH_PROVIDED'\n | 'E_SCOPES_NEITHER_PROVIDED'\n | 'E_SCOPES_UNREADABLE'\n | 'E_BAD_LOCK_ENVELOPE';\n\nexport interface VerifyOk<T> {\n ok: true;\n envelope: T;\n canonicalMessage: string;\n id: string;\n}\n\nexport interface VerifyErr {\n ok: false;\n code: AgentErrorCode;\n message: string;\n}\n\nexport type VerifyDelegationResult = VerifyOk<DelegationEnvelope> | VerifyErr;\nexport type VerifyRevocationResult = VerifyOk<RevocationEnvelope> | VerifyErr;\nexport type VerifySubdelegationResult = VerifyOk<SubdelegationEnvelope> | VerifyErr;\n\nexport interface VerifyActionOkExtra {\n /** The ROOT delegation rooting the authority chain. */\n delegation: DelegationEnvelope;\n /**\n * The sub-delegation chain `[S_1, …, S_leaf]`. Empty when the action cites\n * the root directly. The action's authority leaf is\n * `chain[chain.length - 1] ?? delegation`.\n */\n chain: SubdelegationEnvelope[];\n scopeExercised: string;\n anchor:\n | { status: 'none' }\n | { status: 'pending' }\n | { status: 'confirmed'; blockHeight: number; blockHash: string; verified: boolean };\n}\n\nexport type VerifyActionResult =\n | (VerifyOk<ActionEnvelope> & VerifyActionOkExtra)\n | VerifyErr;\n"]}
|
package/dist/types.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"names":[],"mappings":";AAEO,IAAM,gBAAA,GAAmB","file":"types.mjs","sourcesContent":["// Wire types for OC Agent v1 envelopes. See SPEC.md §4, §5, §9.\n\nexport const ENVELOPE_VERSION = 1 as const;\n\nexport type EnvelopeKind
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"names":[],"mappings":";AAEO,IAAM,gBAAA,GAAmB","file":"types.mjs","sourcesContent":["// Wire types for OC Agent v1 envelopes. See SPEC.md §4, §5, §9.\n\nexport const ENVELOPE_VERSION = 1 as const;\n\nexport type EnvelopeKind =\n | 'agent-delegation'\n | 'agent-action'\n | 'agent-revocation'\n | 'agent-subdelegation';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Shared building blocks\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ActorRef {\n /** mainnet Bitcoin address (P2WPKH, P2TR, or P2PKH). */\n address: string;\n alg: 'bip322';\n}\n\nexport interface Signature {\n alg: 'bip322';\n pubkey: string; // equals the producing actor's address\n value: string; // base64 BIP-322 signature over hex(id)\n}\n\nexport type RevocationHolder = 'principal' | 'agent';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Delegation (SPEC §4)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface DelegationBond {\n /** Non-negative sats declared as bonded at issuance time. */\n sats: number;\n /** SHA-256 hex of the OrangeCheck canonical message signed by principal.address. */\n attestation_id: string;\n}\n\nexport interface DelegationRevocationRef {\n /** Who MAY publish a revocation. Default [\"principal\"]. */\n holders: RevocationHolder[];\n /** Optional Nostr-addressable pointer to a published revocation. Non-cryptographic. */\n ref: string | null;\n}\n\n/**\n * v1.2 private-scope mode: a wholesale OC Lock v2 LockEnvelope wrapping the\n * canonical scope list as its payload. We re-import the LockEnvelope type\n * structurally rather than depending on the @orangecheck/lock-core type — agent-\n * core's type surface stays loose so verifiers can be authored in either an\n * agent-only or full-family setup.\n */\nexport interface ScopesEncryptedEnvelope {\n v: 2;\n kind: 'identity';\n id: string;\n alg: { kem: 'x25519'; aead: 'aes-256-gcm'; kdf: 'hkdf-sha256' };\n from: { address: string; attestation_id?: string };\n recipients: Array<{\n address: string;\n device_id: string;\n device_pk: string;\n eph_pk: string;\n wrapped_key: string;\n nonce_kek: string;\n }>;\n ciphertext: string;\n nonce_ct: string;\n hint?: string;\n created_at: string;\n expires_at: string | null;\n payment: unknown | null;\n sig: { alg: 'bip322'; pubkey: string; value: string };\n}\n\nexport interface DelegationEnvelope {\n v: typeof ENVELOPE_VERSION;\n kind: 'agent-delegation';\n id: string; // 64-hex sha256(canonical_message)\n principal: ActorRef;\n agent: ActorRef;\n /**\n * v1.0 / v1.1 public mode: sorted lexicographically in the canonical\n * message; stored in sorted order on the envelope too.\n *\n * v1.2 private mode: this field is OMITTED from the envelope JSON;\n * `scopes_encrypted` is set instead. After decryption, the recovered\n * scope list takes this field's place in the in-memory envelope object\n * for the remainder of verification.\n */\n scopes?: string[];\n /**\n * v1.2 private mode (PRIVATE-SCOPE.md §1.1): an OC Lock v2 envelope\n * wrapping the canonical scope-list bytes as its payload, sealed to one\n * or more recipients (typically the agent ± named verifiers). MUTUALLY\n * EXCLUSIVE with `scopes`.\n */\n scopes_encrypted?: ScopesEncryptedEnvelope;\n bond: DelegationBond | null;\n issued_at: string; // ISO 8601 UTC\n expires_at: string; // ISO 8601 UTC\n nonce: string; // 32-hex random\n revocation: DelegationRevocationRef;\n sig: Signature;\n}\n\nexport interface DelegationCanonicalInput {\n principal: string;\n agent: string;\n scopes: string[]; // pre-canonicalized, pre-sorted\n bond_sats: number;\n /** 64-hex attestation id or the literal string \"none\". */\n bond_attestation: string;\n issued_at: string;\n expires_at: string;\n nonce: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Agent-action (SPEC §5) — strict extension of OC Stamp\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ActionContent {\n hash: string; // \"sha256:<64-hex>\"\n length: number;\n mime: string;\n ref: string | null;\n}\n\nexport interface ActionOts {\n status: 'pending' | 'confirmed';\n proof: string;\n calendars: string[];\n block_height: number | null;\n block_hash: string | null;\n upgraded_at: string | null;\n}\n\nexport interface ActionEnvelope {\n v: typeof ENVELOPE_VERSION;\n kind: 'agent-action';\n id: string;\n content: ActionContent;\n signer: ActorRef; // agent\n signed_at: string;\n delegation_id: string; // 64-hex\n scope_exercised: string; // a sub-scope of some granted scope\n ots: ActionOts | null;\n sig: Signature;\n}\n\nexport interface ActionCanonicalInput {\n address: string; // agent address\n content_hash: string;\n content_length: number;\n content_mime: string;\n signed_at: string;\n delegation_id: string;\n scope_exercised: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Sub-delegation (SUB-DELEGATION.md, v1.1)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SubdelegationEnvelope {\n v: typeof ENVELOPE_VERSION;\n kind: 'agent-subdelegation';\n id: string; // 64-hex sha256(canonical_message)\n parent_id: string; // 64-hex; the immediate parent envelope's id\n /** The sub-principal — equal to parent.agent.address. */\n principal: ActorRef;\n /** The recipient sub-agent. */\n agent: ActorRef;\n /**\n * v1.0 / v1.1 public mode: each scope MUST be a sub-scope of some scope\n * on the parent. v1.2 private mode: omitted; `scopes_encrypted` set.\n */\n scopes?: string[];\n /** v1.2 private mode — same shape as the root delegation field. */\n scopes_encrypted?: ScopesEncryptedEnvelope;\n issued_at: string; // ISO 8601 UTC; >= parent.issued_at\n expires_at: string; // ISO 8601 UTC; <= parent.expires_at\n nonce: string; // 32-hex random\n revocation: DelegationRevocationRef;\n sig: Signature;\n}\n\nexport interface SubdelegationCanonicalInput {\n parent_id: string;\n principal: string;\n agent: string;\n scopes: string[]; // pre-canonicalized, pre-sorted\n issued_at: string;\n expires_at: string;\n nonce: string;\n}\n\n/** Either a root or a sub envelope; chain links walk up to a root delegation. */\nexport type ChainLink = DelegationEnvelope | SubdelegationEnvelope;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Revocation (SPEC §9)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface RevocationEnvelope {\n v: typeof ENVELOPE_VERSION;\n kind: 'agent-revocation';\n id: string;\n delegation_id: string;\n signer: ActorRef;\n /** Short ASCII rationale, <= 128 bytes. Empty string if omitted. */\n reason: string;\n signed_at: string;\n ots: ActionOts | null;\n sig: Signature;\n}\n\nexport interface RevocationCanonicalInput {\n address: string;\n delegation_id: string;\n reason: string;\n signed_at: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Error codes (SPEC §11)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type AgentErrorCode =\n | 'E_UNSUPPORTED_VERSION'\n | 'E_MALFORMED'\n | 'E_BAD_ID'\n | 'E_BAD_SIG'\n | 'E_BAD_SCOPE_GRAMMAR'\n | 'E_NOT_YET_VALID'\n | 'E_EXPIRED'\n | 'E_REVOKED'\n | 'E_DELEGATION_MISMATCH'\n | 'E_AGENT_MISMATCH'\n | 'E_OUT_OF_WINDOW'\n | 'E_SCOPE_DENIED'\n | 'E_BAD_ACTION_STAMP'\n | 'E_NO_BOND'\n | 'E_BOND_UNMET'\n | 'E_BOND_UNVERIFIED'\n | 'E_REVOKER_UNAUTHORIZED'\n | 'E_CALENDAR_UNREACHABLE'\n | 'E_SUBDELEGATION_DEPTH_EXCEEDED'\n | 'E_SUBDELEGATION_PRINCIPAL_MISMATCH'\n | 'E_SUBDELEGATION_EXPIRES_EXTENDED'\n | 'E_SUBDELEGATION_SCOPE_ESCALATED'\n | 'E_SCOPES_BOTH_PROVIDED'\n | 'E_SCOPES_NEITHER_PROVIDED'\n | 'E_SCOPES_UNREADABLE'\n | 'E_BAD_LOCK_ENVELOPE';\n\nexport interface VerifyOk<T> {\n ok: true;\n envelope: T;\n canonicalMessage: string;\n id: string;\n}\n\nexport interface VerifyErr {\n ok: false;\n code: AgentErrorCode;\n message: string;\n}\n\nexport type VerifyDelegationResult = VerifyOk<DelegationEnvelope> | VerifyErr;\nexport type VerifyRevocationResult = VerifyOk<RevocationEnvelope> | VerifyErr;\nexport type VerifySubdelegationResult = VerifyOk<SubdelegationEnvelope> | VerifyErr;\n\nexport interface VerifyActionOkExtra {\n /** The ROOT delegation rooting the authority chain. */\n delegation: DelegationEnvelope;\n /**\n * The sub-delegation chain `[S_1, …, S_leaf]`. Empty when the action cites\n * the root directly. The action's authority leaf is\n * `chain[chain.length - 1] ?? delegation`.\n */\n chain: SubdelegationEnvelope[];\n scopeExercised: string;\n anchor:\n | { status: 'none' }\n | { status: 'pending' }\n | { status: 'confirmed'; blockHeight: number; blockHash: string; verified: boolean };\n}\n\nexport type VerifyActionResult =\n | (VerifyOk<ActionEnvelope> & VerifyActionOkExtra)\n | VerifyErr;\n"]}
|
package/package.json
CHANGED
|
@@ -1,75 +1,79 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
2
|
+
"name": "@orangecheck/agent-core",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "OC Agent canonical messages, envelope formats (delegation/action/revocation), scope grammar, and verification. See https://github.com/orangecheck/oc-agent-protocol.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"bitcoin",
|
|
7
|
+
"agent",
|
|
8
|
+
"authority",
|
|
9
|
+
"delegation",
|
|
10
|
+
"bip322",
|
|
11
|
+
"oc-agent",
|
|
12
|
+
"orangecheck"
|
|
13
|
+
],
|
|
14
|
+
"author": "OrangeCheck",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/orangecheck/oc-packages.git",
|
|
19
|
+
"directory": "agent-core"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/orangecheck/oc-agent-protocol",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/orangecheck/oc-agent-protocol/issues"
|
|
24
|
+
},
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"module": "./dist/index.mjs",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.mjs",
|
|
32
|
+
"require": "./dist/index.js"
|
|
20
33
|
},
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
34
|
+
"./canonical": {
|
|
35
|
+
"types": "./dist/canonical.d.ts",
|
|
36
|
+
"import": "./dist/canonical.mjs",
|
|
37
|
+
"require": "./dist/canonical.js"
|
|
24
38
|
},
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
".": {
|
|
30
|
-
"types": "./dist/index.d.ts",
|
|
31
|
-
"import": "./dist/index.mjs",
|
|
32
|
-
"require": "./dist/index.js"
|
|
33
|
-
},
|
|
34
|
-
"./canonical": {
|
|
35
|
-
"types": "./dist/canonical.d.ts",
|
|
36
|
-
"import": "./dist/canonical.mjs",
|
|
37
|
-
"require": "./dist/canonical.js"
|
|
38
|
-
},
|
|
39
|
-
"./scope": {
|
|
40
|
-
"types": "./dist/scope.d.ts",
|
|
41
|
-
"import": "./dist/scope.mjs",
|
|
42
|
-
"require": "./dist/scope.js"
|
|
43
|
-
},
|
|
44
|
-
"./types": {
|
|
45
|
-
"types": "./dist/types.d.ts",
|
|
46
|
-
"import": "./dist/types.mjs",
|
|
47
|
-
"require": "./dist/types.js"
|
|
48
|
-
}
|
|
39
|
+
"./scope": {
|
|
40
|
+
"types": "./dist/scope.d.ts",
|
|
41
|
+
"import": "./dist/scope.mjs",
|
|
42
|
+
"require": "./dist/scope.js"
|
|
49
43
|
},
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"LICENSE"
|
|
55
|
-
],
|
|
56
|
-
"scripts": {
|
|
57
|
-
"build": "tsup",
|
|
58
|
-
"dev": "tsup --watch",
|
|
59
|
-
"type-check": "tsc --noEmit",
|
|
60
|
-
"test": "vitest run",
|
|
61
|
-
"test:watch": "vitest",
|
|
62
|
-
"clean": "rm -rf dist",
|
|
63
|
-
"prepublishOnly": "npm run clean && npm run build"
|
|
64
|
-
},
|
|
65
|
-
"dependencies": {
|
|
66
|
-
"@noble/hashes": "^1.5.0",
|
|
67
|
-
"@orangecheck/stamp-core": "^0.1.1"
|
|
68
|
-
},
|
|
69
|
-
"devDependencies": {
|
|
70
|
-
"@types/node": "^22.10.2",
|
|
71
|
-
"tsup": "^8.3.5",
|
|
72
|
-
"typescript": "^5.7.2",
|
|
73
|
-
"vitest": "^3.2.4"
|
|
44
|
+
"./types": {
|
|
45
|
+
"types": "./dist/types.d.ts",
|
|
46
|
+
"import": "./dist/types.mjs",
|
|
47
|
+
"require": "./dist/types.js"
|
|
74
48
|
}
|
|
49
|
+
},
|
|
50
|
+
"files": [
|
|
51
|
+
"dist",
|
|
52
|
+
"src",
|
|
53
|
+
"README.md",
|
|
54
|
+
"LICENSE"
|
|
55
|
+
],
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsup",
|
|
58
|
+
"dev": "tsup --watch",
|
|
59
|
+
"type-check": "tsc --noEmit",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"test:watch": "vitest",
|
|
62
|
+
"clean": "rm -rf dist",
|
|
63
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
64
|
+
},
|
|
65
|
+
"dependencies": {
|
|
66
|
+
"@noble/hashes": "^1.5.0",
|
|
67
|
+
"@orangecheck/stamp-core": "^0.1.1",
|
|
68
|
+
"@orangecheck/lock-core": "^0.1.0"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@types/node": "^22.10.2",
|
|
72
|
+
"tsup": "^8.3.5",
|
|
73
|
+
"typescript": "^5.7.2",
|
|
74
|
+
"vitest": "^3.2.4"
|
|
75
|
+
},
|
|
76
|
+
"publishConfig": {
|
|
77
|
+
"access": "public"
|
|
78
|
+
}
|
|
75
79
|
}
|
package/src/canonical.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
DelegationEnvelope,
|
|
20
20
|
RevocationCanonicalInput,
|
|
21
21
|
RevocationEnvelope,
|
|
22
|
+
SubdelegationCanonicalInput,
|
|
22
23
|
} from './types.js';
|
|
23
24
|
|
|
24
25
|
export { canonicalize, hexEncode };
|
|
@@ -94,6 +95,20 @@ export function revocationCanonicalMessage(input: RevocationCanonicalInput): str
|
|
|
94
95
|
].join('\n');
|
|
95
96
|
}
|
|
96
97
|
|
|
98
|
+
export function subdelegationCanonicalMessage(input: SubdelegationCanonicalInput): string {
|
|
99
|
+
const scopeField = input.scopes.join(',');
|
|
100
|
+
return [
|
|
101
|
+
'oc-agent:subdelegation:v1',
|
|
102
|
+
`parent_id: ${input.parent_id}`,
|
|
103
|
+
`principal: ${input.principal}`,
|
|
104
|
+
`agent: ${input.agent}`,
|
|
105
|
+
`scopes: ${scopeField}`,
|
|
106
|
+
`issued_at: ${input.issued_at}`,
|
|
107
|
+
`expires_at: ${input.expires_at}`,
|
|
108
|
+
`nonce: ${input.nonce}`,
|
|
109
|
+
].join('\n');
|
|
110
|
+
}
|
|
111
|
+
|
|
97
112
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
98
113
|
// Bytes + ids
|
|
99
114
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -110,6 +125,10 @@ export function revocationCanonicalBytes(input: RevocationCanonicalInput): Uint8
|
|
|
110
125
|
return new TextEncoder().encode(revocationCanonicalMessage(input));
|
|
111
126
|
}
|
|
112
127
|
|
|
128
|
+
export function subdelegationCanonicalBytes(input: SubdelegationCanonicalInput): Uint8Array {
|
|
129
|
+
return new TextEncoder().encode(subdelegationCanonicalMessage(input));
|
|
130
|
+
}
|
|
131
|
+
|
|
113
132
|
export function computeDelegationId(input: DelegationCanonicalInput): string {
|
|
114
133
|
return hexEncode(sha256(delegationCanonicalBytes(input)));
|
|
115
134
|
}
|
|
@@ -122,6 +141,10 @@ export function computeRevocationId(input: RevocationCanonicalInput): string {
|
|
|
122
141
|
return hexEncode(sha256(revocationCanonicalBytes(input)));
|
|
123
142
|
}
|
|
124
143
|
|
|
144
|
+
export function computeSubdelegationId(input: SubdelegationCanonicalInput): string {
|
|
145
|
+
return hexEncode(sha256(subdelegationCanonicalBytes(input)));
|
|
146
|
+
}
|
|
147
|
+
|
|
125
148
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
126
149
|
// Envelope canonicalization (SPEC §6; RFC 8785 + scope-sorting)
|
|
127
150
|
// ─────────────────────────────────────────────────────────────────────────────
|
package/src/index.ts
CHANGED
|
@@ -8,12 +8,15 @@ export {
|
|
|
8
8
|
delegationCanonicalMessage,
|
|
9
9
|
actionCanonicalMessage,
|
|
10
10
|
revocationCanonicalMessage,
|
|
11
|
+
subdelegationCanonicalMessage,
|
|
11
12
|
delegationCanonicalBytes,
|
|
12
13
|
actionCanonicalBytes,
|
|
13
14
|
revocationCanonicalBytes,
|
|
15
|
+
subdelegationCanonicalBytes,
|
|
14
16
|
computeDelegationId,
|
|
15
17
|
computeActionId,
|
|
16
18
|
computeRevocationId,
|
|
19
|
+
computeSubdelegationId,
|
|
17
20
|
canonicalizeDelegation,
|
|
18
21
|
canonicalizeAction,
|
|
19
22
|
canonicalizeRevocation,
|
|
@@ -35,11 +38,26 @@ export {
|
|
|
35
38
|
verifyDelegation,
|
|
36
39
|
verifyAction,
|
|
37
40
|
verifyRevocation,
|
|
41
|
+
verifySubdelegation,
|
|
38
42
|
AgentError,
|
|
43
|
+
DEFAULT_MAX_CHAIN_DEPTH,
|
|
39
44
|
} from './verify.js';
|
|
40
45
|
export type {
|
|
41
46
|
VerifyBase,
|
|
42
47
|
VerifyDelegationInput,
|
|
43
48
|
VerifyActionInput,
|
|
44
49
|
VerifyRevocationInput,
|
|
50
|
+
VerifySubdelegationInput,
|
|
45
51
|
} from './verify.js';
|
|
52
|
+
export {
|
|
53
|
+
sealScopes,
|
|
54
|
+
unsealScopes,
|
|
55
|
+
encodeScopesPayload,
|
|
56
|
+
decodeScopesPayload,
|
|
57
|
+
hasPrivateScopes,
|
|
58
|
+
} from './private-scope.js';
|
|
59
|
+
export type {
|
|
60
|
+
SealScopesInput,
|
|
61
|
+
UnsealScopesInput,
|
|
62
|
+
UnsealedScopes,
|
|
63
|
+
} from './private-scope.js';
|