@orangecheck/agent-core 2.5.1 → 2.7.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/types.d.mts CHANGED
@@ -153,7 +153,7 @@ interface RevocationCanonicalInput {
153
153
  reason: string;
154
154
  signed_at: string;
155
155
  }
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' | 'E_BAD_FEDERATION_DESCRIPTOR' | 'E_THRESHOLD_MISMATCH' | 'E_THRESHOLD_NOT_MET' | 'E_UNKNOWN_GUARDIAN' | 'E_DUPLICATE_GUARDIAN';
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_STALE' | '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' | 'E_BAD_FEDERATION_DESCRIPTOR' | 'E_THRESHOLD_MISMATCH' | 'E_THRESHOLD_NOT_MET' | 'E_UNKNOWN_GUARDIAN' | 'E_DUPLICATE_GUARDIAN';
157
157
  interface VerifyOk<T> {
158
158
  ok: true;
159
159
  envelope: T;
@@ -187,6 +187,14 @@ interface VerifyActionOkExtra {
187
187
  blockHash: string;
188
188
  verified: true;
189
189
  };
190
+ asOf: {
191
+ basis: 'now';
192
+ now: string;
193
+ } | {
194
+ basis: 'signed_at';
195
+ signedAt: string;
196
+ anchored: boolean;
197
+ };
190
198
  }
191
199
  type VerifyActionResult = (VerifyOk<ActionEnvelope> & VerifyActionOkExtra) | VerifyErr;
192
200
 
package/dist/types.d.ts CHANGED
@@ -153,7 +153,7 @@ interface RevocationCanonicalInput {
153
153
  reason: string;
154
154
  signed_at: string;
155
155
  }
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' | 'E_BAD_FEDERATION_DESCRIPTOR' | 'E_THRESHOLD_MISMATCH' | 'E_THRESHOLD_NOT_MET' | 'E_UNKNOWN_GUARDIAN' | 'E_DUPLICATE_GUARDIAN';
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_STALE' | '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' | 'E_BAD_FEDERATION_DESCRIPTOR' | 'E_THRESHOLD_MISMATCH' | 'E_THRESHOLD_NOT_MET' | 'E_UNKNOWN_GUARDIAN' | 'E_DUPLICATE_GUARDIAN';
157
157
  interface VerifyOk<T> {
158
158
  ok: true;
159
159
  envelope: T;
@@ -187,6 +187,14 @@ interface VerifyActionOkExtra {
187
187
  blockHash: string;
188
188
  verified: true;
189
189
  };
190
+ asOf: {
191
+ basis: 'now';
192
+ now: string;
193
+ } | {
194
+ basis: 'signed_at';
195
+ signedAt: string;
196
+ anchored: boolean;
197
+ };
190
198
  }
191
199
  type VerifyActionResult = (VerifyOk<ActionEnvelope> & VerifyActionOkExtra) | VerifyErr;
