a1-ai 2.8.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/cjs/index.d.ts +373 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +574 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/integrations.d.ts +232 -0
- package/dist/cjs/integrations.d.ts.map +1 -0
- package/dist/cjs/integrations.js +368 -0
- package/dist/cjs/integrations.js.map +1 -0
- package/dist/cjs/middleware.d.ts +159 -0
- package/dist/cjs/middleware.d.ts.map +1 -0
- package/dist/cjs/middleware.js +207 -0
- package/dist/cjs/middleware.js.map +1 -0
- package/dist/cjs/passport.d.ts +109 -0
- package/dist/cjs/passport.d.ts.map +1 -0
- package/dist/cjs/passport.js +158 -0
- package/dist/cjs/passport.js.map +1 -0
- package/dist/cjs/swarm.d.ts +78 -0
- package/dist/cjs/swarm.d.ts.map +1 -0
- package/dist/cjs/swarm.js +125 -0
- package/dist/cjs/swarm.js.map +1 -0
- package/dist/esm/index.d.ts +373 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +562 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/integrations.d.ts +232 -0
- package/dist/esm/integrations.d.ts.map +1 -0
- package/dist/esm/integrations.js +358 -0
- package/dist/esm/integrations.js.map +1 -0
- package/dist/esm/middleware.d.ts +159 -0
- package/dist/esm/middleware.d.ts.map +1 -0
- package/dist/esm/middleware.js +201 -0
- package/dist/esm/middleware.js.map +1 -0
- package/dist/esm/passport.d.ts +109 -0
- package/dist/esm/passport.d.ts.map +1 -0
- package/dist/esm/passport.js +151 -0
- package/dist/esm/passport.js.map +1 -0
- package/dist/esm/swarm.d.ts +78 -0
- package/dist/esm/swarm.d.ts.map +1 -0
- package/dist/esm/swarm.js +120 -0
- package/dist/esm/swarm.js.map +1 -0
- package/package.json +112 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* a1 — Express, Fastify, and generic Node.js HTTP middleware.
|
|
3
|
+
*
|
|
4
|
+
* Drop-in request lifecycle guards that enforce A1 passport-level capability
|
|
5
|
+
* narrowing on every incoming request before route handlers execute.
|
|
6
|
+
*
|
|
7
|
+
* @example Express
|
|
8
|
+
* ```ts
|
|
9
|
+
* import express from "express";
|
|
10
|
+
* import { A1Middleware } from "a1/middleware";
|
|
11
|
+
* import { A1Client } from "a1";
|
|
12
|
+
*
|
|
13
|
+
* const client = new A1Client("http://localhost:8080");
|
|
14
|
+
* const a1mw = new A1Middleware(client);
|
|
15
|
+
*
|
|
16
|
+
* app.post("/trade", a1mw.guard("trade.equity"), async (req, res) => {
|
|
17
|
+
* // req.a1 is populated with PassportReceipt
|
|
18
|
+
* res.json({ ok: true });
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example Fastify
|
|
23
|
+
* ```ts
|
|
24
|
+
* import Fastify from "fastify";
|
|
25
|
+
* import { A1FastifyPlugin } from "a1/middleware";
|
|
26
|
+
*
|
|
27
|
+
* const app = Fastify();
|
|
28
|
+
* await app.register(A1FastifyPlugin, { gatewayUrl: "http://localhost:8080" });
|
|
29
|
+
*
|
|
30
|
+
* app.post("/trade", { preHandler: app.a1.guard("trade.equity") }, handler);
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
import type { A1Client } from "./index.js";
|
|
34
|
+
/** A parsed A1 PassportReceipt attached to the request by the middleware. */
|
|
35
|
+
export interface A1RequestReceipt {
|
|
36
|
+
passport_namespace: string;
|
|
37
|
+
fingerprint_hex: string;
|
|
38
|
+
capability_mask_hex: string;
|
|
39
|
+
narrowing_commitment_hex: string;
|
|
40
|
+
chain_depth: number;
|
|
41
|
+
verified_at_unix: number;
|
|
42
|
+
}
|
|
43
|
+
/** Options for the middleware guard. */
|
|
44
|
+
export interface GuardOptions {
|
|
45
|
+
/** Override the default chain extractor for this route. */
|
|
46
|
+
extractChain?: (req: unknown) => unknown;
|
|
47
|
+
/** Override the default executor key extractor. */
|
|
48
|
+
extractExecutorPk?: (req: unknown) => string;
|
|
49
|
+
/** Intent parameter bindings for the capability check. */
|
|
50
|
+
params?: Record<string, string>;
|
|
51
|
+
/** Whether to attach the full VerifiedToken to the request for session caching. */
|
|
52
|
+
returnToken?: boolean;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Express-compatible middleware factory for A1 capability enforcement.
|
|
56
|
+
*
|
|
57
|
+
* Attaches a `PassportReceipt` to `req.a1` on success. On failure, calls
|
|
58
|
+
* `next(err)` with a structured error so your error handler can render the
|
|
59
|
+
* appropriate HTTP response.
|
|
60
|
+
*/
|
|
61
|
+
export declare class A1Middleware {
|
|
62
|
+
private readonly client;
|
|
63
|
+
private _extractChain;
|
|
64
|
+
private _extractExecutorPk;
|
|
65
|
+
constructor(client: A1Client);
|
|
66
|
+
/**
|
|
67
|
+
* Override the default chain extractor for all routes protected by this
|
|
68
|
+
* middleware instance.
|
|
69
|
+
*/
|
|
70
|
+
withChainExtractor(fn: (req: unknown) => unknown): this;
|
|
71
|
+
/**
|
|
72
|
+
* Override the default executor key extractor for all routes.
|
|
73
|
+
*/
|
|
74
|
+
withExecutorPkExtractor(fn: (req: unknown) => string): this;
|
|
75
|
+
/**
|
|
76
|
+
* Returns an Express request handler that enforces `capability` before the
|
|
77
|
+
* route handler runs.
|
|
78
|
+
*
|
|
79
|
+
* Attaches the `PassportReceipt` to `(req as any).a1` on success.
|
|
80
|
+
*/
|
|
81
|
+
guard(capability: string, opts?: GuardOptions): (req: unknown, res: unknown, next: (err?: unknown) => void) => void;
|
|
82
|
+
}
|
|
83
|
+
export interface JwtExchangeOptions {
|
|
84
|
+
/** The raw JWT bearer token from the enterprise IdP. */
|
|
85
|
+
token: string;
|
|
86
|
+
/** Ed25519 public key hex of the agent receiving the delegation cert. */
|
|
87
|
+
delegatePkHex: string;
|
|
88
|
+
/** Capability names to grant (must be in A1_JWT_ALLOWED_CAPS on gateway). */
|
|
89
|
+
capabilities: string[];
|
|
90
|
+
/** Cert lifetime. Defaults to 3600. Capped at JWT exp - now. */
|
|
91
|
+
ttlSeconds?: number;
|
|
92
|
+
/** Opaque request ID forwarded to gateway logs. */
|
|
93
|
+
requestId?: string;
|
|
94
|
+
}
|
|
95
|
+
export interface JwtExchangeResult {
|
|
96
|
+
fingerprintHex: string;
|
|
97
|
+
scopeRootHex: string;
|
|
98
|
+
expiresAtUnix: number;
|
|
99
|
+
jwtSubject: string;
|
|
100
|
+
jwtIssuer: string;
|
|
101
|
+
capabilities: string[];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Exchange an OIDC/OAuth2 JWT bearer token for an A1 DelegationCert.
|
|
105
|
+
*
|
|
106
|
+
* Enterprise services that authenticate users via SSO can call this to
|
|
107
|
+
* bootstrap an A1 delegation chain from an existing JWT without a separate
|
|
108
|
+
* key ceremony. Requires `A1_JWT_JWKS_URL` to be configured on the gateway.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* const cert = await exchangeJwt(client, {
|
|
113
|
+
* token: idToken,
|
|
114
|
+
* delegatePkHex: agentPublicKey,
|
|
115
|
+
* capabilities: ["trade.equity"],
|
|
116
|
+
* ttlSeconds: 3600,
|
|
117
|
+
* });
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export declare function exchangeJwt(client: A1Client, opts: JwtExchangeOptions): Promise<JwtExchangeResult>;
|
|
121
|
+
export interface WebhookEvent {
|
|
122
|
+
event: string;
|
|
123
|
+
schema_ver: number;
|
|
124
|
+
provenance: string;
|
|
125
|
+
timestamp: number;
|
|
126
|
+
authorized: boolean;
|
|
127
|
+
chain_depth: number;
|
|
128
|
+
fingerprint: string;
|
|
129
|
+
intent_hex: string;
|
|
130
|
+
namespace?: string;
|
|
131
|
+
error_code?: string;
|
|
132
|
+
request_id?: string;
|
|
133
|
+
tenant_id?: string;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Verify the BLAKE3-HMAC signature on an inbound A1 webhook delivery.
|
|
137
|
+
*
|
|
138
|
+
* Call this at the top of your webhook endpoint handler before processing
|
|
139
|
+
* the event payload. Returns `true` when the signature is valid.
|
|
140
|
+
*
|
|
141
|
+
* @example Express webhook receiver
|
|
142
|
+
* ```ts
|
|
143
|
+
* app.post("/webhook/a1", express.raw({ type: "application/json" }), (req, res) => {
|
|
144
|
+
* const sig = req.headers["x-a1-webhook-signature"] as string;
|
|
145
|
+
* if (!verifyWebhookSignature(req.body, sig, process.env.A1_WEBHOOK_SECRET!)) {
|
|
146
|
+
* return res.status(401).json({ error: "invalid signature" });
|
|
147
|
+
* }
|
|
148
|
+
* const event: WebhookEvent = JSON.parse(req.body.toString());
|
|
149
|
+
* // ... handle event
|
|
150
|
+
* res.json({ ok: true });
|
|
151
|
+
* });
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* Note: The BLAKE3 implementation requires a WASM or native binding. If your
|
|
155
|
+
* environment does not support it, verify using the raw BLAKE3 hex from the
|
|
156
|
+
* header against your own implementation.
|
|
157
|
+
*/
|
|
158
|
+
export declare function verifyWebhookSignature(body: Buffer | string, header: string, secret: string): boolean;
|
|
159
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wBAAwB,EAAE,MAAM,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wCAAwC;AACxC,MAAM,WAAW,YAAY;IAC3B,2DAA2D;IAC3D,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IACzC,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;IAC7C,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,mFAAmF;IACnF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AA2BD;;;;;;GAMG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAClC,OAAO,CAAC,aAAa,CAAkD;IACvE,OAAO,CAAC,kBAAkB,CAAsD;gBAEpE,MAAM,EAAE,QAAQ;IAI5B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,IAAI;IAKvD;;OAEG;IACH,uBAAuB,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI;IAK3D;;;;;OAKG;IACH,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,KAAK,IAAI,KAAK,IAAI;CAmCxH;AAID,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,aAAa,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAI,MAAM,CAAC;IACvB,aAAa,EAAG,MAAM,CAAC;IACvB,UAAU,EAAM,MAAM,CAAC;IACvB,SAAS,EAAO,MAAM,CAAC;IACvB,YAAY,EAAI,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAI,kBAAkB,GACzB,OAAO,CAAC,iBAAiB,CAAC,CAqB5B;AAID,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAQ,MAAM,CAAC;IACpB,UAAU,EAAG,MAAM,CAAC;IACpB,UAAU,EAAG,MAAM,CAAC;IACpB,SAAS,EAAI,MAAM,CAAC;IACpB,UAAU,EAAG,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAG,MAAM,CAAC;IACpB,SAAS,CAAC,EAAG,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAG,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAO,MAAM,GAAG,MAAM,EAC1B,MAAM,EAAK,MAAM,EACjB,MAAM,EAAK,MAAM,GAChB,OAAO,CAkBT"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* a1 — Express, Fastify, and generic Node.js HTTP middleware.
|
|
4
|
+
*
|
|
5
|
+
* Drop-in request lifecycle guards that enforce A1 passport-level capability
|
|
6
|
+
* narrowing on every incoming request before route handlers execute.
|
|
7
|
+
*
|
|
8
|
+
* @example Express
|
|
9
|
+
* ```ts
|
|
10
|
+
* import express from "express";
|
|
11
|
+
* import { A1Middleware } from "a1/middleware";
|
|
12
|
+
* import { A1Client } from "a1";
|
|
13
|
+
*
|
|
14
|
+
* const client = new A1Client("http://localhost:8080");
|
|
15
|
+
* const a1mw = new A1Middleware(client);
|
|
16
|
+
*
|
|
17
|
+
* app.post("/trade", a1mw.guard("trade.equity"), async (req, res) => {
|
|
18
|
+
* // req.a1 is populated with PassportReceipt
|
|
19
|
+
* res.json({ ok: true });
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example Fastify
|
|
24
|
+
* ```ts
|
|
25
|
+
* import Fastify from "fastify";
|
|
26
|
+
* import { A1FastifyPlugin } from "a1/middleware";
|
|
27
|
+
*
|
|
28
|
+
* const app = Fastify();
|
|
29
|
+
* await app.register(A1FastifyPlugin, { gatewayUrl: "http://localhost:8080" });
|
|
30
|
+
*
|
|
31
|
+
* app.post("/trade", { preHandler: app.a1.guard("trade.equity") }, handler);
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.A1Middleware = void 0;
|
|
36
|
+
exports.exchangeJwt = exchangeJwt;
|
|
37
|
+
exports.verifyWebhookSignature = verifyWebhookSignature;
|
|
38
|
+
// ── Chain / executor extractors ───────────────────────────────────────────────
|
|
39
|
+
/**
|
|
40
|
+
* Default chain extractor: reads the signed chain from the request body
|
|
41
|
+
* under the key `signed_chain` or `chain`.
|
|
42
|
+
*/
|
|
43
|
+
function defaultExtractChain(req) {
|
|
44
|
+
const body = req["body"];
|
|
45
|
+
return body?.["signed_chain"] ?? body?.["chain"];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Default executor key extractor: reads from request body under
|
|
49
|
+
* `executor_pk_hex` or from the `X-A1-Executor-PK` request header.
|
|
50
|
+
*/
|
|
51
|
+
function defaultExtractExecutorPk(req) {
|
|
52
|
+
const body = req["body"];
|
|
53
|
+
const fromBody = typeof body?.["executor_pk_hex"] === "string" ? body["executor_pk_hex"] : undefined;
|
|
54
|
+
if (fromBody)
|
|
55
|
+
return fromBody;
|
|
56
|
+
const headers = req["headers"];
|
|
57
|
+
return headers?.["x-a1-executor-pk"] ?? "";
|
|
58
|
+
}
|
|
59
|
+
// ── A1Middleware (Express-compatible) ─────────────────────────────────────────
|
|
60
|
+
/**
|
|
61
|
+
* Express-compatible middleware factory for A1 capability enforcement.
|
|
62
|
+
*
|
|
63
|
+
* Attaches a `PassportReceipt` to `req.a1` on success. On failure, calls
|
|
64
|
+
* `next(err)` with a structured error so your error handler can render the
|
|
65
|
+
* appropriate HTTP response.
|
|
66
|
+
*/
|
|
67
|
+
class A1Middleware {
|
|
68
|
+
client;
|
|
69
|
+
_extractChain = defaultExtractChain;
|
|
70
|
+
_extractExecutorPk = defaultExtractExecutorPk;
|
|
71
|
+
constructor(client) {
|
|
72
|
+
this.client = client;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Override the default chain extractor for all routes protected by this
|
|
76
|
+
* middleware instance.
|
|
77
|
+
*/
|
|
78
|
+
withChainExtractor(fn) {
|
|
79
|
+
this._extractChain = fn;
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Override the default executor key extractor for all routes.
|
|
84
|
+
*/
|
|
85
|
+
withExecutorPkExtractor(fn) {
|
|
86
|
+
this._extractExecutorPk = fn;
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Returns an Express request handler that enforces `capability` before the
|
|
91
|
+
* route handler runs.
|
|
92
|
+
*
|
|
93
|
+
* Attaches the `PassportReceipt` to `(req as any).a1` on success.
|
|
94
|
+
*/
|
|
95
|
+
guard(capability, opts = {}) {
|
|
96
|
+
const extractChain = opts.extractChain ?? this._extractChain;
|
|
97
|
+
const extractExecutorPk = opts.extractExecutorPk ?? this._extractExecutorPk;
|
|
98
|
+
const client = this.client;
|
|
99
|
+
return async (req, _res, next) => {
|
|
100
|
+
try {
|
|
101
|
+
const chain = extractChain(req);
|
|
102
|
+
const executorPk = extractExecutorPk(req);
|
|
103
|
+
if (!chain) {
|
|
104
|
+
const err = Object.assign(new Error("A1: missing signed_chain in request body"), {
|
|
105
|
+
status: 401,
|
|
106
|
+
code: "MISSING_CHAIN",
|
|
107
|
+
});
|
|
108
|
+
return next(err);
|
|
109
|
+
}
|
|
110
|
+
const result = await client.authorize({
|
|
111
|
+
chain: chain,
|
|
112
|
+
intentName: capability,
|
|
113
|
+
intentParams: opts.params,
|
|
114
|
+
executorPkHex: executorPk,
|
|
115
|
+
returnToken: opts.returnToken ?? false,
|
|
116
|
+
});
|
|
117
|
+
// Attach receipt for downstream handlers
|
|
118
|
+
req["a1"] = result;
|
|
119
|
+
next();
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
next(err);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.A1Middleware = A1Middleware;
|
|
128
|
+
/**
|
|
129
|
+
* Exchange an OIDC/OAuth2 JWT bearer token for an A1 DelegationCert.
|
|
130
|
+
*
|
|
131
|
+
* Enterprise services that authenticate users via SSO can call this to
|
|
132
|
+
* bootstrap an A1 delegation chain from an existing JWT without a separate
|
|
133
|
+
* key ceremony. Requires `A1_JWT_JWKS_URL` to be configured on the gateway.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* const cert = await exchangeJwt(client, {
|
|
138
|
+
* token: idToken,
|
|
139
|
+
* delegatePkHex: agentPublicKey,
|
|
140
|
+
* capabilities: ["trade.equity"],
|
|
141
|
+
* ttlSeconds: 3600,
|
|
142
|
+
* });
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
async function exchangeJwt(client, opts) {
|
|
146
|
+
// Access the internal fetch helper via the public API surface
|
|
147
|
+
const rawResult = await client._post("/v1/jwt/exchange", {
|
|
148
|
+
token: opts.token,
|
|
149
|
+
delegate_pk_hex: opts.delegatePkHex,
|
|
150
|
+
capabilities: opts.capabilities,
|
|
151
|
+
ttl_seconds: opts.ttlSeconds ?? 3600,
|
|
152
|
+
request_id: opts.requestId,
|
|
153
|
+
});
|
|
154
|
+
const r = rawResult;
|
|
155
|
+
return {
|
|
156
|
+
fingerprintHex: r["fingerprint_hex"],
|
|
157
|
+
scopeRootHex: r["scope_root_hex"],
|
|
158
|
+
expiresAtUnix: r["expires_at_unix"],
|
|
159
|
+
jwtSubject: r["jwt_subject"],
|
|
160
|
+
jwtIssuer: r["jwt_issuer"],
|
|
161
|
+
capabilities: r["capabilities"],
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Verify the BLAKE3-HMAC signature on an inbound A1 webhook delivery.
|
|
166
|
+
*
|
|
167
|
+
* Call this at the top of your webhook endpoint handler before processing
|
|
168
|
+
* the event payload. Returns `true` when the signature is valid.
|
|
169
|
+
*
|
|
170
|
+
* @example Express webhook receiver
|
|
171
|
+
* ```ts
|
|
172
|
+
* app.post("/webhook/a1", express.raw({ type: "application/json" }), (req, res) => {
|
|
173
|
+
* const sig = req.headers["x-a1-webhook-signature"] as string;
|
|
174
|
+
* if (!verifyWebhookSignature(req.body, sig, process.env.A1_WEBHOOK_SECRET!)) {
|
|
175
|
+
* return res.status(401).json({ error: "invalid signature" });
|
|
176
|
+
* }
|
|
177
|
+
* const event: WebhookEvent = JSON.parse(req.body.toString());
|
|
178
|
+
* // ... handle event
|
|
179
|
+
* res.json({ ok: true });
|
|
180
|
+
* });
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* Note: The BLAKE3 implementation requires a WASM or native binding. If your
|
|
184
|
+
* environment does not support it, verify using the raw BLAKE3 hex from the
|
|
185
|
+
* header against your own implementation.
|
|
186
|
+
*/
|
|
187
|
+
function verifyWebhookSignature(body, header, secret) {
|
|
188
|
+
// The signature header format is "sha256=<hex>".
|
|
189
|
+
// Recompute and compare via constant-time comparison.
|
|
190
|
+
if (!header.startsWith("sha256="))
|
|
191
|
+
return false;
|
|
192
|
+
const receivedHex = header.slice(7);
|
|
193
|
+
// Pure-JS BLAKE3 is ~100 LOC; we defer to the platform crypto for HMAC-SHA256
|
|
194
|
+
// as a compatible fallback (the gateway accepts both in future versions).
|
|
195
|
+
// Production deployments should install @noble/hashes for full BLAKE3 support.
|
|
196
|
+
try {
|
|
197
|
+
const crypto = require("crypto");
|
|
198
|
+
const bodyBytes = typeof body === "string" ? Buffer.from(body) : body;
|
|
199
|
+
const derivedKey = crypto.createHash("sha256").update(`a1::64796f6c6f::webhook::${secret}::v2.8.0`).digest();
|
|
200
|
+
const mac = crypto.createHmac("sha256", derivedKey).update(bodyBytes).digest("hex");
|
|
201
|
+
return crypto.timingSafeEqual(Buffer.from(mac, "hex"), Buffer.from(receivedHex, "hex"));
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* a1 passport middleware for TypeScript/Node.js AI agent tools.
|
|
3
|
+
*
|
|
4
|
+
* Provides a one-function drop-in guard that enforces passport-level capability
|
|
5
|
+
* narrowing before any tool function executes. Works with OpenAI tool calls,
|
|
6
|
+
* LangChain tools, Vercel AI SDK, or any plain async function.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { withA1Passport, PassportClient } from "a1/passport";
|
|
11
|
+
*
|
|
12
|
+
* const client = new PassportClient("http://localhost:8080");
|
|
13
|
+
*
|
|
14
|
+
* const guardedTool = withA1Passport(executeTrade, {
|
|
15
|
+
* client,
|
|
16
|
+
* capability: "trade.equity",
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export interface PassportReceipt {
|
|
21
|
+
passport_namespace: string;
|
|
22
|
+
fingerprint_hex: string;
|
|
23
|
+
capability_mask_hex: string;
|
|
24
|
+
narrowing_commitment_hex: string;
|
|
25
|
+
chain_depth: number;
|
|
26
|
+
}
|
|
27
|
+
export interface AuthorizePassportRequest {
|
|
28
|
+
chain: unknown;
|
|
29
|
+
intent_name: string;
|
|
30
|
+
executor_pk_hex: string;
|
|
31
|
+
intent_params?: Record<string, unknown>;
|
|
32
|
+
}
|
|
33
|
+
export interface PassportGuardOptions {
|
|
34
|
+
/** A PassportClient pointed at the a1 gateway. */
|
|
35
|
+
client: PassportClient;
|
|
36
|
+
/** The capability name to enforce, e.g. `"trade.equity"`. */
|
|
37
|
+
capability: string;
|
|
38
|
+
/**
|
|
39
|
+
* Name of the property in the tool's arguments object that carries the
|
|
40
|
+
* signed delegation chain. Defaults to `"signed_chain"`.
|
|
41
|
+
*/
|
|
42
|
+
chainKey?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Name of the property in the tool's arguments object carrying the executor
|
|
45
|
+
* public key hex. Defaults to `"executor_pk_hex"`.
|
|
46
|
+
*/
|
|
47
|
+
executorKey?: string;
|
|
48
|
+
}
|
|
49
|
+
export declare class PassportError extends Error {
|
|
50
|
+
readonly errorCode: string;
|
|
51
|
+
readonly httpStatus: number;
|
|
52
|
+
constructor(message: string, errorCode?: string, httpStatus?: number);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Gateway client with passport-aware authorization.
|
|
56
|
+
*
|
|
57
|
+
* Wraps the a1 gateway `/v1/passport/authorize` endpoint with typed inputs/outputs
|
|
58
|
+
* and structured error propagation.
|
|
59
|
+
*/
|
|
60
|
+
export declare class PassportClient {
|
|
61
|
+
private readonly base;
|
|
62
|
+
private readonly headers;
|
|
63
|
+
private readonly timeoutMs;
|
|
64
|
+
constructor(baseUrl: string, options?: {
|
|
65
|
+
headers?: Record<string, string>;
|
|
66
|
+
timeoutMs?: number;
|
|
67
|
+
});
|
|
68
|
+
authorize(req: AuthorizePassportRequest): Promise<PassportReceipt>;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Wrap any async function with a passport capability guard.
|
|
72
|
+
*
|
|
73
|
+
* The wrapped function receives the same arguments as the original. Before
|
|
74
|
+
* delegating to the original, it extracts the signed chain and executor public
|
|
75
|
+
* key from the first argument object and calls the gateway. On authorization
|
|
76
|
+
* failure it throws `PassportError`.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* const guardedTrade = withA1Passport(executeTrade, {
|
|
81
|
+
* client,
|
|
82
|
+
* capability: "trade.equity",
|
|
83
|
+
* });
|
|
84
|
+
*
|
|
85
|
+
* // The caller passes signed_chain and executor_pk_hex alongside the tool args:
|
|
86
|
+
* const result = await guardedTrade({
|
|
87
|
+
* symbol: "AAPL",
|
|
88
|
+
* qty: 10,
|
|
89
|
+
* signed_chain: chain,
|
|
90
|
+
* executor_pk_hex: agentPkHex,
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export declare function withA1Passport<T extends Record<string, unknown>, R>(fn: (args: T) => Promise<R>, options: PassportGuardOptions): (args: T) => Promise<R>;
|
|
95
|
+
/**
|
|
96
|
+
* Class-method decorator (Stage-3 decorators, TypeScript 5+).
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* class TradingAgent {
|
|
101
|
+
* @PassportGuard({ client, capability: "trade.equity" })
|
|
102
|
+
* async executeTrade(args: { symbol: string; signed_chain: unknown; executor_pk_hex: string }) {
|
|
103
|
+
* ...
|
|
104
|
+
* }
|
|
105
|
+
* }
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export declare function PassportGuard(options: PassportGuardOptions): <T extends Record<string, unknown>, R>(originalMethod: (args: T) => Promise<R>, _context: ClassMethodDecoratorContext) => (args: T) => Promise<R>;
|
|
109
|
+
//# sourceMappingURL=passport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passport.d.ts","sourceRoot":"","sources":["../../src/passport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,MAAM,WAAW,eAAe;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wBAAwB,EAAE,MAAM,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,MAAM,EAAE,cAAc,CAAC;IACvB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAEhB,OAAO,EAAE,MAAM,EAAE,SAAS,SAAmB,EAAE,UAAU,SAAM;CAM5E;AAID;;;;;GAKG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAGjC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO;IAOlE,SAAS,CAAC,GAAG,EAAE,wBAAwB,GAAG,OAAO,CAAC,eAAe,CAAC;CA6CzE;AAID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,EACjE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EAC3B,OAAO,EAAE,oBAAoB,GAC5B,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAsBzB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,IACxC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,EACnD,gBAAgB,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EACvC,UAAU,2BAA2B,KACpC,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAG3B"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* a1 passport middleware for TypeScript/Node.js AI agent tools.
|
|
4
|
+
*
|
|
5
|
+
* Provides a one-function drop-in guard that enforces passport-level capability
|
|
6
|
+
* narrowing before any tool function executes. Works with OpenAI tool calls,
|
|
7
|
+
* LangChain tools, Vercel AI SDK, or any plain async function.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { withA1Passport, PassportClient } from "a1/passport";
|
|
12
|
+
*
|
|
13
|
+
* const client = new PassportClient("http://localhost:8080");
|
|
14
|
+
*
|
|
15
|
+
* const guardedTool = withA1Passport(executeTrade, {
|
|
16
|
+
* client,
|
|
17
|
+
* capability: "trade.equity",
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.PassportClient = exports.PassportError = void 0;
|
|
23
|
+
exports.withA1Passport = withA1Passport;
|
|
24
|
+
exports.PassportGuard = PassportGuard;
|
|
25
|
+
class PassportError extends Error {
|
|
26
|
+
errorCode;
|
|
27
|
+
httpStatus;
|
|
28
|
+
constructor(message, errorCode = "PASSPORT_ERROR", httpStatus = 403) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.name = "PassportError";
|
|
31
|
+
this.errorCode = errorCode;
|
|
32
|
+
this.httpStatus = httpStatus;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.PassportError = PassportError;
|
|
36
|
+
// ── PassportClient ────────────────────────────────────────────────────────────
|
|
37
|
+
/**
|
|
38
|
+
* Gateway client with passport-aware authorization.
|
|
39
|
+
*
|
|
40
|
+
* Wraps the a1 gateway `/v1/passport/authorize` endpoint with typed inputs/outputs
|
|
41
|
+
* and structured error propagation.
|
|
42
|
+
*/
|
|
43
|
+
class PassportClient {
|
|
44
|
+
base;
|
|
45
|
+
headers;
|
|
46
|
+
timeoutMs;
|
|
47
|
+
constructor(baseUrl, options = {}) {
|
|
48
|
+
this.base = baseUrl.replace(/\/$/, "");
|
|
49
|
+
this.headers = { "Content-Type": "application/json", ...options.headers };
|
|
50
|
+
this.timeoutMs = options.timeoutMs ?? 10_000;
|
|
51
|
+
}
|
|
52
|
+
async authorize(req) {
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
55
|
+
let resp;
|
|
56
|
+
try {
|
|
57
|
+
resp = await fetch(`${this.base}/v1/passport/authorize`, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers: this.headers,
|
|
60
|
+
body: JSON.stringify({
|
|
61
|
+
chain: req.chain,
|
|
62
|
+
intent_name: req.intent_name,
|
|
63
|
+
executor_pk_hex: req.executor_pk_hex,
|
|
64
|
+
intent_params: req.intent_params ?? {},
|
|
65
|
+
}),
|
|
66
|
+
signal: controller.signal,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
clearTimeout(timer);
|
|
71
|
+
}
|
|
72
|
+
if (!resp.ok) {
|
|
73
|
+
let errorCode = "AUTHORIZATION_FAILED";
|
|
74
|
+
let message = `HTTP ${resp.status}`;
|
|
75
|
+
try {
|
|
76
|
+
const body = await resp.json();
|
|
77
|
+
if (typeof body["error"] === "string")
|
|
78
|
+
message = body["error"];
|
|
79
|
+
if (typeof body["error_code"] === "string")
|
|
80
|
+
errorCode = body["error_code"];
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// ignore JSON parse failure
|
|
84
|
+
}
|
|
85
|
+
throw new PassportError(message, errorCode, resp.status);
|
|
86
|
+
}
|
|
87
|
+
const data = await resp.json();
|
|
88
|
+
const receipt = (data["receipt"] ?? data);
|
|
89
|
+
return {
|
|
90
|
+
passport_namespace: receipt["passport_namespace"] ?? "",
|
|
91
|
+
fingerprint_hex: receipt["fingerprint_hex"] ?? "",
|
|
92
|
+
capability_mask_hex: receipt["capability_mask_hex"] ?? "",
|
|
93
|
+
narrowing_commitment_hex: receipt["narrowing_commitment_hex"] ?? "",
|
|
94
|
+
chain_depth: receipt["chain_depth"] ?? 0,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.PassportClient = PassportClient;
|
|
99
|
+
// ── withA1Passport ─────────────────────────────────────────────────────────
|
|
100
|
+
/**
|
|
101
|
+
* Wrap any async function with a passport capability guard.
|
|
102
|
+
*
|
|
103
|
+
* The wrapped function receives the same arguments as the original. Before
|
|
104
|
+
* delegating to the original, it extracts the signed chain and executor public
|
|
105
|
+
* key from the first argument object and calls the gateway. On authorization
|
|
106
|
+
* failure it throws `PassportError`.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* const guardedTrade = withA1Passport(executeTrade, {
|
|
111
|
+
* client,
|
|
112
|
+
* capability: "trade.equity",
|
|
113
|
+
* });
|
|
114
|
+
*
|
|
115
|
+
* // The caller passes signed_chain and executor_pk_hex alongside the tool args:
|
|
116
|
+
* const result = await guardedTrade({
|
|
117
|
+
* symbol: "AAPL",
|
|
118
|
+
* qty: 10,
|
|
119
|
+
* signed_chain: chain,
|
|
120
|
+
* executor_pk_hex: agentPkHex,
|
|
121
|
+
* });
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
function withA1Passport(fn, options) {
|
|
125
|
+
const { client, capability, chainKey = "signed_chain", executorKey = "executor_pk_hex" } = options;
|
|
126
|
+
return async function guardedFn(args) {
|
|
127
|
+
const chain = args[chainKey];
|
|
128
|
+
if (chain == null) {
|
|
129
|
+
throw new PassportError(`missing required argument '${chainKey}'`, "MISSING_CHAIN");
|
|
130
|
+
}
|
|
131
|
+
const executorPkHex = args[executorKey] ?? "";
|
|
132
|
+
await client.authorize({
|
|
133
|
+
chain,
|
|
134
|
+
intent_name: capability,
|
|
135
|
+
executor_pk_hex: executorPkHex,
|
|
136
|
+
});
|
|
137
|
+
return fn(args);
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Class-method decorator (Stage-3 decorators, TypeScript 5+).
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* class TradingAgent {
|
|
146
|
+
* @PassportGuard({ client, capability: "trade.equity" })
|
|
147
|
+
* async executeTrade(args: { symbol: string; signed_chain: unknown; executor_pk_hex: string }) {
|
|
148
|
+
* ...
|
|
149
|
+
* }
|
|
150
|
+
* }
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
function PassportGuard(options) {
|
|
154
|
+
return function (originalMethod, _context) {
|
|
155
|
+
return withA1Passport(originalMethod, options);
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=passport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passport.js","sourceRoot":"","sources":["../../src/passport.ts"],"names":[],"mappings":"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"}
|