@agentidentity/sdk 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.
@@ -0,0 +1,26 @@
1
+ /** The API returned a non-2xx response. Carries the server's own error fields. */
2
+ export declare class AidApiError extends Error {
3
+ readonly status: number;
4
+ readonly code: string;
5
+ readonly requestId: string;
6
+ readonly retryable: boolean;
7
+ constructor(status: number, body: unknown);
8
+ }
9
+ /**
10
+ * The request never reached the API — DNS failure, connection refused, TLS error, or the
11
+ * request deadline elapsing.
12
+ *
13
+ * Without this, these surface as `TypeError: fetch failed`, which names neither the URL nor the
14
+ * underlying problem (undici hides it on `.cause`). Distinguishing "the server said no" from
15
+ * "I never reached the server" is the difference between fixing your request and checking your
16
+ * network, so the two cases get distinct types.
17
+ */
18
+ export declare class AidConnectionError extends Error {
19
+ /** The originating error, e.g. an undici `ECONNREFUSED`/`ENOTFOUND`, or a timeout abort. */
20
+ readonly cause: unknown;
21
+ readonly method: string;
22
+ readonly url: string;
23
+ /** True when the client's own deadline elapsed rather than the connection failing outright. */
24
+ readonly timedOut: boolean;
25
+ constructor(method: string, url: string, cause: unknown, timedOut: boolean);
26
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,55 @@
1
+ function unwrapWireError(body) {
2
+ if (typeof body !== "object" || body === null)
3
+ return undefined;
4
+ if ("error" in body)
5
+ return body.error;
6
+ return body;
7
+ }
8
+ /** The API returned a non-2xx response. Carries the server's own error fields. */
9
+ export class AidApiError extends Error {
10
+ status;
11
+ code;
12
+ requestId;
13
+ retryable;
14
+ constructor(status, body) {
15
+ const wire = unwrapWireError(body);
16
+ super(wire?.message ?? `request failed with status ${status}`);
17
+ this.name = "AidApiError";
18
+ this.status = status;
19
+ this.code = wire?.code ?? "unknown";
20
+ this.requestId = wire?.request_id ?? "";
21
+ this.retryable = wire?.retryable ?? false;
22
+ }
23
+ }
24
+ /**
25
+ * The request never reached the API — DNS failure, connection refused, TLS error, or the
26
+ * request deadline elapsing.
27
+ *
28
+ * Without this, these surface as `TypeError: fetch failed`, which names neither the URL nor the
29
+ * underlying problem (undici hides it on `.cause`). Distinguishing "the server said no" from
30
+ * "I never reached the server" is the difference between fixing your request and checking your
31
+ * network, so the two cases get distinct types.
32
+ */
33
+ export class AidConnectionError extends Error {
34
+ /** The originating error, e.g. an undici `ECONNREFUSED`/`ENOTFOUND`, or a timeout abort. */
35
+ cause;
36
+ method;
37
+ url;
38
+ /** True when the client's own deadline elapsed rather than the connection failing outright. */
39
+ timedOut;
40
+ constructor(method, url, cause, timedOut) {
41
+ const detail = cause instanceof Error && cause.cause instanceof Error
42
+ ? cause.cause.message
43
+ : cause instanceof Error
44
+ ? cause.message
45
+ : String(cause);
46
+ super(timedOut
47
+ ? `${method} ${url} timed out before the API responded`
48
+ : `${method} ${url} could not reach the API: ${detail}`);
49
+ this.name = "AidConnectionError";
50
+ this.cause = cause;
51
+ this.method = method;
52
+ this.url = url;
53
+ this.timedOut = timedOut;
54
+ }
55
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./client.js";
2
+ export { generateVaultKeypair, vaultEncrypt, vaultDecrypt } from "./vault-crypto.js";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./client.js";
2
+ export { generateVaultKeypair, vaultEncrypt, vaultDecrypt } from "./vault-crypto.js";
@@ -0,0 +1,11 @@
1
+ export interface VaultKeypair {
2
+ publicKey: string;
3
+ privateKey: string;
4
+ }
5
+ export interface VaultCiphertext {
6
+ ciphertext: string;
7
+ ephemeralPublicKey: string;
8
+ }
9
+ export declare function generateVaultKeypair(): VaultKeypair;
10
+ export declare function vaultEncrypt(plaintext: Buffer, recipientPublicKey: string): VaultCiphertext;
11
+ export declare function vaultDecrypt(envelope: VaultCiphertext, recipientPublicKey: string, recipientPrivateKey: string): Buffer;
@@ -0,0 +1,55 @@
1
+ // X25519 + AES-256-GCM envelope encryption for vault secrets. This lives in the SDK rather than
2
+ // a separate package because it runs on the *client* side: plaintext never reaches the API, so
3
+ // anyone talking to the vault needs these primitives locally. Node built-ins only, no deps.
4
+ import { createCipheriv, createDecipheriv, createPrivateKey, createPublicKey, diffieHellman, generateKeyPairSync, hkdfSync, randomBytes, } from "node:crypto";
5
+ const HKDF_INFO = Buffer.from("aid-vault-v2");
6
+ const HKDF_SALT = Buffer.alloc(0);
7
+ function publicKeyObject(publicKeyB64url) {
8
+ return createPublicKey({ key: { kty: "OKP", crv: "X25519", x: publicKeyB64url }, format: "jwk" });
9
+ }
10
+ function privateKeyObject(publicKeyB64url, privateKeyB64url) {
11
+ return createPrivateKey({
12
+ key: { kty: "OKP", crv: "X25519", x: publicKeyB64url, d: privateKeyB64url },
13
+ format: "jwk",
14
+ });
15
+ }
16
+ function deriveAesKey(sharedSecret) {
17
+ return Buffer.from(hkdfSync("sha256", sharedSecret, HKDF_SALT, HKDF_INFO, 32));
18
+ }
19
+ export function generateVaultKeypair() {
20
+ const { publicKey, privateKey } = generateKeyPairSync("x25519");
21
+ const pubJwk = publicKey.export({ format: "jwk" });
22
+ const privJwk = privateKey.export({ format: "jwk" });
23
+ return { publicKey: pubJwk.x, privateKey: privJwk.d };
24
+ }
25
+ export function vaultEncrypt(plaintext, recipientPublicKey) {
26
+ const ephemeral = generateKeyPairSync("x25519");
27
+ const sharedSecret = diffieHellman({
28
+ privateKey: ephemeral.privateKey,
29
+ publicKey: publicKeyObject(recipientPublicKey),
30
+ });
31
+ const aesKey = deriveAesKey(sharedSecret);
32
+ const iv = randomBytes(12);
33
+ const cipher = createCipheriv("aes-256-gcm", aesKey, iv);
34
+ const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
35
+ const authTag = cipher.getAuthTag();
36
+ const ephPubJwk = ephemeral.publicKey.export({ format: "jwk" });
37
+ return {
38
+ ciphertext: [iv, authTag, encrypted].map((buf) => buf.toString("base64")).join("."),
39
+ ephemeralPublicKey: ephPubJwk.x,
40
+ };
41
+ }
42
+ export function vaultDecrypt(envelope, recipientPublicKey, recipientPrivateKey) {
43
+ const sharedSecret = diffieHellman({
44
+ privateKey: privateKeyObject(recipientPublicKey, recipientPrivateKey),
45
+ publicKey: publicKeyObject(envelope.ephemeralPublicKey),
46
+ });
47
+ const aesKey = deriveAesKey(sharedSecret);
48
+ const [ivB64, tagB64, dataB64] = envelope.ciphertext.split(".");
49
+ if (!ivB64 || !tagB64 || !dataB64) {
50
+ throw new Error("malformed vault envelope");
51
+ }
52
+ const decipher = createDecipheriv("aes-256-gcm", aesKey, Buffer.from(ivB64, "base64"));
53
+ decipher.setAuthTag(Buffer.from(tagB64, "base64"));
54
+ return Buffer.concat([decipher.update(Buffer.from(dataB64, "base64")), decipher.final()]);
55
+ }
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@agentidentity/sdk",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript client for Agent Identity \u2014 give an agent its own email address, durable event stream, and encrypted secret vault.",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "agent",
8
+ "ai-agent",
9
+ "email",
10
+ "identity",
11
+ "webhooks",
12
+ "events",
13
+ "sdk"
14
+ ],
15
+ "homepage": "https://github.com/ALPHACOD3RS/agent-identity#readme",
16
+ "bugs": "https://github.com/ALPHACOD3RS/agent-identity/issues",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/ALPHACOD3RS/agent-identity.git",
20
+ "directory": "packages/sdk-ts"
21
+ },
22
+ "type": "module",
23
+ "main": "dist/index.js",
24
+ "types": "dist/index.d.ts",
25
+ "sideEffects": false,
26
+ "engines": {
27
+ "node": ">=20"
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "README.md",
32
+ "LICENSE"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/index.d.ts",
40
+ "default": "./dist/index.js"
41
+ },
42
+ "./errors": {
43
+ "types": "./dist/errors.d.ts",
44
+ "default": "./dist/errors.js"
45
+ }
46
+ },
47
+ "scripts": {
48
+ "build": "tsc -b",
49
+ "typecheck": "tsc -b --noEmit",
50
+ "lint": "eslint src",
51
+ "test": "vitest run"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^22.10.0",
55
+ "dotenv": "^16.4.5"
56
+ }
57
+ }