192
200
 
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 =\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 // v1.2 federation principal (FEDERATION.md §3.3)\n | 'E_BAD_FEDERATION_DESCRIPTOR'\n | 'E_THRESHOLD_MISMATCH'\n | 'E_THRESHOLD_NOT_MET'\n | 'E_UNKNOWN_GUARDIAN'\n | 'E_DUPLICATE_GUARDIAN';\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 /**\n * `claimed` is a confirmed `ots` block no verifier walked: the block is the\n * envelope's say-so. Only a passing `verifyOtsAnchor` yields `confirmed`.\n */\n anchor:\n | { status: 'none' }\n | { status: 'pending' }\n | { status: 'claimed'; blockHeight: number; blockHash: string; verified: false }\n | { status: 'confirmed'; blockHeight: number; blockHash: string; verified: true };\n}\n\nexport type VerifyActionResult =\n | (VerifyOk<ActionEnvelope> & VerifyActionOkExtra)\n | VerifyErr;\n"]}
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_STALE'\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 // v1.2 federation principal (FEDERATION.md §3.3)\n | 'E_BAD_FEDERATION_DESCRIPTOR'\n | 'E_THRESHOLD_MISMATCH'\n | 'E_THRESHOLD_NOT_MET'\n | 'E_UNKNOWN_GUARDIAN'\n | 'E_DUPLICATE_GUARDIAN';\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 /**\n * `claimed` is a confirmed `ots` block no verifier walked: the block is the\n * envelope's say-so. Only a passing `verifyOtsAnchor` yields `confirmed`.\n */\n anchor:\n | { status: 'none' }\n | { status: 'pending' }\n | { status: 'claimed'; blockHeight: number; blockHash: string; verified: false }\n | { status: 'confirmed'; blockHeight: number; blockHash: string; verified: true };\n /**\n * The time the verdict holds for. `now`: verifyAction, checked live.\n * `signed_at`: verifyActionAsOfSignedAt, checked as of the time the agent\n * claims; `anchored` is false when only the agent says so.\n */\n asOf:\n | { basis: 'now'; now: string }\n | { basis: 'signed_at'; signedAt: string; anchored: boolean };\n}\n\nexport type VerifyActionResult =\n | (VerifyOk<ActionEnvelope> & VerifyActionOkExtra)\n | VerifyErr;\n"]}
@@ -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 =\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 // v1.2 federation principal (FEDERATION.md §3.3)\n | 'E_BAD_FEDERATION_DESCRIPTOR'\n | 'E_THRESHOLD_MISMATCH'\n | 'E_THRESHOLD_NOT_MET'\n | 'E_UNKNOWN_GUARDIAN'\n | 'E_DUPLICATE_GUARDIAN';\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 /**\n * `claimed` is a confirmed `ots` block no verifier walked: the block is the\n * envelope's say-so. Only a passing `verifyOtsAnchor` yields `confirmed`.\n */\n anchor:\n | { status: 'none' }\n | { status: 'pending' }\n | { status: 'claimed'; blockHeight: number; blockHash: string; verified: false }\n | { status: 'confirmed'; blockHeight: number; blockHash: string; verified: true };\n}\n\nexport type VerifyActionResult =\n | (VerifyOk<ActionEnvelope> & VerifyActionOkExtra)\n | VerifyErr;\n"]}
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_STALE'\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 // v1.2 federation principal (FEDERATION.md §3.3)\n | 'E_BAD_FEDERATION_DESCRIPTOR'\n | 'E_THRESHOLD_MISMATCH'\n | 'E_THRESHOLD_NOT_MET'\n | 'E_UNKNOWN_GUARDIAN'\n | 'E_DUPLICATE_GUARDIAN';\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 /**\n * `claimed` is a confirmed `ots` block no verifier walked: the block is the\n * envelope's say-so. Only a passing `verifyOtsAnchor` yields `confirmed`.\n */\n anchor:\n | { status: 'none' }\n | { status: 'pending' }\n | { status: 'claimed'; blockHeight: number; blockHash: string; verified: false }\n | { status: 'confirmed'; blockHeight: number; blockHash: string; verified: true };\n /**\n * The time the verdict holds for. `now`: verifyAction, checked live.\n * `signed_at`: verifyActionAsOfSignedAt, checked as of the time the agent\n * claims; `anchored` is false when only the agent says so.\n */\n asOf:\n | { basis: 'now'; now: string }\n | { basis: 'signed_at'; signedAt: string; anchored: boolean };\n}\n\nexport type VerifyActionResult =\n | (VerifyOk<ActionEnvelope> & VerifyActionOkExtra)\n | VerifyErr;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orangecheck/agent-core",
3
- "version": "2.5.1",
3
+ "version": "2.7.0",
4
4
  "description": "OC Agent canonical messages, envelope formats (delegation/action/revocation), scope grammar, and verification. See https://github.com/orangecheck/oc-agent-protocol.",
