agent-authority 0.1.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.
Files changed (85) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/LICENSE +21 -0
  3. package/QUICKSTART.md +91 -0
  4. package/README.md +553 -0
  5. package/dist/a2a.d.ts +73 -0
  6. package/dist/a2a.d.ts.map +1 -0
  7. package/dist/a2a.js +117 -0
  8. package/dist/a2a.js.map +1 -0
  9. package/dist/audit.d.ts +12 -0
  10. package/dist/audit.d.ts.map +1 -0
  11. package/dist/audit.js +52 -0
  12. package/dist/audit.js.map +1 -0
  13. package/dist/behalf.d.ts +173 -0
  14. package/dist/behalf.d.ts.map +1 -0
  15. package/dist/behalf.js +475 -0
  16. package/dist/behalf.js.map +1 -0
  17. package/dist/capability.d.ts +56 -0
  18. package/dist/capability.d.ts.map +1 -0
  19. package/dist/capability.js +176 -0
  20. package/dist/capability.js.map +1 -0
  21. package/dist/cli.d.ts +3 -0
  22. package/dist/cli.d.ts.map +1 -0
  23. package/dist/cli.js +273 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/control-plane.d.ts +57 -0
  26. package/dist/control-plane.d.ts.map +1 -0
  27. package/dist/control-plane.js +332 -0
  28. package/dist/control-plane.js.map +1 -0
  29. package/dist/crypto.d.ts +68 -0
  30. package/dist/crypto.d.ts.map +1 -0
  31. package/dist/crypto.js +105 -0
  32. package/dist/crypto.js.map +1 -0
  33. package/dist/errors.d.ts +25 -0
  34. package/dist/errors.d.ts.map +1 -0
  35. package/dist/errors.js +40 -0
  36. package/dist/errors.js.map +1 -0
  37. package/dist/index.d.ts +35 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +34 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/lint.d.ts +17 -0
  42. package/dist/lint.d.ts.map +1 -0
  43. package/dist/lint.js +75 -0
  44. package/dist/lint.js.map +1 -0
  45. package/dist/mandate.d.ts +99 -0
  46. package/dist/mandate.d.ts.map +1 -0
  47. package/dist/mandate.js +141 -0
  48. package/dist/mandate.js.map +1 -0
  49. package/dist/mcp-server.d.ts +26 -0
  50. package/dist/mcp-server.d.ts.map +1 -0
  51. package/dist/mcp-server.js +111 -0
  52. package/dist/mcp-server.js.map +1 -0
  53. package/dist/mcp.d.ts +63 -0
  54. package/dist/mcp.d.ts.map +1 -0
  55. package/dist/mcp.js +123 -0
  56. package/dist/mcp.js.map +1 -0
  57. package/dist/persist.d.ts +51 -0
  58. package/dist/persist.d.ts.map +1 -0
  59. package/dist/persist.js +150 -0
  60. package/dist/persist.js.map +1 -0
  61. package/dist/quickstart.d.ts +63 -0
  62. package/dist/quickstart.d.ts.map +1 -0
  63. package/dist/quickstart.js +171 -0
  64. package/dist/quickstart.js.map +1 -0
  65. package/dist/remote.d.ts +93 -0
  66. package/dist/remote.d.ts.map +1 -0
  67. package/dist/remote.js +120 -0
  68. package/dist/remote.js.map +1 -0
  69. package/dist/seal.d.ts +12 -0
  70. package/dist/seal.d.ts.map +1 -0
  71. package/dist/seal.js +96 -0
  72. package/dist/seal.js.map +1 -0
  73. package/dist/store.d.ts +119 -0
  74. package/dist/store.d.ts.map +1 -0
  75. package/dist/store.js +139 -0
  76. package/dist/store.js.map +1 -0
  77. package/dist/types.d.ts +173 -0
  78. package/dist/types.d.ts.map +1 -0
  79. package/dist/types.js +17 -0
  80. package/dist/types.js.map +1 -0
  81. package/llms.txt +106 -0
  82. package/package.json +107 -0
  83. package/schemas/capability.schema.json +14 -0
  84. package/schemas/mandate.schema.json +68 -0
  85. package/vectors/mandate-vector.json +63 -0
