@execra/core 1.0.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 (52) hide show
  1. package/dist/cli/commands.d.ts +21 -0
  2. package/dist/cli/commands.js +686 -0
  3. package/dist/cli/commands.js.map +1 -0
  4. package/dist/cli/index.d.ts +8 -0
  5. package/dist/cli/index.js +1162 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/cli/prompts.d.ts +12 -0
  8. package/dist/cli/prompts.js +98 -0
  9. package/dist/cli/prompts.js.map +1 -0
  10. package/dist/cli/ui.d.ts +38 -0
  11. package/dist/cli/ui.js +990 -0
  12. package/dist/cli/ui.js.map +1 -0
  13. package/dist/handler/index.d.ts +93 -0
  14. package/dist/handler/index.js +628 -0
  15. package/dist/handler/index.js.map +1 -0
  16. package/dist/handler/walletConnect.d.ts +6 -0
  17. package/dist/handler/walletConnect.js +623 -0
  18. package/dist/handler/walletConnect.js.map +1 -0
  19. package/dist/index.d.ts +14 -0
  20. package/dist/index.js +2046 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/session/index.d.ts +20 -0
  23. package/dist/session/index.js +79 -0
  24. package/dist/session/index.js.map +1 -0
  25. package/dist/solana/index.d.ts +5 -0
  26. package/dist/solana/index.js +302 -0
  27. package/dist/solana/index.js.map +1 -0
  28. package/dist/solana/rpc.d.ts +45 -0
  29. package/dist/solana/rpc.js +120 -0
  30. package/dist/solana/rpc.js.map +1 -0
  31. package/dist/solana/simulate.d.ts +41 -0
  32. package/dist/solana/simulate.js +173 -0
  33. package/dist/solana/simulate.js.map +1 -0
  34. package/dist/solana/tx.d.ts +54 -0
  35. package/dist/solana/tx.js +141 -0
  36. package/dist/solana/tx.js.map +1 -0
  37. package/dist/vault/accounts.d.ts +88 -0
  38. package/dist/vault/accounts.js +126 -0
  39. package/dist/vault/accounts.js.map +1 -0
  40. package/dist/vault/config.d.ts +40 -0
  41. package/dist/vault/config.js +131 -0
  42. package/dist/vault/config.js.map +1 -0
  43. package/dist/vault/index.d.ts +122 -0
  44. package/dist/vault/index.js +580 -0
  45. package/dist/vault/index.js.map +1 -0
  46. package/dist/vault/keystore.d.ts +44 -0
  47. package/dist/vault/keystore.js +118 -0
  48. package/dist/vault/keystore.js.map +1 -0
  49. package/dist/vault/mnemonic.d.ts +43 -0
  50. package/dist/vault/mnemonic.js +37 -0
  51. package/dist/vault/mnemonic.js.map +1 -0
  52. package/package.json +49 -0