5
5
  "keywords": [
6
6
  "bitcoin",
@@ -0,0 +1,82 @@
1
+ // SPEC §4.4: expires_at > issued_at and expires_at - issued_at ≤ 365 days, checked at
2
+ // §8.1 step 2 (E_MALFORMED) whatever the clock says. Every envelope here has an honest
3
+ // id, so without the window check each one would verify.
4
+
5
+ import { describe, expect, it } from 'vitest';
6
+
7
+ import { canonicalizeScopes, computeDelegationId } from './canonical.js';
8
+ import type { DelegationEnvelope } from './types.js';
9
+ import { verifyDelegation } from './verify.js';
10
+
11
+ const ISSUED = '2026-04-22T12:00:00Z';
12
+ const DAY = 86_400_000;
13
+ const iso = (ms: number) => new Date(ms).toISOString().replace(/\.\d{3}Z$/, 'Z');
14
+
15
+ function delegation(issued_at: string, expires_at: string): DelegationEnvelope {
16
+ const principal = 'bc1qprincipal000000000000000000000000000000';
17
+ const agent = 'bc1qagent0000000000000000000000000000000000';
18
+ const scopes = canonicalizeScopes(['ln:send(max_sats<=1000)']);
19
+ const nonce = '0123456789abcdef0123456789abcdef';
20
+ const id = computeDelegationId({
21
+ principal,
22
+ agent,
23
+ scopes,
24
+ bond_sats: 0,
25
+ bond_attestation: 'none',
26
+ issued_at,
27
+ expires_at,
28
+ nonce,
29
+ });
30
+ return {
31
+ v: 1,
32
+ kind: 'agent-delegation',
33
+ id,
34
+ principal: { address: principal, alg: 'bip322' },
35
+ agent: { address: agent, alg: 'bip322' },
36
+ scopes,
37
+ bond: null,
38
+ issued_at,
39
+ expires_at,
40
+ nonce,
41
+ revocation: { holders: ['principal'], ref: null },
42
+ sig: { alg: 'bip322', pubkey: principal, value: 'AAAA' },
43
+ };
44
+ }
45
+
46
+ const verify = (env: DelegationEnvelope, now?: Date) =>
47
+ verifyDelegation({
48
+ envelope: env,
49
+ skipSignatureVerification: true,
50
+ skipRevocationCheck: true,
51
+ ...(now ? { now } : { skipTemporalCheck: true }),
52
+ });
53
+
54
+ describe('delegation window (SPEC §4.4)', () => {
55
+ const issuedMs = Date.parse(ISSUED);
56
+
57
+ it('accepts exactly 365 days', async () => {
58
+ expect((await verify(delegation(ISSUED, iso(issuedMs + 365 * DAY)))).ok).toBe(true);
59
+ });
60
+
61
+ it('rejects 365 days and one second with E_MALFORMED', async () => {
62
+ const r = await verify(delegation(ISSUED, iso(issuedMs + 365 * DAY + 1000)));
63
+ expect(r).toMatchObject({ ok: false, code: 'E_MALFORMED' });
64
+ if (!r.ok) expect(r.message).toBe('expires_at is more than 365 days after issued_at (SPEC §4.4)');
65
+ });
66
+
67
+ it('rejects 366 days even inside the window, so the clock cannot rescue it', async () => {
68
+ const r = await verify(delegation(ISSUED, iso(issuedMs + 366 * DAY)), new Date(issuedMs + DAY));
69
+ expect(r).toMatchObject({ ok: false, code: 'E_MALFORMED' });
70
+ });
71
+
72
+ it('rejects expires_at equal to issued_at with temporal checks skipped', async () => {
73
+ const r = await verify(delegation(ISSUED, ISSUED));
74
+ expect(r).toMatchObject({ ok: false, code: 'E_MALFORMED' });
75
+ if (!r.ok) expect(r.message).toBe('expires_at must be after issued_at');
76
+ });
77
+
78
+ it('rejects a timestamp that is shaped right but is no real time', async () => {
79
+ const r = await verify(delegation(ISSUED, '2026-13-01T00:00:00Z'));
80
+ expect(r).toMatchObject({ ok: false, code: 'E_MALFORMED' });
81
+ });
82
+ });
@@ -16,7 +16,7 @@ import {
16
16
  type FederationDelegationEnvelope,
17
17
  type FederationRevocationEnvelope,
18
18
  } from './federation.js';
19
- import { computeRevocationId } from './canonical.js';
19
+ import { computeDelegationId, computeRevocationId } from './canonical.js';
20
20
  import { verifyDelegation } from './verify.js';
21
21
  import type { DelegationEnvelope } from './types.js';
22
22
 
@@ -168,6 +168,26 @@ d('federation reject reasons (each invalid case fails for its named reason)', ()
168
168
  expect(r.ok).toBe(false);
169
169
  if (!r.ok) expect(r.code).toBe('E_THRESHOLD_MISMATCH');
170
170
  });
