@graphitti/privy-core 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,133 @@
1
+ const PRIVY_API = "https://api.privy.io";
2
+ function basicAuthHeader(appId, appSecret) {
3
+ return `Basic ${Buffer.from(`${appId}:${appSecret}`).toString("base64")}`;
4
+ }
5
+ export async function privyFetch(path, credentials, init = {}) {
6
+ const appId = credentials.PRIVY_APP_ID?.trim();
7
+ const appSecret = credentials.PRIVY_APP_SECRET?.trim();
8
+ if (!(appId && appSecret)) {
9
+ throw new Error("PRIVY_APP_ID and PRIVY_APP_SECRET must be configured.");
10
+ }
11
+ const headers = {
12
+ Authorization: basicAuthHeader(appId, appSecret),
13
+ "privy-app-id": appId,
14
+ "Content-Type": "application/json",
15
+ ...init.headers,
16
+ };
17
+ if (credentials.PRIVY_AUTHORIZATION_KEY?.trim()) {
18
+ headers["privy-authorization-key"] = credentials.PRIVY_AUTHORIZATION_KEY.trim();
19
+ }
20
+ const response = await fetch(`${PRIVY_API}${path}`, { ...init, headers });
21
+ const text = await response.text();
22
+ let body = {};
23
+ if (text) {
24
+ try {
25
+ body = JSON.parse(text);
26
+ }
27
+ catch {
28
+ body = { message: text };
29
+ }
30
+ }
31
+ if (!response.ok) {
32
+ const message = typeof body === "object" &&
33
+ body &&
34
+ "error" in body &&
35
+ typeof body.error === "string"
36
+ ? body.error
37
+ : typeof body === "object" &&
38
+ body &&
39
+ "message" in body &&
40
+ typeof body.message === "string"
41
+ ? body.message
42
+ : `Privy HTTP ${response.status}`;
43
+ throw new Error(message);
44
+ }
45
+ return body;
46
+ }
47
+ export async function getPrivyUser(privyUserId, credentials) {
48
+ return privyFetch(`/v1/users/${encodeURIComponent(privyUserId)}`, credentials);
49
+ }
50
+ export async function searchPrivyUsers(query, credentials) {
51
+ const params = new URLSearchParams({ search: query, limit: "20" });
52
+ return privyFetch(`/v1/users?${params}`, credentials);
53
+ }
54
+ export async function listPrivyWallets(credentials) {
55
+ return privyFetch("/v1/wallets", credentials);
56
+ }
57
+ export async function createPrivyWallet(credentials, chainType = "ethereum") {
58
+ return privyFetch("/v1/wallets", credentials, {
59
+ method: "POST",
60
+ body: JSON.stringify({ chain_type: chainType }),
61
+ });
62
+ }
63
+ export async function getPrivyWallet(walletId, credentials) {
64
+ return privyFetch(`/v1/wallets/${walletId}`, credentials);
65
+ }
66
+ export async function getPrivyWalletByAddress(address, credentials) {
67
+ const params = new URLSearchParams({ address });
68
+ return privyFetch(`/v1/wallets?${params}`, credentials);
69
+ }
70
+ export async function getPrivyWalletBalance(walletId, credentials, asset = "eth") {
71
+ return privyFetch(`/v1/wallets/${walletId}/balance?asset=${encodeURIComponent(asset)}`, credentials);
72
+ }
73
+ export async function getPrivyWalletTransaction(walletId, transactionId, credentials) {
74
+ return privyFetch(`/v1/wallets/${walletId}/transactions/${transactionId}`, credentials);
75
+ }
76
+ export async function createPrivyKeyQuorum(credentials, input) {
77
+ return privyFetch("/v1/key_quorums", credentials, {
78
+ method: "POST",
79
+ body: JSON.stringify({
80
+ display_name: input.displayName,
81
+ authorization_threshold: input.authorizationThreshold,
82
+ user_ids: input.userIds,
83
+ public_keys: input.publicKeys,
84
+ key_quorum_ids: input.keyQuorumIds,
85
+ }),
86
+ });
87
+ }
88
+ export async function getPrivyKeyQuorum(quorumId, credentials) {
89
+ return privyFetch(`/v1/key_quorums/${encodeURIComponent(quorumId)}`, credentials);
90
+ }
91
+ export async function createPrivyPolicy(credentials, input) {
92
+ return privyFetch("/v1/policies", credentials, {
93
+ method: "POST",
94
+ body: JSON.stringify({
95
+ version: "1.0",
96
+ name: input.name,
97
+ chain_type: input.chainType ?? "ethereum",
98
+ rules: input.rules,
99
+ owner_id: input.ownerId,
100
+ }),
101
+ });
102
+ }
103
+ export async function getPrivyPolicy(policyId, credentials) {
104
+ return privyFetch(`/v1/policies/${encodeURIComponent(policyId)}`, credentials);
105
+ }
106
+ export async function privyWalletTransfer(walletId, body, credentials) {
107
+ return privyFetch(`/v1/wallets/${walletId}/transfer`, credentials, {
108
+ method: "POST",
109
+ body: JSON.stringify(body),
110
+ });
111
+ }
112
+ export async function privyWalletSwap(walletId, body, credentials) {
113
+ return privyFetch(`/v1/wallets/${walletId}/swap`, credentials, {
114
+ method: "POST",
115
+ body: JSON.stringify(body),
116
+ });
117
+ }
118
+ export async function createPrivyTransferIntent(walletId, body, credentials) {
119
+ return privyFetch(`/v1/intents/wallets/${walletId}/transfer`, credentials, { method: "POST", body: JSON.stringify(body) });
120
+ }
121
+ export async function createPrivyRpcIntent(walletId, body, credentials) {
122
+ return privyFetch(`/v1/intents/wallets/${walletId}/rpc`, credentials, { method: "POST", body: JSON.stringify(body) });
123
+ }
124
+ export async function getPrivyIntent(intentId, credentials) {
125
+ return privyFetch(`/v1/intents/${intentId}`, credentials);
126
+ }
127
+ export async function listPrivyIntents(credentials, walletId) {
128
+ const params = walletId ? `?wallet_id=${encodeURIComponent(walletId)}` : "";
129
+ return privyFetch(`/v1/intents${params}`, credentials);
130
+ }
131
+ export async function walletRpc(walletId, body, credentials) {
132
+ return privyFetch(`/v1/wallets/${walletId}/rpc`, credentials, { method: "POST", body: JSON.stringify(body) });
133
+ }
@@ -0,0 +1,30 @@
1
+ import { type SupportedChain } from "./chains.js";
2
+ import type { PrivyCredentials } from "./types.js";
3
+ export declare function sendSponsoredTransaction(input: {
4
+ walletId: string;
5
+ chain: SupportedChain;
6
+ to: string;
7
+ data?: string;
8
+ value?: string;
9
+ credentials: PrivyCredentials;
10
+ sponsor?: boolean;
11
+ }): Promise<{
12
+ hash: string;
13
+ gasMode: string;
14
+ }>;
15
+ export declare function personalSign(input: {
16
+ walletId: string;
17
+ message: string;
18
+ chain: SupportedChain;
19
+ credentials: PrivyCredentials;
20
+ }): Promise<{
21
+ signature: string;
22
+ }>;
23
+ export declare function signTypedDataV4(input: {
24
+ walletId: string;
25
+ typedData: unknown;
26
+ chain: SupportedChain;
27
+ credentials: PrivyCredentials;
28
+ }): Promise<{
29
+ signature: string;
30
+ }>;
@@ -0,0 +1,45 @@
1
+ import { toCaip2 } from "./chains.js";
2
+ import { walletRpc } from "./privy-client.js";
3
+ export async function sendSponsoredTransaction(input) {
4
+ const result = await walletRpc(input.walletId, {
5
+ method: "eth_sendTransaction",
6
+ caip2: toCaip2(input.chain),
7
+ sponsor: input.sponsor ?? true,
8
+ params: {
9
+ transaction: {
10
+ to: input.to,
11
+ value: input.value ?? "0x0",
12
+ data: input.data ?? "0x",
13
+ },
14
+ },
15
+ }, input.credentials);
16
+ const hash = result.data?.hash || result.data?.user_operation_hash;
17
+ if (typeof hash !== "string" || !hash) {
18
+ throw new Error("Privy did not return a transaction hash");
19
+ }
20
+ return { hash, gasMode: input.sponsor === false ? "user-pays" : "app-pays" };
21
+ }
22
+ export async function personalSign(input) {
23
+ const result = await walletRpc(input.walletId, {
24
+ method: "personal_sign",
25
+ caip2: toCaip2(input.chain),
26
+ params: { message: input.message, encoding: "utf-8" },
27
+ }, input.credentials);
28
+ const signature = result.data?.signature;
29
+ if (typeof signature !== "string" || !signature) {
30
+ throw new Error("Privy did not return a signature");
31
+ }
32
+ return { signature };
33
+ }
34
+ export async function signTypedDataV4(input) {
35
+ const result = await walletRpc(input.walletId, {
36
+ method: "eth_signTypedData_v4",
37
+ caip2: toCaip2(input.chain),
38
+ params: { typed_data: input.typedData },
39
+ }, input.credentials);
40
+ const signature = result.data?.signature;
41
+ if (typeof signature !== "string" || !signature) {
42
+ throw new Error("Privy did not return a signature");
43
+ }
44
+ return { signature };
45
+ }
@@ -0,0 +1,3 @@
1
+ import type { ExecuteParams } from "./types.js";
2
+ export declare function strParam(params: ExecuteParams, key: string): string | undefined;
3
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
package/dist/shared.js ADDED
@@ -0,0 +1,17 @@
1
+ export function strParam(params, key) {
2
+ const snake = params[key];
3
+ if (typeof snake === "string" && snake.trim()) {
4
+ return snake.trim();
5
+ }
6
+ const camel = params[camelCase(key)];
7
+ if (typeof camel === "string" && camel.trim()) {
8
+ return camel.trim();
9
+ }
10
+ return undefined;
11
+ }
12
+ function camelCase(key) {
13
+ return key.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
14
+ }
15
+ export function isRecord(value) {
16
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17
+ }
@@ -0,0 +1,24 @@
1
+ export type PrivyCredentials = {
2
+ PRIVY_APP_ID?: string;
3
+ PRIVY_APP_SECRET?: string;
4
+ PRIVY_AUTHORIZATION_KEY?: string;
5
+ GRAPHITTI_BASE_URL?: string;
6
+ GRAPHITTI_API_KEY?: string;
7
+ };
8
+ export type ToolResult = {
9
+ success: true;
10
+ data: Record<string, unknown>;
11
+ } | {
12
+ success: false;
13
+ error: string;
14
+ };
15
+ export type PrivyToolDefinition = {
16
+ name: string;
17
+ description: string;
18
+ category: "users" | "wallets" | "sign" | "controls" | "intents" | "graphitti";
19
+ optional?: boolean;
20
+ requiresGraphittiKey?: boolean;
21
+ requiresTreasuryScope?: boolean;
22
+ parameters: Record<string, unknown>;
23
+ };
24
+ export type ExecuteParams = Record<string, unknown>;
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@graphitti/privy-core",
3
+ "version": "0.1.0",
4
+ "description": "Shared Privy wallet and treasury tool catalog and MCP stdio server for agent plugins",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "author": "Graphitti",
8
+ "keywords": [
9
+ "privy",
10
+ "wallet",
11
+ "treasury",
12
+ "mcp",
13
+ "agent",
14
+ "web3"
15
+ ],
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/Bleyle823/Graphitti.git",
19
+ "directory": "ecosystem-agent-plugins/privy/privy-core"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/Bleyle823/Graphitti/issues"
23
+ },
24
+ "homepage": "https://github.com/Bleyle823/Graphitti/tree/main/ecosystem-agent-plugins/privy/privy-core#readme",
25
+ "engines": {
26
+ "node": ">=20"
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "README.md"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "main": "./dist/index.js",
36
+ "types": "./dist/index.d.ts",
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/index.d.ts",
40
+ "import": "./dist/index.js"
41
+ },
42
+ "./mcp": {
43
+ "types": "./dist/mcp-server.d.ts",
44
+ "import": "./dist/mcp-server.js"
45
+ }
46
+ },
47
+ "bin": {
48
+ "privy-mcp": "./dist/mcp-server.js"
49
+ },
50
+ "scripts": {
51
+ "build": "tsc",
52
+ "type-check": "tsc --noEmit",
53
+ "test": "vitest run",
54
+ "prepublishOnly": "pnpm run build"
55
+ },
56
+ "devDependencies": {
57
+ "@types/node": "^22.10.0",
58
+ "typescript": "^5.7.2",
59
+ "vitest": "^3.0.5"
60
+ }
61
+ }