@@ -0,0 +1,93 @@
1
+ import type { AuditEntry, AuditFields } from "./types.js";
2
+ import type { AuditStore, RevocationStore, RateStore } from "./store.js";
3
+ /**
4
+ * Client stores that back an engine with a remote {@link createControlPlane}.
5
+ * Drop them into `createBehalf({ revocations, audit })` and revocation
6
+ * propagates across every agent pointed at the same control plane, while audit
7
+ * is retained centrally — with the five-verb API and enforcement unchanged.
8
+ */
9
+ export interface RemoteOptions {
10
+ /** Bearer token, if the control plane requires one. */
11
+ token?: string;
12
+ /** Injectable fetch (defaults to global fetch) — handy for tests. */
13
+ fetch?: typeof fetch;
14
+ }
15
+ declare class RemoteBase {
16
+ protected readonly base: string;
17
+ protected readonly fetch: typeof fetch;
18
+ private readonly token?;
19
+ constructor(baseUrl: string, opts?: RemoteOptions);
20
+ protected headers(): Record<string, string>;
21
+ protected get<T>(path: string): Promise<T>;
22
+ protected post<T>(path: string, body: unknown): Promise<T>;
23
+ }
24
+ /** Revocation backed by the control plane — revoke once, propagates to all. */
25
+ export declare class HttpRevocationStore extends RemoteBase implements RevocationStore {
26
+ revoke(id: string): Promise<void>;
27
+ isRevoked(id: string): Promise<boolean>;
28
+ }
29
+ /** Tamper-evident audit retained centrally by the control plane. */
30
+ export declare class HttpAuditStore extends RemoteBase implements AuditStore {
31
+ /** One round-trip per record; the control plane (single writer) seals it. */
32
+ record(fields: AuditFields): Promise<AuditEntry>;
33
+ append(entry: AuditEntry): Promise<void>;
34
+ all(): Promise<AuditEntry[]>;
35
+ forMandate(mandateId: string): Promise<AuditEntry[]>;
36
+ forIssuer(issuer: string): Promise<AuditEntry[]>;
37
+ }
38
+ /** Rate limiting enforced centrally — one cap shared across all agents. */
39
+ export declare class HttpRateStore extends RemoteBase implements RateStore {
40
+ hit(key: string, windowMs: number, limit: number, _now: number): Promise<boolean>;
41
+ }
42
+ /** Lightweight typed client for the consent + policy endpoints. */
43
+ export declare class ControlPlaneClient extends RemoteBase {
44
+ requestConsent(agent: string, capability: string, context?: Record<string, unknown>): Promise<{
45
+ id: string;
46
+ status: string;
47
+ }>;
48
+ getConsent(id: string): Promise<{
49
+ id: string;
50
+ status: string;
51
+ }>;
52
+ decideConsent(id: string, approve: boolean): Promise<{
53
+ id: string;
54
+ status: string;
55
+ }>;
56
+ getPolicy<T = unknown>(name: string): Promise<{
57
+ name: string;
58
+ policy: T;
59
+ }>;
60
+ putPolicy<T = unknown>(name: string, policy: T): Promise<{
61
+ name: string;
62
+ policy: T;
63
+ }>;
64
+ }
65
+ export interface ConsentProviderOptions {
66
+ /** How often to poll for a decision. Default 500ms. */
67
+ pollMs?: number;
68
+ /** Give up (deny) after this long. Default 30s. */
69
+ timeoutMs?: number;
70
+ /** Called with the pending record's id — surface it to a dashboard/approver. */
71
+ onPending?: (record: {
72
+ id: string;
73
+ }) => void;
74
+ /** Injectable sleep — handy for tests. */
75
+ sleep?: (ms: number) => Promise<void>;
76
+ }
77
+ /** Info the middleware passes to a just-in-time consent decision. */
78
+ export interface ConsentRequest {
79
+ tool?: string;
80
+ capability: string;
81
+ mandate?: {
82
+ agent?: string;
83
+ };
84
+ }
85
+ /**
86
+ * A consent provider backed by the control plane. Use it as `withBehalf`'s
87
+ * `onPrompt`: on a denied call it opens a pending consent request, then polls
88
+ * until a human approves/denies it (via the dashboard or `decideConsent`),
89
+ * wiring the control plane's consent surface to enforcement end-to-end.
90
+ */
91
+ export declare function controlPlaneConsent(client: ControlPlaneClient, opts?: ConsentProviderOptions): (info: ConsentRequest) => Promise<boolean>;
92
+ export {};
93
+ //# sourceMappingURL=remote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"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"}
package/dist/remote.js ADDED
@@ -0,0 +1,120 @@
1
+ class RemoteBase {
2
+ base;
3
+ fetch;
4
+ token;
5
+ constructor(baseUrl, opts = {}) {
6
+ this.base = baseUrl.replace(/\/$/, "");
7
+ this.fetch = opts.fetch ?? fetch;
8
+ this.token = opts.token;
9
+ }
10
+ headers() {
11
+ const h = { "content-type": "application/json" };
12
+ if (this.token)
13
+ h["authorization"] = `Bearer ${this.token}`;
14
+ return h;
15
+ }
16
+ async get(path) {
17
+ const res = await this.fetch(this.base + path, { headers: this.headers() });
18
+ if (!res.ok)
19
+ throw new Error(`control plane ${res.status} for GET ${path}`);
20
+ return (await res.json());
21
+ }
22
+ async post(path, body) {
23
+ const res = await this.fetch(this.base + path, {
24
+ method: "POST",
25
+ headers: this.headers(),
26
+ body: JSON.stringify(body),
27
+ });
28
+ if (!res.ok)
29
+ throw new Error(`control plane ${res.status} for POST ${path}`);
30
+ return (await res.json());
31
+ }
32
+ }
33
+ /** Revocation backed by the control plane — revoke once, propagates to all. */
34
+ export class HttpRevocationStore extends RemoteBase {
35
+ async revoke(id) {
36
+ await this.post("/v1/revoke", { id });
37
+ }
38
+ async isRevoked(id) {
39
+ const { revoked } = await this.get(`/v1/revoked/${encodeURIComponent(id)}`);
40
+ return revoked;
41
+ }
42
+ }
43
+ /** Tamper-evident audit retained centrally by the control plane. */
44
+ export class HttpAuditStore extends RemoteBase {
45
+ /** One round-trip per record; the control plane (single writer) seals it. */
46
+ async record(fields) {
47
+ return (await this.post("/v1/audit", { fields })).entry;
48
+ }
49
+ async append(entry) {
50
+ await this.post("/v1/audit", { entry });
51
+ }
52
+ async all() {
53
+ return (await this.get("/v1/audit")).entries;
54
+ }
55
+ async forMandate(mandateId) {
56
+ return (await this.get(`/v1/audit/${encodeURIComponent(mandateId)}`)).entries;
57
+ }
58
+ async forIssuer(issuer) {
59
+ return (await this.get(`/v1/audit?issuer=${encodeURIComponent(issuer)}`)).entries;
60
+ }
61
+ }
62
+ /** Rate limiting enforced centrally — one cap shared across all agents. */
63
+ export class HttpRateStore extends RemoteBase {
64
+ async hit(key, windowMs, limit, _now) {
65
+ // `now` is intentionally NOT sent — the control plane stamps each hit with
66
+ // its own clock, so a skewed or hostile client can't shift the window.
67
+ return (await this.post("/v1/rate", { key, windowMs, limit })).allowed;
68
+ }
69
+ }
70
+ /** Lightweight typed client for the consent + policy endpoints. */
71
+ export class ControlPlaneClient extends RemoteBase {
72
+ requestConsent(agent, capability, context) {
73
+ return this.post("/v1/consent", { agent, capability, context });
74
+ }
75
+ getConsent(id) {
76
+ return this.get(`/v1/consent/${encodeURIComponent(id)}`);
77
+ }
78
+ decideConsent(id, approve) {
79
+ return this.post(`/v1/consent/${encodeURIComponent(id)}/decision`, { approve });
80
+ }
81
+ getPolicy(name) {
82
+ return this.get(`/v1/policy/${encodeURIComponent(name)}`);
83
+ }
84
+ async putPolicy(name, policy) {
85
+ const res = await this.fetch(`${this.base}/v1/policy/${encodeURIComponent(name)}`, {
86
+ method: "PUT",
87
+ headers: this.headers(),
88
+ body: JSON.stringify({ policy }),
89
+ });
90
+ if (!res.ok)
91
+ throw new Error(`control plane ${res.status} for PUT policy`);
92
+ return (await res.json());
93
+ }
94
+ }
95
+ /**
96
+ * A consent provider backed by the control plane. Use it as `withBehalf`'s
97
+ * `onPrompt`: on a denied call it opens a pending consent request, then polls
98
+ * until a human approves/denies it (via the dashboard or `decideConsent`),
99
+ * wiring the control plane's consent surface to enforcement end-to-end.
100
+ */
101
+ export function controlPlaneConsent(client, opts = {}) {
102
+ const pollMs = opts.pollMs ?? 500;
103
+ const timeoutMs = opts.timeoutMs ?? 30_000;
104
+ const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
105
+ return async (info) => {
106
+ const agent = info.mandate?.agent ?? info.tool ?? "agent";
107
+ const rec = await client.requestConsent(agent, info.capability, { tool: info.tool });
108
+ opts.onPending?.(rec);
109
+ const deadline = Date.now() + timeoutMs;
110
+ while (Date.now() < deadline) {
111
+ const cur = await client.getConsent(rec.id);
112
+ // Any terminal state other than approved (denied, expired, …) is a deny.
113
+ if (cur.status !== "pending")
114
+ return cur.status === "approved";
115
+ await sleep(pollMs);
116
+ }
117
+ return false; // timed out → deny
118
+ };
119
+ }
120
+ //# sourceMappingURL=remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"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"}
package/dist/seal.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /** An X25519 keypair for sealing, as base64url raw 32-byte keys. */
2
+ export interface SealKeyPair {
3
+ publicKey: string;
4
+ privateKey: string;
5
+ }
6
+ /** Generate an X25519 sealing keypair (publish `publicKey`, keep `privateKey`). */
7
+ export declare function newSealKeyPair(): SealKeyPair;
8
+ /** Encrypt `plaintext` so only the holder of `recipientPublicKey`'s key can read it. */
9
+ export declare function seal(plaintext: string, recipientPublicKey: string): string;
10
+ /** Decrypt a `seal-1` credential with the recipient's sealing keypair. */
11
+ export declare function unseal(sealed: string, recipient: SealKeyPair): string;
12
+ //# sourceMappingURL=seal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seal.d.ts","sourceRoot":"","sources":["../src/seal.ts"],"names":[],"mappings":"AAsCA,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAmBD,mFAAmF;AACnF,wBAAgB,cAAc,IAAI,WAAW,CAK5C;AAED,wFAAwF;AACxF,wBAAgB,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAmB1E;AAED,0EAA0E;AAC1E,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,GAAG,MAAM,CAwBrE"}
package/dist/seal.js ADDED
@@ -0,0 +1,96 @@
1
+ import { generateKeyPairSync, diffieHellman, createPublicKey, createPrivateKey, hkdfSync, createCipheriv, createDecipheriv, randomBytes, } from "node:crypto";
2
+ /**
3
+ * Sealed holder credentials (defense-in-depth for `serializeWithKey`).
4
+ *
5
+ * A holder credential is a secret; binding it to an agent identity (`bindAgent`)
6
+ * already makes a *stolen* credential inert, but the credential itself is still
7
+ * sensitive in transit/at rest. Sealing encrypts it to a specific recipient so
8
+ * only the holder of the matching private key can open it.
9
+ *
10
+ * Scheme `seal-1` — a standard ECIES construction over primitives available
11
+ * natively in Node and, in Python, via the `cryptography` backend, so a
12
+ * credential sealed in one port can be opened in the other:
13
+ *
14
+ * 1. ephemeral X25519 keypair `e`
15
+ * 2. shared = X25519(e_priv, recipient_pub)
16
+ * 3. key = HKDF-SHA256(ikm=shared, salt=e_pub‖recipient_pub, info="behalf-seal-v1", 32)
17
+ * 4. ct‖tag = AES-256-GCM(key, nonce=random12, aad="behalf-seal-v1", plaintext)
18
+ * 5. wire = base64url(JSON { v:"seal-1", epk, n, ct }) (ct carries the tag)
19
+ *
20
+ * The recipient's sealing key is an **X25519** keypair, separate from the
21
+ * Ed25519 agent-identity key used by `bindAgent` (different algorithms, different
22
+ * purposes). Generate one with {@link newSealKeyPair} and publish `publicKey`.
23
+ */
24
+ const INFO = Buffer.from("behalf-seal-v1");
25
+ const AAD = Buffer.from("behalf-seal-v1");
26
+ function rawPublic(key) {
27
+ const jwk = key.export({ format: "jwk" });
28
+ if (!jwk.x)
29
+ throw new Error("not an X25519 public key");
30
+ return Buffer.from(jwk.x, "base64url");
31
+ }
32
+ function importPublic(rawB64) {
33
+ return createPublicKey({ key: { kty: "OKP", crv: "X25519", x: rawB64 }, format: "jwk" });
34
+ }
35
+ function importPrivate(kp) {
36
+ return createPrivateKey({
37
+ key: { kty: "OKP", crv: "X25519", x: kp.publicKey, d: kp.privateKey },
38
+ format: "jwk",
39
+ });
40
+ }
41
+ /** Generate an X25519 sealing keypair (publish `publicKey`, keep `privateKey`). */
42
+ export function newSealKeyPair() {
43
+ const { publicKey, privateKey } = generateKeyPairSync("x25519");
44
+ const pubJwk = publicKey.export({ format: "jwk" });
45
+ const privJwk = privateKey.export({ format: "jwk" });
46
+ return { publicKey: pubJwk.x, privateKey: privJwk.d };
47
+ }
48
+ /** Encrypt `plaintext` so only the holder of `recipientPublicKey`'s key can read it. */
49
+ export function seal(plaintext, recipientPublicKey) {
50
+ const recipientPub = importPublic(recipientPublicKey);
51
+ const eph = generateKeyPairSync("x25519");
52
+ const shared = diffieHellman({ privateKey: eph.privateKey, publicKey: recipientPub });
53
+ const ephPubRaw = rawPublic(eph.publicKey);
54
+ const salt = Buffer.concat([ephPubRaw, Buffer.from(recipientPublicKey, "base64url")]);
55
+ const key = Buffer.from(hkdfSync("sha256", shared, salt, INFO, 32));
56
+ const nonce = randomBytes(12);
57
+ const cipher = createCipheriv("aes-256-gcm", key, nonce);
58
+ cipher.setAAD(AAD);
59
+ const ct = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
60
+ const tag = cipher.getAuthTag();
61
+ const wire = {
62
+ v: "seal-1",
63
+ epk: ephPubRaw.toString("base64url"),
64
+ n: nonce.toString("base64url"),
65
+ ct: Buffer.concat([ct, tag]).toString("base64url"),
66
+ };
67
+ return Buffer.from(JSON.stringify(wire), "utf8").toString("base64url");
68
+ }
69
+ /** Decrypt a `seal-1` credential with the recipient's sealing keypair. */
70
+ export function unseal(sealed, recipient) {
71
+ let wire;
72
+ try {
73
+ wire = JSON.parse(Buffer.from(sealed, "base64url").toString("utf8"));
74
+ }
75
+ catch {
76
+ throw new Error("malformed sealed credential");
77
+ }
78
+ if (wire.v !== "seal-1" || !wire.epk || !wire.n || !wire.ct) {
79
+ throw new Error("unsupported or malformed seal");
80
+ }
81
+ const ephPub = importPublic(wire.epk);
82
+ const shared = diffieHellman({ privateKey: importPrivate(recipient), publicKey: ephPub });
83
+ const salt = Buffer.concat([
84
+ Buffer.from(wire.epk, "base64url"),
85
+ Buffer.from(recipient.publicKey, "base64url"),
86
+ ]);
87
+ const key = Buffer.from(hkdfSync("sha256", shared, salt, INFO, 32));
88
+ const data = Buffer.from(wire.ct, "base64url");
89
+ const tag = data.subarray(data.length - 16);
90
+ const ct = data.subarray(0, data.length - 16);
91
+ const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(wire.n, "base64url"));
92
+ decipher.setAAD(AAD);
93
+ decipher.setAuthTag(tag);
94
+ return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
95
+ }
96
+ //# sourceMappingURL=seal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seal.js","sourceRoot":"","sources":["../src/seal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,gBAAgB,EAChB,WAAW,GAEZ,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAQ1C,SAAS,SAAS,CAAC,GAAc;IAC/B,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAmB,CAAC;IAC5D,IAAI,CAAC,GAAG,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACxD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,YAAY,CAAC,MAAc;IAClC,OAAO,eAAe,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AAC3F,CAAC;AAED,SAAS,aAAa,CAAC,EAAe;IACpC,OAAO,gBAAgB,CAAC;QACtB,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,UAAU,EAAE;QACrE,MAAM,EAAE,KAAK;KACd,CAAC,CAAC;AACL,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,cAAc;IAC5B,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAmB,CAAC;IACrE,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAmB,CAAC;IACvE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAE,EAAE,UAAU,EAAE,OAAO,CAAC,CAAE,EAAE,CAAC;AAC1D,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,IAAI,CAAC,SAAiB,EAAE,kBAA0B;IAChE,MAAM,YAAY,GAAG,YAAY,CAAC,kBAAkB,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC;IACtF,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACtF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACpE,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACzD,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACnB,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC7E,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG;QACX,CAAC,EAAE,QAAQ;QACX,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC;QACpC,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC;QAC9B,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;KACnD,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACzE,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,MAAM,CAAC,MAAc,EAAE,SAAsB;IAC3D,IAAI,IAA2D,CAAC;IAChE,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,IAAI,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,UAAU,EAAE,aAAa,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1F,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,WAAW,CAAC;KAC9C,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACpE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAC5C,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;IACxF,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACzB,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACjF,CAAC"}
@@ -0,0 +1,119 @@
1
+ import type { AuditEntry, AuditFields, ConsentRecord } from "./types.js";
2
+ /**
3
+ * Pluggable persistence. Defaults are in-memory and local-first, so the library
4
+ * works with zero setup; swap in a networked store for distributed revocation.
5
+ */
6
+ export interface RevocationStore {
7
+ revoke(id: string): Promise<void> | void;
8
+ isRevoked(id: string): Promise<boolean> | boolean;
9
+ }
10
+ export interface RateStore {
11
+ /**
12
+ * Atomically record a hit against `key` and report whether it falls within
13
+ * `limit` over the sliding `windowMs`. A rejected hit is NOT counted. Back it
14
+ * with a shared store (the control plane) to enforce one limit across every
15
+ * agent that holds the mandate — otherwise each process gets its own cap.
16
+ */
17
+ hit(key: string, windowMs: number, limit: number, now: number): Promise<boolean> | boolean;
18
+ }
19
+ export interface AuditStore {
20
+ /**
21
+ * Seal `fields` onto the chain and persist — the primary write path used by
22
+ * the engine. The store owns sequencing/hashing so writes stay O(1) and, for
23
+ * a shared store, race-free under a single writer.
24
+ */
25
+ record(fields: AuditFields): Promise<AuditEntry> | AuditEntry;
26
+ /** Append an already-sealed entry verbatim (replication / import). */
27
+ append(entry: AuditEntry): Promise<void> | void;
28
+ /** Entries whose chain includes `mandateId`, in order. */
29
+ forMandate(mandateId: string): Promise<AuditEntry[]> | AuditEntry[];
30
+ /** Entries issued under `issuer` (root public key) — per-tenant scoping. */
31
+ forIssuer(issuer: string): Promise<AuditEntry[]> | AuditEntry[];
32
+ all(): Promise<AuditEntry[]> | AuditEntry[];
33
+ }
34
+ /** Storage for just-in-time consent records (control plane). */
35
+ export interface ConsentStore {
36
+ put(record: ConsentRecord): Promise<void> | void;
37
+ get(id: string): Promise<ConsentRecord | undefined> | ConsentRecord | undefined;
38
+ list(): Promise<ConsentRecord[]> | ConsentRecord[];
39
+ }
40
+ /** Storage for named tool→capability policies (control plane). */
41
+ export interface PolicyStore {
42
+ set(name: string, policy: unknown): Promise<void> | void;
43
+ get(name: string): Promise<unknown> | unknown;
44
+ has(name: string): Promise<boolean> | boolean;
45
+ }
46
+ export declare class MemoryConsentStore implements ConsentStore {
47
+ private readonly records;
48
+ put(record: ConsentRecord): void;
49
+ get(id: string): ConsentRecord | undefined;
50
+ list(): ConsentRecord[];
51
+ }
52
+ export declare class MemoryPolicyStore implements PolicyStore {
53
+ private readonly policies;
54
+ set(name: string, policy: unknown): void;
55
+ get(name: string): unknown;
56
+ has(name: string): boolean;
57
+ }
58
+ export declare class MemoryRevocationStore implements RevocationStore {
59
+ private revoked;
60
+ revoke(id: string): void;
61
+ isRevoked(id: string): boolean;
62
+ }
63
+ export interface CacheOptions {
64
+ /** How long a "not revoked" answer may be reused before re-checking. */
65
+ ttlMs: number;
66
+ /** Override the clock — handy for tests. */
67
+ now?: () => number;
68
+ }
69
+ /**
70
+ * Wraps another {@link RevocationStore} (typically the networked
71
+ * `HttpRevocationStore`) with a bounded cache, so a hot mandate isn't
72
+ * re-checked over the network on every `authorize()`.
73
+ *
74
+ * Safe by construction: revocation is monotonic, so a *revoked* answer is cached
75
+ * forever, while a *not-revoked* answer is cached only for `ttlMs`. The cost is
76
+ * a bounded staleness window — a mandate revoked elsewhere may still pass for up
77
+ * to `ttlMs`. This is exactly the "short TTL + revocation check" trade-off; keep
78
+ * the TTL small (seconds) for tight revocation, larger to cut traffic.
79
+ */
80
+ export declare class CachingRevocationStore implements RevocationStore {
81
+ private readonly inner;
82
+ private readonly opts;
83
+ private readonly revoked;
84
+ private readonly freshUntil;
85
+ private readonly now;
86
+ constructor(inner: RevocationStore, opts: CacheOptions);
87
+ revoke(id: string): Promise<void>;
88
+ isRevoked(id: string): Promise<boolean>;
89
+ }
90
+ export declare class MemoryRateStore implements RateStore {
91
+ private readonly hits;
92
+ hit(key: string, windowMs: number, limit: number, now: number): boolean;
93
+ }
94
+ /**
95
+ * Token-bucket rate limiting — a smoother alternative to {@link MemoryRateStore}'s
96
+ * sliding-count window, for callers who want **burst shaping**. Each key owns a
97
+ * bucket of capacity `limit` that refills continuously at `limit / windowMs`
98
+ * tokens per ms; a hit consumes one token if available (allow), and a rejected
99
+ * hit consumes nothing (so rejections aren't counted, matching the sliding
100
+ * store). The effect: an initial burst of up to `limit`, then a steady long-run
101
+ * rate of `limit` per `windowMs`. Drop-in for any `RateStore` slot — pass it as
102
+ * `rate` to an engine, or to the control plane for a shared bucket.
103
+ *
104
+ * Like the sliding store this is per-process unless shared; for one cap across
105
+ * agents, run it inside the control plane and point agents at `HttpRateStore`.
106
+ */
107
+ export declare class TokenBucketRateStore implements RateStore {
108
+ private readonly buckets;
109
+ hit(key: string, windowMs: number, limit: number, now: number): boolean;
110
+ }
111
+ export declare class MemoryAuditStore implements AuditStore {
112
+ private entries;
113
+ record(fields: AuditFields): AuditEntry;
114
+ append(entry: AuditEntry): void;
115
+ forMandate(mandateId: string): AuditEntry[];
116
+ forIssuer(issuer: string): AuditEntry[];
117
+ all(): AuditEntry[];
118
+ }
119
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
package/dist/store.js ADDED
@@ -0,0 +1,139 @@
1
+ import { seal } from "./audit.js";
2
+ export class MemoryConsentStore {
3
+ records = new Map();
4
+ put(record) {
5
+ this.records.set(record.id, record);
6
+ }
7
+ get(id) {
8
+ return this.records.get(id);
9
+ }
10
+ list() {
11
+ return [...this.records.values()];
12
+ }
13
+ }
14
+ export class MemoryPolicyStore {
15
+ policies = new Map();
16
+ set(name, policy) {
17
+ this.policies.set(name, policy);
18
+ }
19
+ get(name) {
20
+ return this.policies.get(name);
21
+ }
22
+ has(name) {
23
+ return this.policies.has(name);
24
+ }
25
+ }
26
+ export class MemoryRevocationStore {
27
+ revoked = new Set();
28
+ revoke(id) {
29
+ this.revoked.add(id);
30
+ }
31
+ isRevoked(id) {
32
+ return this.revoked.has(id);
33
+ }
34
+ }
35
+ /**
36
+ * Wraps another {@link RevocationStore} (typically the networked
37
+ * `HttpRevocationStore`) with a bounded cache, so a hot mandate isn't
38
+ * re-checked over the network on every `authorize()`.
39
+ *
40
+ * Safe by construction: revocation is monotonic, so a *revoked* answer is cached
41
+ * forever, while a *not-revoked* answer is cached only for `ttlMs`. The cost is
42
+ * a bounded staleness window — a mandate revoked elsewhere may still pass for up
43
+ * to `ttlMs`. This is exactly the "short TTL + revocation check" trade-off; keep
44
+ * the TTL small (seconds) for tight revocation, larger to cut traffic.
45
+ */
46
+ export class CachingRevocationStore {
47
+ inner;
48
+ opts;
49
+ revoked = new Set();
50
+ freshUntil = new Map();
51
+ now;
52
+ constructor(inner, opts) {
53
+ this.inner = inner;
54
+ this.opts = opts;
55
+ this.now = opts.now ?? (() => Date.now());
56
+ }
57
+ async revoke(id) {
58
+ await this.inner.revoke(id);
59
+ this.revoked.add(id);
60
+ this.freshUntil.delete(id);
61
+ }
62
+ async isRevoked(id) {
63
+ if (this.revoked.has(id))
64
+ return true;
65
+ const until = this.freshUntil.get(id);
66
+ if (until !== undefined && this.now() < until)
67
+ return false;
68
+ const revoked = await this.inner.isRevoked(id);
69
+ if (revoked)
70
+ this.revoked.add(id);
71
+ else
72
+ this.freshUntil.set(id, this.now() + this.opts.ttlMs);
73
+ return revoked;
74
+ }
75
+ }
76
+ export class MemoryRateStore {
77
+ hits = new Map();
78
+ hit(key, windowMs, limit, now) {
79
+ const recent = (this.hits.get(key) ?? []).filter((t) => now - t < windowMs);
80
+ if (recent.length + 1 > limit) {
81
+ this.hits.set(key, recent);
82
+ return false;
83
+ }
84
+ recent.push(now);
85
+ this.hits.set(key, recent);
86
+ return true;
87
+ }
88
+ }
89
+ /**
90
+ * Token-bucket rate limiting — a smoother alternative to {@link MemoryRateStore}'s
91
+ * sliding-count window, for callers who want **burst shaping**. Each key owns a
92
+ * bucket of capacity `limit` that refills continuously at `limit / windowMs`
93
+ * tokens per ms; a hit consumes one token if available (allow), and a rejected
94
+ * hit consumes nothing (so rejections aren't counted, matching the sliding
95
+ * store). The effect: an initial burst of up to `limit`, then a steady long-run
96
+ * rate of `limit` per `windowMs`. Drop-in for any `RateStore` slot — pass it as
97
+ * `rate` to an engine, or to the control plane for a shared bucket.
98
+ *
99
+ * Like the sliding store this is per-process unless shared; for one cap across
100
+ * agents, run it inside the control plane and point agents at `HttpRateStore`.
101
+ */
102
+ export class TokenBucketRateStore {
103
+ buckets = new Map();
104
+ hit(key, windowMs, limit, now) {
105
+ if (limit <= 0 || windowMs <= 0)
106
+ return false;
107
+ const refillPerMs = limit / windowMs;
108
+ const b = this.buckets.get(key) ?? { tokens: limit, last: now };
109
+ // Refill for elapsed time (clamped to capacity), then try to spend a token.
110
+ b.tokens = Math.min(limit, b.tokens + Math.max(0, now - b.last) * refillPerMs);
111
+ b.last = now;
112
+ const allowed = b.tokens >= 1;
113
+ if (allowed)
114
+ b.tokens -= 1;
115
+ this.buckets.set(key, b);
116
+ return allowed;
117
+ }
118
+ }
119
+ export class MemoryAuditStore {
120
+ entries = [];
121
+ record(fields) {
122
+ const entry = seal(this.entries[this.entries.length - 1] ?? null, fields);
123
+ this.entries.push(entry);
124
+ return entry;
125
+ }
126
+ append(entry) {
127
+ this.entries.push(entry);
128
+ }
129
+ forMandate(mandateId) {
130
+ return this.entries.filter((e) => e.chain.includes(mandateId));
131
+ }
132
+ forIssuer(issuer) {
133
+ return this.entries.filter((e) => e.issuer === issuer);
134
+ }
135
+ all() {
136
+ return [...this.entries];
137
+ }
138
+ }
139
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}