171
+ it('366-day window → E_MALFORMED (FEDERATION.md §5 bounds it as SPEC §4.4 does)', async () => {
172
+ const v = await load('v19-federation-delegation-3of5-valid.json');
173
+ const env = { ...v.expected.envelope } as FederationDelegationEnvelope;
174
+ env.expires_at = new Date(Date.parse(env.issued_at) + 366 * 86_400_000)
175
+ .toISOString()
176
+ .replace(/\.\d{3}Z$/, 'Z');
177
+ // Honest id for the longer window, so the window is the only fault.
178
+ env.id = computeDelegationId({
179
+ principal: `federation:${env.principal.descriptor_id}`,
180
+ agent: env.agent.address,
181
+ scopes: env.scopes,
182
+ bond_sats: env.bond?.sats ?? 0,
183
+ bond_attestation: env.bond?.attestation_id ?? 'none',
184
+ issued_at: env.issued_at,
185
+ expires_at: env.expires_at,
186
+ nonce: env.nonce,
187
+ });
188
+ const r = await verifyFederationDelegation({ envelope: env, ...opts });
189
+ expect(r).toMatchObject({ ok: false, code: 'E_MALFORMED' });
190
+ });
171
191
  });
172
192
 
173
193
  // FEDERATION.md §4 / SECURITY §5 item 7: a revoked federation delegation must
package/src/federation.ts CHANGED
@@ -32,6 +32,7 @@ import type {
32
32
  DelegationRevocationRef,
33
33
  RevocationEnvelope,
34
34
  } from './types.js';
35
+ import { delegationWindowError } from './verify.js';
35
36
 
36
37
  // ─────────────────────────────────────────────────────────────────────────────
37
38
  // Types (FEDERATION.md §2 / §3.2)