@@ -0,0 +1,44 @@
1
+ /**
2
+ *
3
+ * AES-256-GCM encrypted keystore.
4
+ * The mnemonic (seed phrase) is encrypted at rest in ~/.wallet/vault.enc
5
+ * Private keys NEVER touch disk — they are derived in memory at runtime.
6
+ *
7
+ * Encryption scheme:
8
+ * - Key derivation: PBKDF2 (SHA-512, 210,000 iterations) — OWASP recommended
9
+ * - Cipher: AES-256-GCM (authenticated encryption — detects tampering)
10
+ * - Salt: 32 random bytes (unique per vault)
11
+ * - IV: 16 random bytes (unique per encryption)
12
+ *
13
+ * Dependencies: Node.js built-in `crypto`, `fs`, `os`, `path`
14
+ */
15
+ interface VaultData {
16
+ mnemonic: string;
17
+ createdAt: string;
18
+ version: number;
19
+ }
20
+ declare function getWalletDir(): string;
21
+ declare function getVaultPath(): string;
22
+ declare function getConfigPath(): string;
23
+ declare function getSessionsPath(): string;
24
+ declare const SESSIONS_FILE: string;
25
+ declare function ensureWalletDir(): void;
26
+ declare function vaultExists(): boolean;
27
+ /**
28
+ * Encrypt and save the vault to disk.
29
+ * @param data - vault contents (mnemonic + metadata)
30
+ * @param password - user's wallet password
31
+ */
32
+ declare function saveVault(data: VaultData, password: string): Promise<void>;
33
+ /**
34
+ * Load and decrypt the vault from disk.
35
+ * Throws if the password is wrong or the file has been tampered with.
36
+ */
37
+ declare function loadVault(password: string): Promise<VaultData>;
38
+ /**
39
+ * Change the vault password.
40
+ * Decrypts with old password, re-encrypts with new password.
41
+ */
42
+ declare function changePassword(oldPassword: string, newPassword: string): Promise<void>;
43
+
44
+ export { SESSIONS_FILE, type VaultData, changePassword, ensureWalletDir, getConfigPath, getSessionsPath, getVaultPath, getWalletDir, loadVault, saveVault, vaultExists };
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/vault/keystore.ts
4
+ import crypto from "crypto";
5
+ import fs from "fs";
6
+ import os from "os";
7
+ import path from "path";
8
+ var VAULT_VERSION = 1;
9
+ var PBKDF2_ITERATIONS = 21e4;
10
+ var PBKDF2_DIGEST = "sha512";
11
+ var KEY_LENGTH = 32;
12
+ var SALT_LENGTH = 32;
13
+ var IV_LENGTH = 16;
14
+ var CIPHER = "aes-256-gcm";
15
+ function getWalletDir() {
16
+ return path.join(os.homedir(), ".wallet");
17
+ }
18
+ function getVaultPath() {
19
+ return path.join(getWalletDir(), "vault.enc");
20
+ }
21
+ function getConfigPath() {
22
+ return path.join(getWalletDir(), "config.json");
23
+ }
24
+ function getSessionsPath() {
25
+ return path.join(getWalletDir(), "sessions.json");
26
+ }
27
+ var SESSIONS_FILE = getSessionsPath();
28
+ function ensureWalletDir() {
29
+ const dir = getWalletDir();
30
+ if (!fs.existsSync(dir)) {
31
+ fs.mkdirSync(dir, { recursive: true, mode: 448 });
32
+ }
33
+ }
34
+ function vaultExists() {
35
+ return fs.existsSync(getVaultPath());
36
+ }
37
+ async function saveVault(data, password) {
38
+ ensureWalletDir();
39
+ const salt = crypto.randomBytes(SALT_LENGTH);
40
+ const iv = crypto.randomBytes(IV_LENGTH);
41
+ const key = await deriveKey(password, salt);
42
+ const plaintext = JSON.stringify(data);
43
+ const cipher = crypto.createCipheriv(CIPHER, key, iv);
44
+ const encrypted = Buffer.concat([
45
+ cipher.update(plaintext, "utf8"),
46
+ cipher.final()
47
+ ]);
48
+ const authTag = cipher.getAuthTag();
49
+ const vault = {
50
+ version: VAULT_VERSION,
51
+ salt: salt.toString("hex"),
52
+ iv: iv.toString("hex"),
53
+ authTag: authTag.toString("hex"),
54
+ ciphertext: encrypted.toString("hex")
55
+ };
56
+ fs.writeFileSync(getVaultPath(), JSON.stringify(vault, null, 2), {
57
+ mode: 384
58
+ // owner read/write only
59
+ });
60
+ }
61
+ async function loadVault(password) {
62
+ if (!vaultExists()) {
63
+ throw new Error("No vault found. Run `wallet init` to create one.");
64
+ }
65
+ const raw = fs.readFileSync(getVaultPath(), "utf8");
66
+ const vault = JSON.parse(raw);
67
+ if (vault.version !== VAULT_VERSION) {
68
+ throw new Error(`Unsupported vault version: ${vault.version}`);
69
+ }
70
+ const salt = Buffer.from(vault.salt, "hex");
71
+ const iv = Buffer.from(vault.iv, "hex");
72
+ const authTag = Buffer.from(vault.authTag, "hex");
73
+ const ciphertext = Buffer.from(vault.ciphertext, "hex");
74
+ const key = await deriveKey(password, salt);
75
+ try {
76
+ const decipher = crypto.createDecipheriv(CIPHER, key, iv);
77
+ decipher.setAuthTag(authTag);
78
+ const decrypted = Buffer.concat([
79
+ decipher.update(ciphertext),
80
+ decipher.final()
81
+ ]);
82
+ return JSON.parse(decrypted.toString("utf8"));
83
+ } catch {
84
+ throw new Error("Decryption failed: wrong password or vault is corrupted.");
85
+ }
86
+ }
87
+ async function changePassword(oldPassword, newPassword) {
88
+ const data = await loadVault(oldPassword);
89
+ await saveVault(data, newPassword);
90
+ }
91
+ function deriveKey(password, salt) {
92
+ return new Promise((resolve, reject) => {
93
+ crypto.pbkdf2(
94
+ password,
95
+ salt,
96
+ PBKDF2_ITERATIONS,
97
+ KEY_LENGTH,
98
+ PBKDF2_DIGEST,
99
+ (err, key) => {
100
+ if (err) reject(err);
101
+ else resolve(key);
102
+ }
103
+ );
104
+ });
105
+ }
106
+ export {
107
+ SESSIONS_FILE,
108
+ changePassword,
109
+ ensureWalletDir,
110
+ getConfigPath,
111
+ getSessionsPath,
112
+ getVaultPath,
113
+ getWalletDir,
114
+ loadVault,
115
+ saveVault,
116
+ vaultExists
117
+ };
118
+ //# sourceMappingURL=keystore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/vault/keystore.ts"],"sourcesContent":["/**\n *\n * AES-256-GCM encrypted keystore.\n * The mnemonic (seed phrase) is encrypted at rest in ~/.wallet/vault.enc\n * Private keys NEVER touch disk — they are derived in memory at runtime.\n *\n * Encryption scheme:\n * - Key derivation: PBKDF2 (SHA-512, 210,000 iterations) — OWASP recommended\n * - Cipher: AES-256-GCM (authenticated encryption — detects tampering)\n * - Salt: 32 random bytes (unique per vault)\n * - IV: 16 random bytes (unique per encryption)\n *\n * Dependencies: Node.js built-in `crypto`, `fs`, `os`, `path`\n */\n\nimport crypto from \"crypto\";\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface VaultData {\n mnemonic: string;\n createdAt: string;\n version: number;\n}\n\ninterface EncryptedVault {\n version: number; // format version for future migrations\n salt: string; // hex — used for PBKDF2 key derivation\n iv: string; // hex — AES-GCM initialisation vector\n authTag: string; // hex — GCM authentication tag (detects tampering)\n ciphertext: string; // hex — encrypted vault data\n}\n\n// ── Constants ─────────────────────────────────────────────────────────────────\n\nconst VAULT_VERSION = 1;\nconst PBKDF2_ITERATIONS = 210_000; // OWASP 2024 recommendation for PBKDF2-SHA512\nconst PBKDF2_DIGEST = \"sha512\";\nconst KEY_LENGTH = 32; // 256 bits for AES-256\nconst SALT_LENGTH = 32; // 256 bits\nconst IV_LENGTH = 16; // 128 bits for AES-GCM\nconst CIPHER = \"aes-256-gcm\";\n\n// ── Vault Path ────────────────────────────────────────────────────────────────\n\nexport function getWalletDir(): string {\n // return path.join(__dirname, \".wallet\");\n return path.join(os.homedir(), \".wallet\");\n}\n\nexport function getVaultPath(): string {\n return path.join(getWalletDir(), \"vault.enc\");\n}\n\nexport function getConfigPath(): string {\n return path.join(getWalletDir(), \"config.json\");\n}\n\nexport function getSessionsPath(): string {\n return path.join(getWalletDir(), \"sessions.json\");\n}\n\nexport const SESSIONS_FILE = getSessionsPath();\n\nexport function ensureWalletDir(): void {\n const dir = getWalletDir();\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 }); // owner-only access\n }\n}\n\nexport function vaultExists(): boolean {\n return fs.existsSync(getVaultPath());\n}\n\n// ── Encryption ────────────────────────────────────────────────────────────────\n\n/**\n * Encrypt and save the vault to disk.\n * @param data - vault contents (mnemonic + metadata)\n * @param password - user's wallet password\n */\nexport async function saveVault(\n data: VaultData,\n password: string,\n): Promise<void> {\n ensureWalletDir();\n\n const salt = crypto.randomBytes(SALT_LENGTH);\n const iv = crypto.randomBytes(IV_LENGTH);\n const key = await deriveKey(password, salt);\n\n const plaintext = JSON.stringify(data);\n const cipher = crypto.createCipheriv(CIPHER, key, iv);\n\n const encrypted = Buffer.concat([\n cipher.update(plaintext, \"utf8\"),\n cipher.final(),\n ]);\n\n const authTag = cipher.getAuthTag();\n\n const vault: EncryptedVault = {\n version: VAULT_VERSION,\n salt: salt.toString(\"hex\"),\n iv: iv.toString(\"hex\"),\n authTag: authTag.toString(\"hex\"),\n ciphertext: encrypted.toString(\"hex\"),\n };\n\n fs.writeFileSync(getVaultPath(), JSON.stringify(vault, null, 2), {\n mode: 0o600, // owner read/write only\n });\n}\n\n/**\n * Load and decrypt the vault from disk.\n * Throws if the password is wrong or the file has been tampered with.\n */\nexport async function loadVault(password: string): Promise<VaultData> {\n if (!vaultExists()) {\n throw new Error(\"No vault found. Run `wallet init` to create one.\");\n }\n\n const raw = fs.readFileSync(getVaultPath(), \"utf8\");\n const vault: EncryptedVault = JSON.parse(raw);\n\n if (vault.version !== VAULT_VERSION) {\n throw new Error(`Unsupported vault version: ${vault.version}`);\n }\n\n const salt = Buffer.from(vault.salt, \"hex\");\n const iv = Buffer.from(vault.iv, \"hex\");\n const authTag = Buffer.from(vault.authTag, \"hex\");\n const ciphertext = Buffer.from(vault.ciphertext, \"hex\");\n\n const key = await deriveKey(password, salt);\n\n try {\n const decipher = crypto.createDecipheriv(CIPHER, key, iv);\n decipher.setAuthTag(authTag);\n\n const decrypted = Buffer.concat([\n decipher.update(ciphertext),\n decipher.final(),\n ]);\n\n return JSON.parse(decrypted.toString(\"utf8\")) as VaultData;\n } catch {\n // GCM auth tag failure means wrong password OR tampered file\n throw new Error(\"Decryption failed: wrong password or vault is corrupted.\");\n }\n}\n\n/**\n * Change the vault password.\n * Decrypts with old password, re-encrypts with new password.\n */\nexport async function changePassword(\n oldPassword: string,\n newPassword: string,\n): Promise<void> {\n const data = await loadVault(oldPassword);\n await saveVault(data, newPassword);\n}\n\n// ── Internal ──────────────────────────────────────────────────────────────────\n\n/**\n * Derive a 256-bit AES key from a password using PBKDF2-SHA512.\n */\nfunction deriveKey(password: string, salt: Buffer): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n crypto.pbkdf2(\n password,\n salt,\n PBKDF2_ITERATIONS,\n KEY_LENGTH,\n PBKDF2_DIGEST,\n (err, key) => {\n if (err) reject(err);\n else resolve(key);\n },\n );\n });\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,43 @@
1
+ /**
2
+ *
3
+ * BIP-39 mnemonic generation, validation, and seed derivation.
4
+ * Supports 12-word (128-bit) and 24-word (256-bit) mnemonics.
5
+ *
6
+ * Dependencies: bip39
7
+ */
8
+ type MnemonicStrength = 12 | 24;
9
+ interface MnemonicResult {
10
+ mnemonic: string;
11
+ wordCount: 12 | 24;
12
+ }
13
+ /**
14
+ * Generate a new cryptographically random BIP-39 mnemonic.
15
+ * @param strength 128 for 12-word, 256 for 24-word (default: 128)
16
+ */
17
+ declare function generateMnemonic(strength?: MnemonicStrength): MnemonicResult;
18
+ /**
19
+ * Validate a BIP-39 mnemonic phrase.
20
+ * Checks both wordlist membership and BIP-39 checksum.
21
+ */
22
+ declare function validateMnemonic(mnemonic: string): boolean;
23
+ /**
24
+ * Derive a 64-byte seed buffer from a mnemonic.
25
+ * Optional passphrase adds extra security per BIP-39 spec.
26
+ * This seed is the root of ALL derived accounts.
27
+ */
28
+ declare function mnemonicToSeed(mnemonic: string, passphrase?: string): Promise<Buffer>;
29
+ /**
30
+ * Split mnemonic into a numbered word array.
31
+ * Used for backup verification display in the terminal UI.
32
+ *
33
+ * Example output:
34
+ * [ "1. witch", "2. collapse", "3. practice", ... ]
35
+ */
36
+ declare function mnemonicToNumberedWords(mnemonic: string): string[];
37
+ /**
38
+ * Reconstruct mnemonic from a word array.
39
+ * Used when user inputs words one by one during restore flow.
40
+ */
41
+ declare function wordsToMnemonic(words: string[]): string;
42
+
43
+ export { type MnemonicResult, type MnemonicStrength, generateMnemonic, mnemonicToNumberedWords, mnemonicToSeed, validateMnemonic, wordsToMnemonic };
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/vault/mnemonic.ts
4
+ import * as bip39 from "bip39";
5
+ function generateMnemonic2(strength = 12) {
6
+ const mnemonic = bip39.generateMnemonic(strength == 12 ? 128 : 256);
7
+ const wordCount = strength;
8
+ return { mnemonic, wordCount };
9
+ }
10
+ function validateMnemonic2(mnemonic) {
11
+ const cleaned = cleanMnemonic(mnemonic);
12
+ return bip39.validateMnemonic(cleaned);
13
+ }
14
+ async function mnemonicToSeed2(mnemonic, passphrase = "") {
15
+ const cleaned = cleanMnemonic(mnemonic);
16
+ if (!validateMnemonic2(cleaned)) {
17
+ throw new Error("Invalid mnemonic: failed wordlist or checksum validation");
18
+ }
19
+ return bip39.mnemonicToSeed(cleaned, passphrase);
20
+ }
21
+ function mnemonicToNumberedWords(mnemonic) {
22
+ return cleanMnemonic(mnemonic).split(" ").map((word, i) => `${i + 1}. ${word}`);
23
+ }
24
+ function wordsToMnemonic(words) {
25
+ return words.map((w) => w.trim().toLowerCase()).join(" ");
26
+ }
27
+ function cleanMnemonic(mnemonic) {
28
+ return mnemonic.trim().toLowerCase().replace(/\s+/g, " ");
29
+ }
30
+ export {
31
+ generateMnemonic2 as generateMnemonic,
32
+ mnemonicToNumberedWords,
33
+ mnemonicToSeed2 as mnemonicToSeed,
34
+ validateMnemonic2 as validateMnemonic,
35
+ wordsToMnemonic
36
+ };
37
+ //# sourceMappingURL=mnemonic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/vault/mnemonic.ts"],"sourcesContent":["/**\n *\n * BIP-39 mnemonic generation, validation, and seed derivation.\n * Supports 12-word (128-bit) and 24-word (256-bit) mnemonics.\n *\n * Dependencies: bip39\n */\n\nimport * as bip39 from \"bip39\";\n\nexport type MnemonicStrength = 12 | 24; // 128 = 12 words, 256 = 24 words\n\nexport interface MnemonicResult {\n mnemonic: string;\n wordCount: 12 | 24;\n}\n\n/**\n * Generate a new cryptographically random BIP-39 mnemonic.\n * @param strength 128 for 12-word, 256 for 24-word (default: 128)\n */\nexport function generateMnemonic(\n strength: MnemonicStrength = 12,\n): MnemonicResult {\n const mnemonic = bip39.generateMnemonic(strength == 12 ? 128 : 256);\n const wordCount = strength;\n return { mnemonic, wordCount };\n}\n\n/**\n * Validate a BIP-39 mnemonic phrase.\n * Checks both wordlist membership and BIP-39 checksum.\n */\nexport function validateMnemonic(mnemonic: string): boolean {\n const cleaned = cleanMnemonic(mnemonic);\n return bip39.validateMnemonic(cleaned);\n}\n\n/**\n * Derive a 64-byte seed buffer from a mnemonic.\n * Optional passphrase adds extra security per BIP-39 spec.\n * This seed is the root of ALL derived accounts.\n */\nexport async function mnemonicToSeed(\n mnemonic: string,\n passphrase: string = \"\",\n): Promise<Buffer> {\n const cleaned = cleanMnemonic(mnemonic);\n\n if (!validateMnemonic(cleaned)) {\n throw new Error(\"Invalid mnemonic: failed wordlist or checksum validation\");\n }\n\n return bip39.mnemonicToSeed(cleaned, passphrase);\n}\n\n/**\n * Split mnemonic into a numbered word array.\n * Used for backup verification display in the terminal UI.\n *\n * Example output:\n * [ \"1. witch\", \"2. collapse\", \"3. practice\", ... ]\n */\nexport function mnemonicToNumberedWords(mnemonic: string): string[] {\n return cleanMnemonic(mnemonic)\n .split(\" \")\n .map((word, i) => `${i + 1}. ${word}`);\n}\n\n/**\n * Reconstruct mnemonic from a word array.\n * Used when user inputs words one by one during restore flow.\n */\nexport function wordsToMnemonic(words: string[]): string {\n return words.map((w) => w.trim().toLowerCase()).join(\" \");\n}\n\n// ── Internal ──────────────────────────────────────────────────────────────────\n\nfunction cleanMnemonic(mnemonic: string): string {\n return mnemonic.trim().toLowerCase().replace(/\\s+/g, \" \");\n}\n"],"mappings":";;;AAQA,YAAY,WAAW;AAahB,SAASA,kBACd,WAA6B,IACb;AAChB,QAAM,WAAiB,uBAAiB,YAAY,KAAK,MAAM,GAAG;AAClE,QAAM,YAAY;AAClB,SAAO,EAAE,UAAU,UAAU;AAC/B;AAMO,SAASC,kBAAiB,UAA2B;AAC1D,QAAM,UAAU,cAAc,QAAQ;AACtC,SAAa,uBAAiB,OAAO;AACvC;AAOA,eAAsBC,gBACpB,UACA,aAAqB,IACJ;AACjB,QAAM,UAAU,cAAc,QAAQ;AAEtC,MAAI,CAACD,kBAAiB,OAAO,GAAG;AAC9B,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AAEA,SAAa,qBAAe,SAAS,UAAU;AACjD;AASO,SAAS,wBAAwB,UAA4B;AAClE,SAAO,cAAc,QAAQ,EAC1B,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE;AACzC;AAMO,SAAS,gBAAgB,OAAyB;AACvD,SAAO,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,EAAE,KAAK,GAAG;AAC1D;AAIA,SAAS,cAAc,UAA0B;AAC/C,SAAO,SAAS,KAAK,EAAE,YAAY,EAAE,QAAQ,QAAQ,GAAG;AAC1D;","names":["generateMnemonic","validateMnemonic","mnemonicToSeed"]}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@execra/core",
3
+ "version": "1.0.0",
4
+ "description": "Execra core — vault, HD key derivation, Solana RPC, and transaction pipeline",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1",
9
+ "build": "tsup",
10
+ "prepublishOnly": "pnpm build"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "module": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.js"
21
+ },
22
+ "./handler/walletConnect": {
23
+ "types": "./dist/handler/walletConnect.d.ts",
24
+ "default": "./dist/handler/walletConnect.js"
25
+ }
26
+ },
27
+ "keywords": ["solana", "wallet", "crypto", "agent", "execra", "hd-wallet", "bip44"],
28
+ "author": "Execra",
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "@solana/web3.js": "^1.98.4",
32
+ "@walletconnect/sign-client": "^2.23.8",
33
+ "@walletconnect/utils": "^2.23.8",
34
+ "bip39": "^3.1.0",
35
+ "bs58": "^6.0.0",
36
+ "chalk": "^5.6.2",
37
+ "ed25519-hd-key": "^1.3.0",
38
+ "ink": "^6.8.0",
39
+ "react": "^19.2.4",
40
+ "tweetnacl": "^1.0.3",
41
+ "ws": "^8.19.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^25.4.0",
45
+ "@types/react": "^19.2.14",
46
+ "@types/ws": "^8.18.1",
47
+ "tsup": "^8.5.1"
48
+ }
49
+ }