@agenticprimitives/delegation 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/hash.js ADDED
@@ -0,0 +1,80 @@
1
+ // EIP-712 hashing for Delegation + Caveat[].
2
+ //
3
+ // Domain MUST match what AgentDelegationManager computes on-chain:
4
+ // EIP712Domain(string name, string version, uint256 chainId, address verifyingContract)
5
+ // name = "AgentDelegationManager"
6
+ // version = "1"
7
+ import { hashTypedData, keccak256, encodeAbiParameters } from 'viem';
8
+ const DOMAIN_NAME = 'AgentDelegationManager';
9
+ const DOMAIN_VERSION = '1';
10
+ export const DELEGATION_EIP712_TYPES = {
11
+ Delegation: [
12
+ { name: 'delegator', type: 'address' },
13
+ { name: 'delegate', type: 'address' },
14
+ { name: 'authority', type: 'bytes32' },
15
+ { name: 'caveats', type: 'Caveat[]' },
16
+ { name: 'salt', type: 'uint256' },
17
+ ],
18
+ // `args` (redeemer-supplied runtime data) is DELIBERATELY excluded from
19
+ // the signed hash — it must match AgentDelegationManager's
20
+ // CAVEAT_TYPEHASH = keccak256("Caveat(address enforcer,bytes terms)")
21
+ // (DelegationManager.sol:55). Including args here made every delegation
22
+ // carrying a caveat fail on-chain ERC-1271 redeem AND let a redeemer's
23
+ // chosen args ride inside the delegator's signature. (audit F-1)
24
+ Caveat: [
25
+ { name: 'enforcer', type: 'address' },
26
+ { name: 'terms', type: 'bytes' },
27
+ ],
28
+ };
29
+ export function delegationDomain(chainId, delegationManager) {
30
+ return {
31
+ name: DOMAIN_NAME,
32
+ version: DOMAIN_VERSION,
33
+ chainId,
34
+ verifyingContract: delegationManager,
35
+ };
36
+ }
37
+ function caveatMessage(c) {
38
+ // Only the signed fields (enforcer, terms). `args` is runtime-only and
39
+ // never part of the delegation hash — see DELEGATION_EIP712_TYPES.Caveat.
40
+ return {
41
+ enforcer: c.enforcer,
42
+ terms: c.terms,
43
+ };
44
+ }
45
+ /**
46
+ * EIP-712 hash of a Delegation. This is the value the smart-account owner
47
+ * signs (via signTypedData / personal_sign of the digest) and the value
48
+ * AgentDelegationManager validates via ERC-1271.
49
+ */
50
+ export function hashDelegation(d, chainId, delegationManager) {
51
+ return hashTypedData({
52
+ domain: delegationDomain(chainId, delegationManager),
53
+ types: DELEGATION_EIP712_TYPES,
54
+ primaryType: 'Delegation',
55
+ message: {
56
+ delegator: d.delegator,
57
+ delegate: d.delegate,
58
+ authority: d.authority,
59
+ caveats: d.caveats.map(caveatMessage),
60
+ salt: d.salt,
61
+ },
62
+ });
63
+ }
64
+ /**
65
+ * keccak256 of the ABI-encoded caveat array. Mirrors what
66
+ * AgentDelegationManager computes for caveat enforcement bookkeeping.
67
+ */
68
+ export function hashCaveats(caveats) {
69
+ const encoded = encodeAbiParameters([
70
+ {
71
+ type: 'tuple[]',
72
+ components: [
73
+ { name: 'enforcer', type: 'address' },
74
+ { name: 'terms', type: 'bytes' },
75
+ ],
76
+ },
77
+ ], [caveats.map(caveatMessage)]);
78
+ return keccak256(encoded);
79
+ }
80
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,EAAE;AACF,mEAAmE;AACnE,0FAA0F;AAC1F,oCAAoC;AACpC,kBAAkB;AAElB,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,mBAAmB,EAA0B,MAAM,MAAM,CAAC;AAG7F,MAAM,WAAW,GAAG,wBAAwB,CAAC;AAC7C,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,UAAU,EAAE;QACV,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE;QACtC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE;QACrC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE;QACtC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE;QACrC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;KAClC;IACD,wEAAwE;IACxE,2DAA2D;IAC3D,sEAAsE;IACtE,wEAAwE;IACxE,uEAAuE;IACvE,iEAAiE;IACjE,MAAM,EAAE;QACN,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE;QACrC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE;KACjC;CACO,CAAC;AAEX,MAAM,UAAU,gBAAgB,CAAC,OAAe,EAAE,iBAA0B;IAC1E,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;QACvB,OAAO;QACP,iBAAiB,EAAE,iBAAiB;KACrC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,CAAS;IAC9B,uEAAuE;IACvE,0EAA0E;IAC1E,OAAO;QACL,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,KAAK,EAAE,CAAC,CAAC,KAAK;KACf,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,CAAa,EAAE,OAAe,EAAE,iBAA0B;IACvF,OAAO,aAAa,CAAC;QACnB,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,CAAC;QACpD,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EAAE,YAAY;QACzB,OAAO,EAAE;YACP,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;YACrC,IAAI,EAAE,CAAC,CAAC,IAAI;SACb;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAAiB;IAC3C,MAAM,OAAO,GAAG,mBAAmB,CACjC;QACE;YACE,IAAI,EAAE,SAAS;YACf,UAAU,EAAE;gBACV,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE;gBACrC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE;aACjC;SACF;KACF,EACD,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAC7B,CAAC;IACF,OAAO,SAAS,CAAC,OAAO,CAAC,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,12 @@
1
+ export { ROOT_AUTHORITY } from './types';
2
+ export { buildCaveat, buildMcpToolScopeCaveat, buildDataScopeCaveat, buildDelegateBindingCaveat, buildQuorumCaveat, encodeTimestampTerms, encodeValueTerms, encodeAllowedTargetsTerms, encodeAllowedMethodsTerms, MCP_TOOL_SCOPE_ENFORCER, DATA_SCOPE_ENFORCER, DELEGATE_BINDING_ENFORCER, } from './caveats';
3
+ export type { QuorumCaveatOpts } from './caveats';
4
+ export { hashDelegation, hashCaveats, DELEGATION_EIP712_TYPES, delegationDomain } from './hash';
5
+ export { evaluateCaveats } from './evaluator';
6
+ export { DelegationClient } from './client';
7
+ export { SessionManager, createMemorySessionStore } from './session-manager';
8
+ export { mintDelegationToken, verifyDelegationToken } from './token';
9
+ export { isRevoked, revokeDelegation } from './onchain';
10
+ export type { Address, Hex, Caveat, CaveatContext, CaveatVerdict, Delegation, DataScopeGrant, DelegationClientOpts, DelegationTokenClaims, EnforcerAddressMap, EvaluateOpts, JtiStore, SessionMeta, SessionPackage, SessionRow, SessionStore, TxContext, VerifyError, VerifyOpts, } from './types';
11
+ export type { VerifyOptsExt } from './token';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC,OAAO,EACL,WAAW,EACX,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,yBAAyB,EACzB,yBAAyB,EACzB,uBAAuB,EACvB,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAM7E,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAExD,YAAY,EACV,OAAO,EACP,GAAG,EACH,MAAM,EACN,aAAa,EACb,aAAa,EACb,UAAU,EACV,cAAc,EACd,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,cAAc,EACd,UAAU,EACV,YAAY,EACZ,SAAS,EACT,WAAW,EACX,UAAU,GACX,MAAM,SAAS,CAAC;AAKjB,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ // @agenticprimitives/delegation — public API
2
+ //
3
+ // See ../../specs/202-delegation.md for the full contract.
4
+ export { ROOT_AUTHORITY } from './types';
5
+ export { buildCaveat, buildMcpToolScopeCaveat, buildDataScopeCaveat, buildDelegateBindingCaveat, buildQuorumCaveat, encodeTimestampTerms, encodeValueTerms, encodeAllowedTargetsTerms, encodeAllowedMethodsTerms, MCP_TOOL_SCOPE_ENFORCER, DATA_SCOPE_ENFORCER, DELEGATE_BINDING_ENFORCER, } from './caveats';
6
+ export { hashDelegation, hashCaveats, DELEGATION_EIP712_TYPES, delegationDomain } from './hash';
7
+ export { evaluateCaveats } from './evaluator';
8
+ export { DelegationClient } from './client';
9
+ export { SessionManager, createMemorySessionStore } from './session-manager';
10
+ // H7-B.8: `verifyCrossDelegation` removed from the public surface (XPKG-002 /
11
+ // EXT-024 closure). The stub unconditionally returned a "not implemented"
12
+ // error string — a public symbol that lies about runtime capability. When the
13
+ // work resumes it lands behind `./experimental` per spec 100 §6.
14
+ export { mintDelegationToken, verifyDelegationToken } from './token';
15
+ export { isRevoked, revokeDelegation } from './onchain';
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,EAAE;AACF,2DAA2D;AAE3D,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC,OAAO,EACL,WAAW,EACX,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,yBAAyB,EACzB,yBAAyB,EACzB,uBAAuB,EACvB,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAE7E,8EAA8E;AAC9E,0EAA0E;AAC1E,8EAA8E;AAC9E,iEAAiE;AACjE,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Hex, Address } from '@agenticprimitives/types';
2
+ import type { TxContext } from './types';
3
+ export declare function isRevoked(_hash: Hex, _opts: {
4
+ delegationManager: Address;
5
+ rpcUrl: string;
6
+ }): Promise<boolean>;
7
+ export declare function revokeDelegation(_hash: Hex, _ctx: TxContext): Promise<Hex>;
8
+ //# sourceMappingURL=onchain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onchain.d.ts","sourceRoot":"","sources":["../src/onchain.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,wBAAsB,SAAS,CAC7B,KAAK,EAAE,GAAG,EACV,KAAK,EAAE;IAAE,iBAAiB,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACpD,OAAO,CAAC,OAAO,CAAC,CAIlB;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAIhF"}
@@ -0,0 +1,9 @@
1
+ // On-chain revocation helpers. v0 demo doesn't exercise revocation (step 2
2
+ // just packages a session). Stubs preserve the public-export surface.
3
+ export async function isRevoked(_hash, _opts) {
4
+ throw new Error('isRevoked: not implemented in v0 demo step 2 (lands with demo step 3 / mcp-runtime commit).');
5
+ }
6
+ export async function revokeDelegation(_hash, _ctx) {
7
+ throw new Error('revokeDelegation: not implemented in v0 demo step 2 (lands with on-chain redeem path).');
8
+ }
9
+ //# sourceMappingURL=onchain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onchain.js","sourceRoot":"","sources":["../src/onchain.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,sEAAsE;AAKtE,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,KAAU,EACV,KAAqD;IAErD,MAAM,IAAI,KAAK,CACb,6FAA6F,CAC9F,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAU,EAAE,IAAe;IAChE,MAAM,IAAI,KAAK,CACb,wFAAwF,CACzF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,51 @@
1
+ import { keccak256, type Address, type Hex } from 'viem';
2
+ import type { A2AKeyProvider } from '@agenticprimitives/key-custody';
3
+ import type { Delegation, SessionMeta, SessionStore } from './types';
4
+ export interface SessionResolveResult {
5
+ meta: SessionMeta;
6
+ delegation: Delegation | null;
7
+ signer: {
8
+ address: Address;
9
+ privateKey: Hex;
10
+ signMessage(msg: string | {
11
+ raw: Hex;
12
+ }): Promise<Hex>;
13
+ };
14
+ }
15
+ export declare class SessionManager {
16
+ private readonly opts;
17
+ constructor(opts: {
18
+ keyCustody: A2AKeyProvider;
19
+ store: SessionStore;
20
+ ttlSeconds?: number;
21
+ /** Allow tests/clock injection. Default: Date.now() */
22
+ now?: () => number;
23
+ });
24
+ private nowMs;
25
+ /**
26
+ * Generate a fresh session keypair, encrypt {sessionPrivateKey} (no
27
+ * delegation yet) at rest, persist as pending. Returns the sessionId and
28
+ * sessionKeyAddress to hand back to the user/web app.
29
+ */
30
+ init(accountAddress: Address, chainId: number): Promise<{
31
+ sessionId: string;
32
+ sessionKeyAddress: Address;
33
+ }>;
34
+ /**
35
+ * Receive a fully-signed Delegation, unwrap the pending session, re-encrypt
36
+ * the full {sessionPrivateKey, delegation} package, mark active.
37
+ */
38
+ package(sessionId: string, delegation: Delegation): Promise<void>;
39
+ /**
40
+ * Decrypt an active session and return the session signer + delegation.
41
+ * Refuses pending/revoked/expired rows. Signer never holds the private
42
+ * key longer than this call; callers should mint tokens with it
43
+ * immediately and drop the reference.
44
+ */
45
+ resolve(sessionId: string): Promise<SessionResolveResult>;
46
+ revoke(sessionId: string): Promise<void>;
47
+ private requirePending;
48
+ }
49
+ export declare function createMemorySessionStore(): SessionStore;
50
+ export { keccak256 };
51
+ //# sourceMappingURL=session-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../src/session-manager.ts"],"names":[],"mappings":"AAeA,OAAO,EAGL,SAAS,EAET,KAAK,OAAO,EACZ,KAAK,GAAG,EACT,MAAM,MAAM,CAAC;AACd,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EAGX,YAAY,EACb,MAAM,SAAS,CAAC;AA2EjB,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,WAAW,CAAC;IAClB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE;QACN,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,EAAE,GAAG,CAAC;QAChB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG;YAAE,GAAG,EAAE,GAAG,CAAA;SAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;KACvD,CAAC;CACH;AAED,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE;QACrB,UAAU,EAAE,cAAc,CAAC;QAC3B,KAAK,EAAE,YAAY,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,uDAAuD;QACvD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;KACpB;IAGH,OAAO,CAAC,KAAK;IAIb;;;;OAIG;IACG,IAAI,CACR,cAAc,EAAE,OAAO,EACvB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,OAAO,CAAA;KAAE,CAAC;IA4C7D;;;OAGG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAuCvE;;;;;OAKG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IA4DzD,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAIhC,cAAc;CAQ7B;AAID,wBAAgB,wBAAwB,IAAI,YAAY,CAkBvD;AAeD,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -0,0 +1,259 @@
1
+ // SessionManager — owns the session lifecycle per spec 202 §5.
2
+ //
3
+ // Lifecycle: init → package → resolve → revoke / expired.
4
+ // init generates a fresh session keypair, persists encrypted-pending
5
+ // row via the SessionStore (data key generated through the
6
+ // A2AKeyProvider from @agenticprimitives/key-custody).
7
+ // package caller submits a user-signed Delegation; SessionManager
8
+ // re-encrypts {sessionPrivateKey, delegation} as the full
9
+ // package, marks the row active.
10
+ // resolve decrypts the package, hands back a viem-compatible signer
11
+ // over the session private key, plus the bound delegation.
12
+ // revoke marks the row revoked; callers must mint a new session.
13
+ import { secp256k1 } from '@noble/curves/secp256k1';
14
+ import { keccak_256 } from '@noble/hashes/sha3';
15
+ import { bytesToHex, hexToBytes, keccak256, toBytes, } from 'viem';
16
+ import { canonicalContextBytes } from '@agenticprimitives/key-custody';
17
+ function randomBytes(n) {
18
+ const out = new Uint8Array(n);
19
+ globalThis.crypto.getRandomValues(out);
20
+ return out;
21
+ }
22
+ function generateSessionId() {
23
+ const buf = randomBytes(16);
24
+ let s = 'sa_';
25
+ for (const b of buf)
26
+ s += b.toString(16).padStart(2, '0');
27
+ return s;
28
+ }
29
+ function publicKeyToAddress(pub) {
30
+ const raw = pub.length === 65 ? pub.slice(1) : pub;
31
+ const hash = keccak_256(raw);
32
+ return bytesToHex(hash.slice(12));
33
+ }
34
+ function sessionIdHash(sessionId) {
35
+ const h = keccak_256(new TextEncoder().encode(sessionId));
36
+ let s = '';
37
+ for (const b of h.slice(0, 16))
38
+ s += b.toString(16).padStart(2, '0');
39
+ return s;
40
+ }
41
+ function buildAad(meta, keyVersion) {
42
+ return {
43
+ session_id_h: sessionIdHash(meta.sessionId),
44
+ account_address: meta.accountAddress.toLowerCase(),
45
+ chain_id: String(meta.chainId),
46
+ expires_at: meta.expiresAt,
47
+ key_version: keyVersion,
48
+ };
49
+ }
50
+ // TS strict-mode quirk: Web Crypto types want ArrayBuffer specifically; Uint8Array
51
+ // over a ArrayBufferLike (could be SharedArrayBuffer) doesn't fit. Cast through
52
+ // BufferSource — these are all locally-allocated, never shared.
53
+ function asBufferSource(b) {
54
+ return b;
55
+ }
56
+ async function aesGcmEncrypt(key, iv, plaintext, aad) {
57
+ const cryptoKey = await globalThis.crypto.subtle.importKey('raw', asBufferSource(key), 'AES-GCM', false, ['encrypt']);
58
+ const ct = await globalThis.crypto.subtle.encrypt({ name: 'AES-GCM', iv: asBufferSource(iv), additionalData: asBufferSource(aad) }, cryptoKey, asBufferSource(plaintext));
59
+ return new Uint8Array(ct);
60
+ }
61
+ async function aesGcmDecrypt(key, iv, ciphertext, aad) {
62
+ const cryptoKey = await globalThis.crypto.subtle.importKey('raw', asBufferSource(key), 'AES-GCM', false, ['decrypt']);
63
+ const pt = await globalThis.crypto.subtle.decrypt({ name: 'AES-GCM', iv: asBufferSource(iv), additionalData: asBufferSource(aad) }, cryptoKey, asBufferSource(ciphertext));
64
+ return new Uint8Array(pt);
65
+ }
66
+ export class SessionManager {
67
+ opts;
68
+ constructor(opts) {
69
+ this.opts = opts;
70
+ }
71
+ nowMs() {
72
+ return (this.opts.now ?? Date.now)();
73
+ }
74
+ /**
75
+ * Generate a fresh session keypair, encrypt {sessionPrivateKey} (no
76
+ * delegation yet) at rest, persist as pending. Returns the sessionId and
77
+ * sessionKeyAddress to hand back to the user/web app.
78
+ */
79
+ async init(accountAddress, chainId) {
80
+ const sessionId = generateSessionId();
81
+ const ttl = (this.opts.ttlSeconds ?? 24 * 60 * 60) * 1000;
82
+ const expiresAt = new Date(this.nowMs() + ttl).toISOString();
83
+ // Fresh secp256k1 keypair
84
+ const priv = randomBytes(32);
85
+ // secp256k1 priv keys MUST be in [1, n-1]. Retry on rare overflow / zero.
86
+ if (!secp256k1.utils.isValidPrivateKey(priv)) {
87
+ return this.init(accountAddress, chainId); // recurse — vanishingly rare
88
+ }
89
+ const pub = secp256k1.getPublicKey(priv, false);
90
+ const sessionKeyAddress = publicKeyToAddress(pub);
91
+ const meta = { sessionId, accountAddress, chainId, expiresAt };
92
+ // Encrypt the partial package (only sessionPrivateKey for now; delegation
93
+ // joins at /package).
94
+ const partialPayload = new TextEncoder().encode(JSON.stringify({ sessionPrivateKey: bytesToHex(priv) }));
95
+ const aadCtx = buildAad(meta, this.opts.keyCustody.keyVersion);
96
+ const aadBytes = canonicalContextBytes(aadCtx);
97
+ const wrap = await this.opts.keyCustody.generateSessionDataKey({ aadContext: aadCtx });
98
+ const iv = randomBytes(12);
99
+ const encryptedPackage = await aesGcmEncrypt(wrap.plaintextDataKey, iv, partialPayload, aadBytes);
100
+ const row = {
101
+ id: sessionId,
102
+ accountAddress,
103
+ chainId,
104
+ sessionKeyAddress,
105
+ status: 'pending',
106
+ encryptedPackage,
107
+ iv,
108
+ encryptedDataKey: wrap.encryptedDataKey,
109
+ keyVersion: wrap.keyVersion,
110
+ expiresAt,
111
+ createdAt: new Date(this.nowMs()).toISOString(),
112
+ };
113
+ await this.opts.store.save(row);
114
+ return { sessionId, sessionKeyAddress };
115
+ }
116
+ /**
117
+ * Receive a fully-signed Delegation, unwrap the pending session, re-encrypt
118
+ * the full {sessionPrivateKey, delegation} package, mark active.
119
+ */
120
+ async package(sessionId, delegation) {
121
+ const row = await this.requirePending(sessionId);
122
+ const meta = {
123
+ sessionId,
124
+ accountAddress: row.accountAddress,
125
+ chainId: row.chainId,
126
+ expiresAt: row.expiresAt,
127
+ };
128
+ // Decrypt the current partial payload to extract the sessionPrivateKey.
129
+ const aadCtx = buildAad(meta, row.keyVersion);
130
+ const aadBytes = canonicalContextBytes(aadCtx);
131
+ const dk = await this.opts.keyCustody.decryptSessionDataKey({
132
+ encryptedDataKey: row.encryptedDataKey,
133
+ aadContext: aadCtx,
134
+ keyId: 'local-master',
135
+ keyVersion: row.keyVersion,
136
+ });
137
+ const partial = await aesGcmDecrypt(dk, row.iv, row.encryptedPackage, aadBytes);
138
+ const parsed = JSON.parse(new TextDecoder().decode(partial));
139
+ // Re-encrypt the full package with a fresh IV (data key stays the same).
140
+ const fullPayload = new TextEncoder().encode(JSON.stringify({
141
+ sessionPrivateKey: parsed.sessionPrivateKey,
142
+ delegation: serializableDelegation(delegation),
143
+ }));
144
+ const newIv = randomBytes(12);
145
+ const encryptedPackage = await aesGcmEncrypt(dk, newIv, fullPayload, aadBytes);
146
+ const updated = {
147
+ ...row,
148
+ status: 'active',
149
+ encryptedPackage,
150
+ iv: newIv,
151
+ };
152
+ await this.opts.store.save(updated);
153
+ }
154
+ /**
155
+ * Decrypt an active session and return the session signer + delegation.
156
+ * Refuses pending/revoked/expired rows. Signer never holds the private
157
+ * key longer than this call; callers should mint tokens with it
158
+ * immediately and drop the reference.
159
+ */
160
+ async resolve(sessionId) {
161
+ const row = await this.opts.store.get(sessionId);
162
+ if (!row)
163
+ throw new Error(`SessionManager.resolve: session "${sessionId}" not found`);
164
+ if (row.status !== 'active') {
165
+ throw new Error(`SessionManager.resolve: session is "${row.status}"`);
166
+ }
167
+ const now = this.nowMs();
168
+ if (Date.parse(row.expiresAt) < now) {
169
+ throw new Error('SessionManager.resolve: session expired');
170
+ }
171
+ const meta = {
172
+ sessionId,
173
+ accountAddress: row.accountAddress,
174
+ chainId: row.chainId,
175
+ expiresAt: row.expiresAt,
176
+ };
177
+ const aadCtx = buildAad(meta, row.keyVersion);
178
+ const aadBytes = canonicalContextBytes(aadCtx);
179
+ const dk = await this.opts.keyCustody.decryptSessionDataKey({
180
+ encryptedDataKey: row.encryptedDataKey,
181
+ aadContext: aadCtx,
182
+ keyId: 'local-master',
183
+ keyVersion: row.keyVersion,
184
+ });
185
+ const pt = await aesGcmDecrypt(dk, row.iv, row.encryptedPackage, aadBytes);
186
+ const pkg = JSON.parse(new TextDecoder().decode(pt));
187
+ const priv = hexToBytes(pkg.sessionPrivateKey);
188
+ const address = publicKeyToAddress(secp256k1.getPublicKey(priv, false));
189
+ return {
190
+ meta,
191
+ delegation: pkg.delegation ? deserializeDelegation(pkg.delegation) : null,
192
+ signer: {
193
+ address,
194
+ privateKey: pkg.sessionPrivateKey,
195
+ signMessage: async (msg) => {
196
+ let digest;
197
+ if (typeof msg === 'string') {
198
+ const bytes = new TextEncoder().encode(msg);
199
+ const prefix = new TextEncoder().encode(`\x19Ethereum Signed Message:\n${bytes.length}`);
200
+ const combined = new Uint8Array(prefix.length + bytes.length);
201
+ combined.set(prefix, 0);
202
+ combined.set(bytes, prefix.length);
203
+ digest = keccak_256(combined);
204
+ }
205
+ else {
206
+ digest = toBytes(msg.raw);
207
+ }
208
+ const sig = secp256k1.sign(digest, priv);
209
+ const r = sig.r.toString(16).padStart(64, '0');
210
+ const s = sig.s.toString(16).padStart(64, '0');
211
+ const v = (sig.recovery ?? 0) + 27;
212
+ return ('0x' + r + s + v.toString(16).padStart(2, '0'));
213
+ },
214
+ },
215
+ };
216
+ }
217
+ async revoke(sessionId) {
218
+ await this.opts.store.revoke(sessionId);
219
+ }
220
+ async requirePending(sessionId) {
221
+ const row = await this.opts.store.get(sessionId);
222
+ if (!row)
223
+ throw new Error(`SessionManager: session "${sessionId}" not found`);
224
+ if (row.status !== 'pending') {
225
+ throw new Error(`SessionManager.package: session is "${row.status}", expected "pending"`);
226
+ }
227
+ return row;
228
+ }
229
+ }
230
+ // ─── Memory store ─────────────────────────────────────────────────────────
231
+ export function createMemorySessionStore() {
232
+ const rows = new Map();
233
+ return {
234
+ async save(row) {
235
+ rows.set(row.id, row);
236
+ },
237
+ async get(id) {
238
+ return rows.get(id) ?? null;
239
+ },
240
+ async list(accountAddress) {
241
+ return [...rows.values()].filter((r) => r.accountAddress.toLowerCase() === accountAddress.toLowerCase());
242
+ },
243
+ async revoke(id) {
244
+ const row = rows.get(id);
245
+ if (!row)
246
+ return;
247
+ rows.set(id, { ...row, status: 'revoked', revokedAt: new Date().toISOString() });
248
+ },
249
+ };
250
+ }
251
+ function serializableDelegation(d) {
252
+ return { ...d, salt: d.salt.toString() };
253
+ }
254
+ function deserializeDelegation(d) {
255
+ return { ...d, salt: BigInt(d.salt) };
256
+ }
257
+ // keccak256 is exported for convenience to keep the contract clean for tests
258
+ export { keccak256 };
259
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../src/session-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,158 @@
1
+ import { type Address, type Hex } from 'viem';
2
+ import type { DelegationTokenClaims, VerifyError, VerifyOpts, DataScopeGrant } from './types';
3
+ import { type AuditSink } from '@agenticprimitives/audit';
4
+ /** Sorted-key JSON; BigInt → numeric string. Both sides must produce the
5
+ * exact same bytes for the signature to round-trip.
6
+ *
7
+ * Exported for cross-runtime golden-test fixtures. Stability of this
8
+ * function is a SECURITY INVARIANT — any byte-level drift across
9
+ * runtimes (Node, Bun, browser, Cloudflare Workers) means the same
10
+ * claims hash to different signatures, breaking token verification
11
+ * silently. */
12
+ export declare function canonicalJSON(value: unknown): string;
13
+ export declare function mintDelegationToken(claims: Omit<DelegationTokenClaims, 'iat' | 'exp' | 'jti'> & {
14
+ jti?: string;
15
+ ttlSeconds?: number;
16
+ }, signMessage: (msg: string) => Promise<Hex>, opts?: {
17
+ /** Audit sink (C3 pass 3c). Emits `delegation.mint` per call. */
18
+ auditSink?: AuditSink;
19
+ correlationId?: string;
20
+ /**
21
+ * Production guard — reject mints whose `ttlSeconds` exceeds this.
22
+ * Defaults to `DEFAULT_MAX_TTL_SECONDS` (1h). Set higher only with
23
+ * `acceptElevatedRisk: true`.
24
+ */
25
+ maxAllowedTtlSeconds?: number;
26
+ /**
27
+ * Production guard — reject mints whose `usageLimit` exceeds this.
28
+ * Defaults to `DEFAULT_MAX_USAGE_LIMIT` (100). Set higher only with
29
+ * `acceptElevatedRisk: true`.
30
+ */
31
+ maxAllowedUsageLimit?: number;
32
+ /**
33
+ * Required when caller wants TTL > 1h OR usage > 100. Forces a
34
+ * deliberate "I know this is a long-lived elevated-blast-radius
35
+ * token" decision rather than silent permissive defaults.
36
+ */
37
+ acceptElevatedRisk?: boolean;
38
+ }): Promise<{
39
+ token: string;
40
+ jti: string;
41
+ }>;
42
+ export interface VerifyOptsExt extends VerifyOpts {
43
+ /** Tool name for mcp-tool-scope caveat evaluation. */
44
+ toolName?: string;
45
+ /**
46
+ * Whether to require the delegator's smart account to be on-chain.
47
+ * Default: `true` (fail-closed). When the account isn't deployed,
48
+ * ERC-1271 can't be verified and the security model is broken.
49
+ *
50
+ * Demo flows that intentionally use counterfactual addresses without
51
+ * deploying may pass `false` to tolerate the undeployed state. Production
52
+ * code MUST keep the default — there's no scenario where an undeployed
53
+ * delegator should be honored.
54
+ */
55
+ requireDeployed?: boolean;
56
+ /**
57
+ * Revocation read failure behavior. Audit finding H3.
58
+ *
59
+ * - `'closed'` (DEFAULT — H7-B.9 / XPKG-005 closure): if `isRevoked()`
60
+ * RPC read throws, the whole verification fails with
61
+ * `revocation check unavailable`. Safe under RPC outage: a revoked
62
+ * delegation cannot be silently accepted.
63
+ * - `'open'`: tolerate the RPC failure and continue. Appropriate ONLY
64
+ * for explicit demo/dev paths where RPC flakiness is expected. Must
65
+ * be set explicitly — the previous NODE_ENV-keyed default could
66
+ * silently fall open on Cloudflare Workers / SES runtimes (where
67
+ * `process.env.NODE_ENV` is undefined).
68
+ */
69
+ revocationFailMode?: 'closed' | 'open';
70
+ /**
71
+ * Audit sink (audit C3 pass 3b). When provided, every verify outcome
72
+ * emits a `delegation.verify.{accept,reject}` event. The principal
73
+ * goes in `actor`, the delegation hash in `subject`. The token JTI
74
+ * (claims.jti) is hashed before logging to avoid surfacing the
75
+ * one-shot identifier in the forensics trail beyond the minimum
76
+ * needed for correlation.
77
+ *
78
+ * Fail-soft: emit failures never break the verify flow.
79
+ */
80
+ auditSink?: AuditSink;
81
+ /** Correlation ID threaded into emitted events. */
82
+ correlationId?: string;
83
+ /**
84
+ * When set, the delegation MUST carry a caveat with an `enforcer`
85
+ * matching this address. The redeem-time signature check happens
86
+ * on-chain inside the `QuorumEnforcer.beforeHook` (packages/contracts/
87
+ * src/enforcers/QuorumEnforcer.sol); this opt's role is to fail
88
+ * closed at the OFF-CHAIN layer when a delegation was issued
89
+ * without the required quorum caveat at all. Without this opt set,
90
+ * delegation does NOT require quorum — backwards-compatible for
91
+ * T1/T2 tier flows that don't need it.
92
+ *
93
+ * Use case (mcp-runtime sets it for T3+ tools):
94
+ * evaluateThresholdPolicy(classification).requiresQuorum
95
+ * ? { enforcer: deployments.quorumEnforcer }
96
+ * : undefined
97
+ */
98
+ requireQuorumCaveat?: {
99
+ enforcer: Address;
100
+ };
101
+ /**
102
+ * Quorum-enforcement proof (audit H3). Required whenever
103
+ * `requireQuorumCaveat` is set. Picks ONE of two enforcement models:
104
+ *
105
+ * - `{ mode: 'on-chain-redeemed' }` — the caller asserts that the
106
+ * authorized call will go through `DelegationManager.redeemDelegation`,
107
+ * which invokes `QuorumEnforcer.beforeHook` and verifies the
108
+ * packed signatures on chain against the bound execution payload.
109
+ * Use this for any flow that actually broadcasts a UserOp /
110
+ * transaction that hits the on-chain enforcer.
111
+ *
112
+ * - `{ mode: 'off-chain', payloadHash, packedSignatures }` — for
113
+ * MCP-only / data-tool flows that never reach the on-chain
114
+ * enforcer. The verifier MUST validate the packed signatures
115
+ * off-chain against `payloadHash` (which the caller binds to
116
+ * the tool/action context) AND against the signer set encoded
117
+ * in the QuorumCaveat terms. This mode currently throws with
118
+ * `quorum_off_chain_not_implemented` — wire-format is reserved
119
+ * so consumers can plan migration; the verification logic
120
+ * ships in a follow-up wave once the bound payload format is
121
+ * spec'd in `specs/207-smart-account-threshold-policy.md` §
122
+ * "off-chain quorum".
123
+ *
124
+ * If `requireQuorumCaveat` is set without a `quorumProof`, the
125
+ * verifier rejects. This makes the off-chain enforcement gap
126
+ * structural — a consumer can't silently rely on caveat presence
127
+ * as a substitute for signature verification.
128
+ */
129
+ quorumProof?: {
130
+ mode: 'on-chain-redeemed';
131
+ } | {
132
+ mode: 'off-chain';
133
+ payloadHash: Hex;
134
+ packedSignatures: Hex;
135
+ };
136
+ /**
137
+ * When `true`, verify that the delegator's smart account has
138
+ * pre-blessed this delegation hash on-chain via
139
+ * `acceptSessionDelegation(hash)`. Spec 207 § 6 high-risk gate —
140
+ * critical-tier tool calls require an explicit on-chain
141
+ * authorization so a quorum at issuance isn't sufficient on its
142
+ * own; the user must additionally commit the specific delegation
143
+ * hash with a chain-visible transaction.
144
+ *
145
+ * Audit emit captures this as `context.acceptedOnChain: true` on
146
+ * the accept row so forensics can distinguish high-value flows.
147
+ */
148
+ requireAcceptedOnChain?: boolean;
149
+ }
150
+ /**
151
+ * Full verification pipeline. Caller passes `toolName` in opts for tool-scope
152
+ * caveat evaluation; without it the mcp-tool-scope caveat denies.
153
+ */
154
+ export declare function verifyDelegationToken(token: string, opts: VerifyOptsExt): Promise<{
155
+ principal: Address;
156
+ grants?: DataScopeGrant[];
157
+ } | VerifyError>;
158
+ //# sourceMappingURL=token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAeA,OAAO,EAA4B,KAAK,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AACxE,OAAO,KAAK,EAEV,qBAAqB,EACrB,WAAW,EACX,UAAU,EACV,cAAc,EACf,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAwBtE;;;;;;;gBAOgB;AAChB,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAsBpD;AAiDD,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,IAAI,CAAC,qBAAqB,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAClG,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,EAC1C,IAAI,CAAC,EAAE;IACL,iEAAiE;IACjE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,GACA,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CA2EzC;AAuCD,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;;;;;;OAYG;IACH,kBAAkB,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACvC;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;IASvB;;;;;;;;;;;;;;OAcG;IACH,mBAAmB,CAAC,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,WAAW,CAAC,EACR;QAAE,IAAI,EAAE,mBAAmB,CAAA;KAAE,GAC7B;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,WAAW,EAAE,GAAG,CAAC;QAAC,gBAAgB,EAAE,GAAG,CAAA;KAAE,CAAC;IAEnE;;;;;;;;;;;OAWG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AA+BD;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,cAAc,EAAE,CAAA;CAAE,GAAG,WAAW,CAAC,CAgQ1E"}