@@ -251,6 +252,8 @@ export async function verifyFederationDelegation(
251
252
  if (!ISO_UTC.test(env.issued_at) || !ISO_UTC.test(env.expires_at)) {
252
253
  return fail('E_MALFORMED', 'issued_at / expires_at must be ISO 8601 UTC');
253
254
  }
255
+ const windowError = delegationWindowError(env.issued_at, env.expires_at);
256
+ if (windowError) return fail('E_MALFORMED', windowError);
254
257
  if (!/^[0-9a-f]{32}$/.test(env.nonce)) return fail('E_MALFORMED', 'nonce must be 32 hex chars');
255
258
 
256
259
  // Canonical scopes (identical rules to v1) must be sorted on the envelope.
@@ -305,7 +308,6 @@ export async function verifyFederationDelegation(
305
308
  const now = input.now ?? new Date();
306
309
  const issued = new Date(env.issued_at);
307
310
  const expires = new Date(env.expires_at);
308
- if (expires <= issued) return fail('E_MALFORMED', 'expires_at <= issued_at');
309
311
  if (now < issued) return fail('E_NOT_YET_VALID', `delegation not valid until ${env.issued_at}`);
310
312
  if (now >= expires) return fail('E_EXPIRED', `delegation expired at ${env.expires_at}`);
311
313
  }
package/src/index.ts CHANGED
@@ -37,15 +37,19 @@ export type { Scope, ScopeConstraint, ScopeOp, ValidationOptions } from './scope
37
37
  export {
38
38
  verifyDelegation,
39
39
  verifyAction,
40
+ verifyActionAsOfSignedAt,
41
+ createReplayGuard,
40
42
  verifyRevocation,
41
43
  verifySubdelegation,
42
44
  AgentError,
43
45
  DEFAULT_MAX_CHAIN_DEPTH,
46
+ DEFAULT_MAX_SKEW_MS,
44
47
  } from './verify.js';
45
48
  export type {
46
49
  VerifyBase,
47
50
  VerifyDelegationInput,
48
51
  VerifyActionInput,
52
+ VerifyActionAsOfSignedAtInput,
49
53
  VerifyRevocationInput,
50
54
  VerifySubdelegationInput,
51
55
  } from './verify.js';
@@ -0,0 +1,151 @@
1
+ // SPEC §8.1 step 6 checks the delegation at the time of verification, not at
2
+ // the action's signed_at. The agent picks signed_at, so an action that only
3
+ // had to fit the delegation's window could be backdated past its expiry or past
4
+ // a revocation and still verify. A live verifier checks at `now`; an audit of a
5
+ // past action says outright that it relied on the agent's claimed time.
6
+ import { describe, expect, it } from 'vitest';
7
+
8
+ import { computeActionId, computeRevocationId } from './canonical.js';
9
+ import { createReplayGuard, verifyAction, verifyActionAsOfSignedAt } from './verify.js';
10
+ import type { ActionEnvelope, DelegationEnvelope, RevocationEnvelope } from './types.js';
11
+
12
+ const delegation: DelegationEnvelope = {
13
+ v: 1,
14
+ kind: 'agent-delegation',
15
+ id: '36d79600191db871baa3fc9aa3b5e77750a5c423b1f620ec26cf16bd122e19a7',
16
+ principal: { address: 'bc1qprincipal000000000000000000000000000000', alg: 'bip322' },
17
+ agent: { address: 'bc1qagent0000000000000000000000000000000000', alg: 'bip322' },
18
+ scopes: ['lock:seal(recipient=bc1qalice000000000000000000000000000000000)'],
19
+ bond: null,
20
+ issued_at: '2026-04-22T12:00:00Z',
21
+ expires_at: '2026-04-29T12:00:00Z',
22
+ nonce: '0123456789abcdef0123456789abcdef',
23
+ revocation: { holders: ['principal'], ref: null },
24
+ sig: { alg: 'bip322', pubkey: 'bc1qprincipal000000000000000000000000000000', value: 'AAAA' },
25
+ } as DelegationEnvelope;
26
+
27
+ function action(signed_at: string): ActionEnvelope {
28
+ const canon = {
29
+ address: delegation.agent.address,
30
+ content_hash: 'sha256:' + '00'.repeat(32),
31
+ content_length: 0,
32
+ content_mime: 'text/plain',
33
+ signed_at,
34
+ delegation_id: delegation.id,
35
+ scope_exercised: delegation.scopes![0]!,
36
+ };
37
+ return {
38
+ v: 1,
39
+ kind: 'agent-action',
40
+ id: computeActionId(canon),
41
+ content: { hash: canon.content_hash, length: 0, mime: 'text/plain', ref: null },
42
+ signer: { address: canon.address, alg: 'bip322' },
43
+ signed_at,
44
+ delegation_id: delegation.id,
45
+ scope_exercised: canon.scope_exercised,
46
+ ots: null,
47
+ sig: { alg: 'bip322', pubkey: canon.address, value: 'AAAA' },
48
+ } as ActionEnvelope;
49
+ }
50
+
51
+ function revocation(signed_at: string): RevocationEnvelope {
52
+ const canon = { address: delegation.principal.address, delegation_id: delegation.id, reason: '', signed_at };
53
+ return {
54
+ v: 1,
55
+ kind: 'agent-revocation',
56
+ id: computeRevocationId(canon),
57
+ delegation_id: delegation.id,
58
+ signer: { address: canon.address, alg: 'bip322' },
59
+ reason: '',
60
+ signed_at,
61
+ ots: null,
62
+ sig: { alg: 'bip322', pubkey: canon.address, value: 'AAAA' },
63
+ } as RevocationEnvelope;
64
+ }
65
+
66
+ const base = { delegation, skipSignatureVerification: true };
67
+
68
+ describe('live verification checks at now', () => {
69
+ it('refuses an action backdated into the window of a delegation that has expired', async () => {
70
+ const r = await verifyAction({
71
+ ...base,
72
+ action: action('2026-04-28T00:00:00Z'),
73
+ revocations: [],
74
+ now: new Date('2026-05-01T00:00:00Z'),
75
+ });
76
+ expect(r.ok === false && r.code).toBe('E_EXPIRED');
77
+ });
78
+
79
+ it('refuses an action backdated to before a revocation that is already in effect', async () => {
80
+ const r = await verifyAction({
81
+ ...base,
82
+ action: action('2026-04-24T11:59:00Z'),
83
+ revocations: [revocation('2026-04-24T11:59:30Z')],
84
+ now: new Date('2026-04-24T12:00:00Z'),
85
+ });
86
+ expect(r.ok === false && r.code).toBe('E_REVOKED');
87
+ });
88
+
89
+ it('refuses an action signed further from now than the freshness bound', async () => {
90
+ const now = new Date('2026-04-24T12:00:00Z');
91
+ const old = await verifyAction({ ...base, action: action('2026-04-24T11:50:00Z'), revocations: [], now });
92
+ expect(old.ok === false && old.code).toBe('E_STALE');
93
+ const ahead = await verifyAction({ ...base, action: action('2026-04-24T12:05:00Z'), revocations: [], now });
94
+ expect(ahead.ok === false && ahead.code).toBe('E_STALE');
95
+ });
96
+
97
+ it('accepts a fresh action under a clear feed, and says it was checked at now', async () => {
98
+ const now = new Date('2026-04-24T12:00:00Z');
99
+ const r = await verifyAction({ ...base, action: action('2026-04-24T11:59:30Z'), revocations: [], now });
100
+ expect(r.ok).toBe(true);
101
+ expect(r.ok && r.asOf).toEqual({ basis: 'now', now: '2026-04-24T12:00:00.000Z' });
102
+ });
103
+
104
+ it('takes a wider freshness bound when the caller sets one', async () => {
105
+ const r = await verifyAction({
106
+ ...base,
107
+ action: action('2026-04-24T11:50:00Z'),
108
+ revocations: [],
109
+ now: new Date('2026-04-24T12:00:00Z'),
110
+ maxSkewMs: 15 * 60_000,
111
+ });
112
+ expect(r.ok).toBe(true);
113
+ });
114
+
115
+ it('does not let a revocation dated in the future refuse an action today', async () => {
116
+ const r = await verifyAction({
117
+ ...base,
118
+ action: action('2026-04-24T11:59:30Z'),
119
+ revocations: [revocation('2026-04-25T00:00:00Z')],
120
+ now: new Date('2026-04-24T12:00:00Z'),
121
+ });
122
+ expect(r.ok).toBe(true);
123
+ });
124
+ });
125
+
126
+ describe('an audit checks as of signed_at, and says that time is a claim', () => {
127
+ it('accepts a past action inside its window, with an unanchored signed_at', async () => {
128
+ const r = await verifyActionAsOfSignedAt({ ...base, action: action('2026-04-28T00:00:00Z'), revocations: [] });
129
+ expect(r.ok).toBe(true);
130
+ expect(r.ok && r.asOf).toEqual({ basis: 'signed_at', signedAt: '2026-04-28T00:00:00Z', anchored: false });
131
+ });
132
+
133
+ it('still refuses an action that claims a time after the revocation', async () => {
134
+ const r = await verifyActionAsOfSignedAt({
135
+ ...base,
136
+ action: action('2026-04-24T12:00:00Z'),
137
+ revocations: [revocation('2026-04-24T11:59:30Z')],
138
+ });
139
+ expect(r.ok === false && r.code).toBe('E_REVOKED');
140
+ });
141
+ });
142
+
143
+ describe('createReplayGuard', () => {
144
+ it('admits an action once, and forgets it when it could no longer pass as fresh', () => {
145
+ const guard = createReplayGuard(120_000);
146
+ const a = action('2026-04-24T12:00:00Z');
147
+ expect(guard.firstUse(a, new Date('2026-04-24T12:00:05Z'))).toBe(true);
148
+ expect(guard.firstUse(a, new Date('2026-04-24T12:01:00Z'))).toBe(false);
149
+ expect(guard.firstUse(a, new Date('2026-04-24T12:02:01Z'))).toBe(true);
150
+ });
151
+ });
@@ -189,8 +189,10 @@ async function buildPrivateEnvelopeWithKey(
189
189
  ],
190
190
  });
191
191
 
192
- const issued_at = '2026-04-22T12:00:00Z';
193
- const expires_at = '2099-04-22T12:00:00Z';
192
+ // Current window, inside SPEC §4.4's 365-day limit, so the temporal check passes.
193
+ const isoSeconds = (ms: number) => new Date(ms).toISOString().replace(/\.\d{3}Z$/, 'Z');
194
+ const issued_at = isoSeconds(Date.now() - 86_400_000);
195
+ const expires_at = isoSeconds(Date.now() + 30 * 86_400_000);
194
196
  const nonce = hexEncode(randomBytesN(16));
195
197
 
196
198
  const canonInput = {
@@ -5,7 +5,7 @@
5
5
  import { describe, expect, it } from 'vitest';
6
6
 
7
7
  import { computeActionId, computeDelegationId, computeRevocationId } from './canonical.js';
8
- import { verifyAction, verifyDelegation, verifyRevocation } from './verify.js';
8
+ import { verifyActionAsOfSignedAt, verifyDelegation, verifyRevocation } from './verify.js';
9
9
  import type { ActionEnvelope, ActionOts, DelegationEnvelope, RevocationEnvelope } from './types.js';
10
10
 
11
11
  const PRINCIPAL = 'bc1qprincipal000000000000000000000000000000';
@@ -91,6 +91,8 @@ function confirmed(height: number): ActionOts {
91
91
 
92
92
  const AT = new Date('2026-04-23T12:00:00Z');
93
93
 
94
+ // Priority between an action and a revocation (SPEC §9.3) is a question about
95
+ // the action's own time, so these run as audits, as of signed_at.
94
96
  describe('revocation authority always includes the principal', () => {
95
97
  for (const holders of [['agent'], [], ['principal'], undefined, 'agent']) {
96
98
  it(`principal revocation is honoured with holders=${JSON.stringify(holders)}`, async () => {
@@ -105,7 +107,7 @@ describe('revocation authority always includes the principal', () => {
105
107
  now: AT,
106
108
  });
107
109
  expect(dr.ok === false && dr.code).toBe('E_REVOKED');
108
- const ar = await verifyAction({
110
+ const ar = await verifyActionAsOfSignedAt({
109
111
  action: action(d, '2026-04-23T06:00:00Z'),
110
112
  delegation: d,
111
113
  revocations: [rev],
@@ -150,7 +152,7 @@ describe('revocation priority uses only verified anchors', () => {
150
152
  const later = '2026-04-23T06:00:00Z';
151
153
 
152
154
  it('an action anchor with no anchor verifier does not outrank a revocation', async () => {
153
- const r = await verifyAction({
155
+ const r = await verifyActionAsOfSignedAt({
154
156
  action: action(d, later, confirmed(1)),
155
157
  delegation: d,
156
158
  revocations: [rev],
@@ -160,7 +162,7 @@ describe('revocation priority uses only verified anchors', () => {
160
162
  });
161
163
 
162
164
  it('an action anchor the verifier rejects does not outrank a revocation', async () => {
163
- const r = await verifyAction({
165
+ const r = await verifyActionAsOfSignedAt({
164
166
  action: action(d, later, confirmed(1)),
165
167
  delegation: d,
166
168
  revocations: [rev],
@@ -168,7 +170,7 @@ describe('revocation priority uses only verified anchors', () => {
168
170
  verifyOtsAnchor: async () => false,
169
171
  });
170
172
  expect(r.ok === false && r.code).toBe('E_REVOKED');
171
- const clean = await verifyAction({
173
+ const clean = await verifyActionAsOfSignedAt({
172
174
  action: action(d, later, confirmed(1)),
173
175
  delegation: d,
174
176
  revocations: [],
@@ -185,14 +187,14 @@ describe('revocation priority uses only verified anchors', () => {
185
187
 
186
188
  // The ots block is outside the signature: its block is a claim until walked.
187
189
  it('reports an unwalked anchor as claimed, and a walked one as confirmed', async () => {
188
- const unwalked = await verifyAction({
190
+ const unwalked = await verifyActionAsOfSignedAt({
189
191
  action: action(d, later, confirmed(1)),
190
192
  delegation: d,
191
193
  revocations: [],
192
194
  skipSignatureVerification: true,
193
195
  });
194
196
  expect(unwalked.ok && unwalked.anchor.status).toBe('claimed');
195
- const walked = await verifyAction({
197
+ const walked = await verifyActionAsOfSignedAt({
196
198
  action: action(d, later, confirmed(1)),
197
199
  delegation: d,
198
200
  revocations: [],
@@ -211,7 +213,7 @@ describe('revocation priority uses only verified anchors', () => {
211
213
  const a = action(d, later, confirmed(100));
212
214
  const revAnchored = revocation(d, PRINCIPAL, '2026-04-23T00:00:00Z', confirmed(200));
213
215
  const seen: string[] = [];
214
- const r = await verifyAction({
216
+ const r = await verifyActionAsOfSignedAt({
215
217
  action: a,
216
218
  delegation: d,
217
219
  revocations: [revAnchored],
@@ -227,7 +229,7 @@ describe('revocation priority uses only verified anchors', () => {
227
229
  });
228
230
 
229
231
  it('a verified action anchor against an unanchored revocation falls back to signed times', async () => {
230
- const r = await verifyAction({
232
+ const r = await verifyActionAsOfSignedAt({
231
233
  action: action(d, later, confirmed(1)),
232
234
  delegation: d,
233
235
  revocations: [rev],
@@ -235,7 +237,7 @@ describe('revocation priority uses only verified anchors', () => {
235
237
  verifyOtsAnchor: async () => true,
236
238
  });
237
239
  expect(r.ok === false && r.code).toBe('E_REVOKED');
238
- const before = await verifyAction({
240
+ const before = await verifyActionAsOfSignedAt({
239
241
  action: action(d, '2026-04-22T18:00:00Z', confirmed(1)),
240
242
  delegation: d,
241
243
  revocations: [rev],
@@ -248,7 +250,7 @@ describe('revocation priority uses only verified anchors', () => {
248
250
  it('a revocation anchor that does not verify cannot move the revocation later', async () => {
249
251
  const revFarFuture = revocation(d, PRINCIPAL, '2026-04-23T00:00:00Z', confirmed(10_000_000));
250
252
  const a = action(d, later, confirmed(100));
251
- const r = await verifyAction({
253
+ const r = await verifyActionAsOfSignedAt({
252
254
  action: a,
253
255
  delegation: d,
254
256
  revocations: [revFarFuture],
@@ -262,7 +264,7 @@ describe('revocation priority uses only verified anchors', () => {
262
264
  const a = action(d, later, confirmed(300));
263
265
  const revAt = (h: number) => revocation(d, PRINCIPAL, '2026-04-23T00:00:00Z', confirmed(h));
264
266
  const verifyOtsAnchor = async () => true;
265
- const earlierRev = await verifyAction({
267
+ const earlierRev = await verifyActionAsOfSignedAt({
266
268
  action: a,
267
269
  delegation: d,
268
270
  revocations: [revAt(300)],
@@ -270,7 +272,7 @@ describe('revocation priority uses only verified anchors', () => {
270
272
  verifyOtsAnchor,
271
273
  });
272
274
  expect(earlierRev.ok === false && earlierRev.code).toBe('E_REVOKED');
273
- const laterRev = await verifyAction({
275
+ const laterRev = await verifyActionAsOfSignedAt({
274
276
  action: a,
275
277
  delegation: d,
276
278
  revocations: [revAt(301)],