fema-pf-calc 1.0.7 → 1.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.
package/README.md CHANGED
@@ -1,24 +1,20 @@
1
- # FEMA — Fee Estimation & Management for Solana
1
+ # Fema
2
2
 
3
- FEMA is a TypeScript SDK that calculates optimal priority fees for Solana transactions in real time. Instead of hardcoding a fee or guessing, developers install FEMA and call one function to get the right fee based on what the network is actually paying right now.
3
+ Fema is a TypeScript SDK for Solana with two tools: `estimateFee` calculates the right priority fee based on what the network is actually paying right now, and `safeSend` handles the full transaction lifecycle including simulation, signing, submission, and confirmation.
4
4
 
5
5
  Supports **mainnet-beta** and **devnet**.
6
6
 
7
- ---
8
-
9
7
  ## The Problem
10
8
 
11
9
  Every Solana transaction can include a priority fee, a tip paid to validators to land the transaction faster. Set it too low and your transaction gets stuck or dropped. Set it too high and you overpay.
12
10
 
13
11
  The fee you need also depends on what kind of transaction you are sending. A Jupiter swap competes with other Jupiter swaps. An NFT mint competes with other NFT mints. They are not in the same queue, so they should not use the same fee.
14
12
 
15
- FEMA solves this by scanning recent blocks, building a real fee distribution, and giving you a number you can use directly.
16
-
17
- ---
13
+ Fema solves this by scanning recent blocks, building a real fee distribution, and giving you a number you can use directly.
18
14
 
19
15
  ## How It Works
20
16
 
21
- 1. FEMA connects to Solana via a built-in Helius-backed RPC proxy — no API key or RPC setup required
17
+ 1. Fema connects to Solana via a built-in Helius-backed RPC proxy — no API key or RPC setup required
22
18
  2. For each transaction in the last 30 blocks it extracts the fee paid in microLamports per compute unit
23
19
  3. It sorts these into a distribution and computes percentiles (p25, p50, p75)
24
20
  4. If you specify a protocol or pass your transaction, it filters the data to only transactions that used the same programs as yours
@@ -26,17 +22,13 @@ FEMA solves this by scanning recent blocks, building a real fee distribution, an
26
22
 
27
23
  Results are cached for 7 seconds to avoid hammering the RPC on every call.
28
24
 
29
- ---
30
-
31
25
  ## Installation
32
26
 
33
27
  ```bash
34
28
  npm install fema-pf-calc
35
29
  ```
36
30
 
37
- ---
38
-
39
- ## Quick Start
31
+ ## estimateFee Quick Start
40
32
 
41
33
  ```ts
42
34
  import { init, estimateFee } from "fema-pf-calc";
@@ -56,18 +48,16 @@ const priorityIx = ComputeBudgetProgram.setComputeUnitPrice({
56
48
 
57
49
  That is all a developer needs to do. No RPC key, no math, no guessing.
58
50
 
59
- ---
60
-
61
- ## Options
51
+ ## estimateFee Options
62
52
 
63
53
  ```ts
64
54
  const result = await estimateFee({
65
- speed: "fast", // "slow" | "medium" | "fast"
66
- strategy: "balanced", // "cheap" | "balanced" | "aggressive"
67
- protocol: "jupiter", // see supported protocols below
55
+ speed: "fast", // "slow" | "medium" | "fast"
56
+ strategy: "balanced", // "cheap" | "balanced" | "aggressive"
57
+ protocol: "jupiter", // see supported protocols below
68
58
  transaction: myTransaction, // pass your actual tx for automatic protocol detection
69
- maxFee: 500_000, // optional cap in microLamports
70
- includeStats: true, // include full distribution in response
59
+ maxFee: 500_000, // optional cap in microLamports
60
+ includeStats: true, // include full distribution in response
71
61
  });
72
62
  ```
73
63
 
@@ -87,11 +77,9 @@ const result = await estimateFee({
87
77
  | `balanced` | none | Hit the target exactly. Safe default for most use cases. |
88
78
  | `aggressive` | +15 percentile points | Slightly overpay to guarantee landing. |
89
79
 
90
- ---
91
-
92
80
  ## Protocol-Aware Estimation
93
81
 
94
- The most powerful feature of FEMA. When you specify a protocol, FEMA filters the fee data to only transactions that used the same programs — giving you a fee based on your actual competition, not the whole network.
82
+ The most powerful feature of Fema. When you specify a protocol, Fema filters the fee data to only transactions that used the same programs — giving you a fee based on your actual competition, not the whole network.
95
83
 
96
84
  ```ts
97
85
  // Jupiter swap
@@ -110,7 +98,7 @@ const { fee: pumpFee } = await estimateFee({
110
98
  });
111
99
  ```
112
100
 
113
- Alternatively, pass your actual transaction and FEMA will detect the protocol automatically:
101
+ Alternatively, pass your actual transaction and Fema will detect the protocol automatically:
114
102
 
115
103
  ```ts
116
104
  const { fee } = await estimateFee({
@@ -132,9 +120,7 @@ const { fee } = await estimateFee({
132
120
  | `system` | System Program (SOL transfers) |
133
121
  | `token` | Token Program, Token 2022, Associated Token Program |
134
122
 
135
- ---
136
-
137
- ## Response
123
+ ## estimateFee Response
138
124
 
139
125
  ```ts
140
126
  {
@@ -163,8 +149,6 @@ const { fee } = await estimateFee({
163
149
 
164
150
  The `fee` value is in **microLamports per compute unit** — the exact unit that `ComputeBudgetProgram.setComputeUnitPrice` expects. No conversion needed.
165
151
 
166
- ---
167
-
168
152
  ## Configuration
169
153
 
170
154
  ```ts
@@ -174,8 +158,6 @@ init({
174
158
  });
175
159
  ```
176
160
 
177
- ---
178
-
179
161
  ## Sample Code
180
162
 
181
163
  ```ts
@@ -209,7 +191,98 @@ app.listen(8000, () => {
209
191
  export default app;
210
192
  ```
211
193
 
212
- ---
194
+ ## safeSend
195
+
196
+ `safeSend` handles the full lifecycle of sending a Solana transaction. It simulates before sending, signs with your wallet, submits, and confirms on-chain. It catches errors before they cost SOL, retries automatically when safe to do so, and tells you exactly what went wrong when it isn't.
197
+
198
+ ## safeSend Quick Start
199
+
200
+ ```ts
201
+ import { safeSend } from "fema-pf-calc";
202
+
203
+ const result = await safeSend({
204
+ tx: myTransaction,
205
+ wallet: walletAdapter, // any wallet with signTransaction (Phantom, Backpack, etc.)
206
+ network: "mainnet-beta",
207
+ mode: "safe",
208
+ });
209
+
210
+ if (result.success) {
211
+ console.log("Confirmed:", result.signature);
212
+ } else {
213
+ console.log("Failed:", result.error?.type);
214
+ }
215
+ ```
216
+
217
+ ## safeSend Options
218
+
219
+ ```ts
220
+ const result = await safeSend({
221
+ tx: myTransaction, // Transaction | VersionedTransaction
222
+ wallet: walletAdapter, // must implement signTransaction
223
+ network: "mainnet-beta", // "devnet" | "mainnet-beta" (default: "devnet")
224
+ mode: "safe", // "safe" | "fast" (default: "safe")
225
+ ai: true, // enable AI diagnostics on failure (default: false)
226
+ });
227
+ ```
228
+
229
+ ### Mode
230
+
231
+ | Mode | What it does |
232
+ | ------ | -------------------------------------------------------------------------- |
233
+ | `safe` | Simulates first, retries up to 3× on recoverable errors, confirms on-chain |
234
+ | `fast` | Simulates first, sends once, returns immediately — no retries |
235
+
236
+ ## safeSend Response
237
+
238
+ ```ts
239
+ // Success
240
+ { success: true, signature: "5Kj...", network: "mainnet-beta", retriesUsed: 0 }
241
+
242
+ // Failure
243
+ {
244
+ success: false,
245
+ network: "mainnet-beta",
246
+ retriesUsed: 2,
247
+ error: {
248
+ type: "INSUFFICIENT_FUNDS",
249
+ logs: ["..."],
250
+
251
+ // only included when ai: true
252
+ explanation: "The sender account does not have enough lamports...",
253
+ suggestedFix: "Fund the account with at least 0.05 SOL before retrying.",
254
+ }
255
+ }
256
+ ```
257
+
258
+ ### Error Types
259
+
260
+ | Type | Recoverable | What happened |
261
+ | ---------------------- | ----------- | ------------------------------------------------- |
262
+ | `INSUFFICIENT_FUNDS` | No | Sender cannot cover the transfer + fees |
263
+ | `BLOCKHASH_EXPIRED` | Yes | Blockhash went stale, retried with a fresh one |
264
+ | `COMPUTE_EXCEEDED` | Yes | Compute limit too low, auto-bumped and retried |
265
+ | `INVALID_INSTRUCTION` | No | Instruction references a wrong or unknown program |
266
+ | `NETWORK_FAILURE` | No | Could not reach the RPC |
267
+ | `SEND_FAILED` | No | Transaction was rejected at submission |
268
+ | `SIGNING_REJECTED` | No | Wallet refused to sign |
269
+ | `CONFIRMATION_TIMEOUT` | No | Transaction was sent but not confirmed in time |
270
+ | `MAX_RETRIES_EXCEEDED` | No | Hit the 3-retry limit without landing |
271
+
272
+ ## AI Diagnostics
273
+
274
+ Set `ai: true` and add a `GROQ_API_KEY` to your environment to get a plain-English explanation and a concrete fix suggestion on every failure.
275
+
276
+ ```ts
277
+ const result = await safeSend({ tx, wallet, network: "mainnet-beta", ai: true });
278
+
279
+ if (!result.success) {
280
+ console.log(result.error?.explanation); // "The compute budget was exceeded..."
281
+ console.log(result.error?.suggestedFix); // "Add ComputeBudgetProgram.setComputeUnitLimit..."
282
+ }
283
+ ```
284
+
285
+ Get a free Groq API key at console.groq.com. Fema uses Llama 3.3-70b under the hood and falls back silently if the key is missing or the API is unavailable.
213
286
 
214
287
  ## License
215
288
 
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ import { FemaConfig, EstimateFeeOptions, EstimateFeeResult } from "./types";
2
2
  export type { EstimateFeeOptions, EstimateFeeResult, FemaConfig, FeeSnapshot, FeeStats, FeeEntry, Speed, Strategy, CongestionLevel, SolanaCluster, } from "./types";
3
3
  export type { Protocol } from "./protocols";
4
4
  export { PROTOCOLS } from "./protocols";
5
+ export { safeSend } from "./safeSend";
6
+ export type { SafeSendOptions, SafeSendResult, SafeSendNetwork, SafeSendMode, SafeSendError, WalletAdapter, AIExplanation, } from "./safeSend/types";
5
7
  export declare function init(config: Partial<FemaConfig>): void;
6
8
  export declare function estimateFee(options?: EstimateFeeOptions): Promise<EstimateFeeResult>;
7
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAA6B,MAAM,SAAS,CAAC;AAiBvG,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,eAAe,EACf,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAkBxC,wBAAgB,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAiBtD;AAID,wBAAsB,WAAW,CAC/B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAsE5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAA6B,MAAM,SAAS,CAAC;AAiBvG,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,eAAe,EACf,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EACV,eAAe,EACf,cAAc,EACd,eAAe,EACf,YAAY,EACZ,aAAa,EACb,aAAa,EACb,aAAa,GACd,MAAM,kBAAkB,CAAC;AAkB1B,wBAAgB,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAiBtD;AAID,wBAAsB,WAAW,CAC/B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAsE5B"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PROTOCOLS = void 0;
3
+ exports.safeSend = exports.PROTOCOLS = void 0;
4
4
  exports.init = init;
5
5
  exports.estimateFee = estimateFee;
6
6
  const config_1 = require("./config");
@@ -11,6 +11,9 @@ const database_1 = require("./services/database");
11
11
  const feeCalculator_1 = require("./engine/feeCalculator");
12
12
  var protocols_2 = require("./protocols");
13
13
  Object.defineProperty(exports, "PROTOCOLS", { enumerable: true, get: function () { return protocols_2.PROTOCOLS; } });
14
+ // ─── safeSend ─────────────────────────────────────────────────────────────────
15
+ var safeSend_1 = require("./safeSend");
16
+ Object.defineProperty(exports, "safeSend", { enumerable: true, get: function () { return safeSend_1.safeSend; } });
14
17
  // ─── SDK initialisation ───────────────────────────────────────────────────────
15
18
  let _started = false;
16
19
  // Deduplicate concurrent fetches — if a block scan is already in flight,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AA6DA,oBAiBC;AAID,kCAwEC;AAzJD,qCAA+C;AAC/C,4CAAuD;AACvD,8CAK2B;AAC3B,2CAA+E;AAC/E,kDAI6B;AAC7B,0DAAoF;AAepF,yCAAwC;AAA/B,sGAAA,SAAS,OAAA;AAElB,iFAAiF;AAEjF,uCAAsC;AAA7B,oGAAA,QAAQ,OAAA;AAWjB,iFAAiF;AAEjF,IAAI,QAAQ,GAAG,KAAK,CAAC;AAErB,yEAAyE;AACzE,oFAAoF;AACpF,IAAI,aAAa,GAA+B,IAAI,CAAC;AAErD,KAAK,UAAU,YAAY,CAAC,gBAAyB;IACnD,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IACxC,aAAa,GAAG,IAAA,gCAAuB,EAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;QACzE,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC,CAAC,CAAC;IACH,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,SAAgB,IAAI,CAAC,MAA2B;IAC9C,IAAA,aAAW,EAAC,MAAM,CAAC,CAAC;IACpB,IAAA,wBAAe,GAAE,CAAC;IAElB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,8DAA8D;QAC9D,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;YAClC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAA,4BAAY,EAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;gBACvG,IAAA,gBAAQ,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAC5B,IAAA,4BAAiB,EAAC,QAAQ,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAwD,CAAC,CAAC,CAAC;QAEzE,IAAA,iCAAsB,EAAC,GAAG,EAAE,CAAC,IAAA,gCAAqB,GAAE,EAAE,KAAM,CAAC,CAAC;QAC9D,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC;AACH,CAAC;AAED,iFAAiF;AAE1E,KAAK,UAAU,WAAW,CAC/B,UAA8B,EAAE;IAEhC,MAAM,EACJ,KAAK,GAAG,QAAQ,EAChB,QAAQ,GAAG,UAAU,EACrB,YAAY,GAAG,KAAK,EACpB,MAAM,EACN,WAAW,EACX,QAAQ,GACT,GAAG,OAAO,CAAC;IAEZ,oEAAoE;IACpE,IAAI,UAAU,GAAa,EAAE,CAAC;IAC9B,IAAI,QAAQ,EAAE,CAAC;QACb,UAAU,GAAG,IAAA,iCAAqB,EAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;SAAM,IAAI,WAAW,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,IAAA,0BAAiB,EAAC,WAAW,CAAC,CAAC;QAClD,UAAU,GAAG,UAAU,CAAC;QACxB,qEAAqE;QACrE,MAAM,QAAQ,GAAG,IAAA,0BAAc,EAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,QAAQ,EAAE,CAAC;YACb,2DAA2D;YAC3D,UAAU,GAAG,IAAA,iCAAqB,EAAC,QAAQ,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAED,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,CAAC,IAAA,6BAAoB,EAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEjF,+EAA+E;IAC/E,MAAM,MAAM,GAAG,IAAA,iBAAS,GAAE,CAAC;IAC3B,MAAM,mBAAmB,GAAG,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC;IAExF,IAAI,MAAM,IAAI,CAAC,CAAC,gBAAgB,IAAI,mBAAmB,CAAC,EAAE,CAAC;QACzD,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,IAAA,gCAAgB,EAAC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAC/E,MAAM,EAAE,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAA,4BAAY,EAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;QAC7G,OAAO,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;IAC5F,CAAC;IAED,sCAAsC;IACtC,IAAI,OAAO,GAAe,EAAE,CAAC;IAC7B,IAAI,YAAY,GAAG,KAAK,CAAC;IAEzB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,YAAY,CAAC,gBAAgB,CAAC,CAAC;QAC/C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,0CAA0C,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;QACjF,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,8CAA8C;IAC9C,IAAI,YAAY,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,IAAA,gCAAqB,GAAE,CAAC;QACvC,MAAM,YAAY,GAAG,MAAM;YACzB,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC;YACjE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACX,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,2EAA2E;IAC3E,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,IAAA,gCAAgB,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAExE,eAAe;IACf,MAAM,EAAE,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAA,4BAAY,EAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;IAE7G,8CAA8C;IAC9C,IAAA,gBAAQ,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5B,IAAA,4BAAiB,EAAC,QAAQ,CAAC,CAAC;IAE5B,OAAO,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;AAC5F,CAAC;AAED,iFAAiF;AAEjF,SAAS,WAAW,CAClB,GAAW,EACX,QAAqD,EACrD,cAAsB,EACtB,OAAiB,EACjB,YAAqB,EACrB,eAAwB;IAExB,MAAM,MAAM,GAAsB;QAChC,GAAG;QACH,UAAU,EAAE,QAAQ,CAAC,eAAe;QACpC,cAAc;QACd,UAAU,EAAE,OAAO,CAAC,MAAM;QAC1B,eAAe;KAChB,CAAC;IAEF,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,CAAC,KAAK,GAAG;YACb,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,SAAS,EAAE,QAAQ,CAAC,SAAS;YAC7B,YAAY,EAAE,iBAAiB,CAAC,OAAO,CAAC;SACzC,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,iBAAiB,CAAC,UAAoB;IAC7C,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAA,0BAAU,EAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/D,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAChG,CAAC;AAED,SAAS,eAAe,CAAC,GAAW,EAAE,MAAc,EAAE,GAAW;IAC/D,OAAO;QACL,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC;QACrB,GAAG;QACH,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM;QACN,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9B,GAAG;QACH,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC;KACtB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ErrorType, AIExplanation } from "./types";
2
+ /**
3
+ * Use Groq (Llama 3.3-70b) to analyze a Solana transaction failure.
4
+ * AI layer is post-process only — it never mutates transactions or controls retries.
5
+ *
6
+ * Falls back gracefully when GROQ_API_KEY is not set or the API call fails.
7
+ */
8
+ export declare function explain(errorType: ErrorType, logs: string[], network: string, attempts: number): Promise<AIExplanation>;
9
+ //# sourceMappingURL=aiExplainer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiExplainer.d.ts","sourceRoot":"","sources":["../../src/safeSend/aiExplainer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AA+BxD;;;;;GAKG;AACH,wBAAsB,OAAO,CAC3B,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,aAAa,CAAC,CAgCxB"}
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.explain = explain;
7
+ const groq_sdk_1 = __importDefault(require("groq-sdk"));
8
+ const MODEL = "llama-3.3-70b-versatile";
9
+ const SYSTEM_PROMPT = `You are a Solana blockchain transaction diagnostics expert.
10
+
11
+ You receive failed Solana transaction data — error type, simulation logs, network, and attempt count — and you return a precise diagnosis.
12
+
13
+ Respond ONLY with a valid JSON object in this exact shape:
14
+ {
15
+ "explanation": "<1–2 sentences explaining the root cause>",
16
+ "fixSuggestion": "<specific, actionable steps the developer should take now>",
17
+ "confidenceScore": <float 0.0–1.0>
18
+ }
19
+
20
+ Rules:
21
+ - Read the simulation logs carefully. Programs emit custom error codes and messages — use them.
22
+ - Do not repeat the error type label verbatim. Explain WHY it happened.
23
+ - fixSuggestion must be concrete (e.g. "Add ComputeBudgetProgram.setComputeUnitLimit({ units: 400000 }) as the first instruction").
24
+ - confidenceScore reflects how certain you are given the available log detail.
25
+ - No markdown, no prose outside the JSON.`;
26
+ let _client = null;
27
+ function getClient() {
28
+ if (!_client) {
29
+ _client = new groq_sdk_1.default({ apiKey: process.env.GROQ_API_KEY });
30
+ }
31
+ return _client;
32
+ }
33
+ /**
34
+ * Use Groq (Llama 3.3-70b) to analyze a Solana transaction failure.
35
+ * AI layer is post-process only — it never mutates transactions or controls retries.
36
+ *
37
+ * Falls back gracefully when GROQ_API_KEY is not set or the API call fails.
38
+ */
39
+ async function explain(errorType, logs, network, attempts) {
40
+ if (!process.env.GROQ_API_KEY?.trim()) {
41
+ return noKeyFallback(errorType);
42
+ }
43
+ const userMessage = buildUserMessage(errorType, logs, network, attempts);
44
+ try {
45
+ const client = getClient();
46
+ const response = await client.chat.completions.create({
47
+ model: MODEL,
48
+ temperature: 0.1,
49
+ max_tokens: 512,
50
+ response_format: { type: "json_object" },
51
+ messages: [
52
+ { role: "system", content: SYSTEM_PROMPT },
53
+ { role: "user", content: userMessage },
54
+ ],
55
+ });
56
+ const raw = response.choices[0]?.message?.content?.trim() ?? "{}";
57
+ const parsed = JSON.parse(raw);
58
+ return {
59
+ explanation: String(parsed.explanation ?? ""),
60
+ fixSuggestion: String(parsed.fixSuggestion ?? ""),
61
+ confidenceScore: clamp(Number(parsed.confidenceScore ?? 0.5)),
62
+ };
63
+ }
64
+ catch {
65
+ return apiFallback(errorType);
66
+ }
67
+ }
68
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
69
+ function buildUserMessage(errorType, logs, network, attempts) {
70
+ const logsBlock = logs.length > 0 ? logs.join("\n") : "(no simulation logs returned)";
71
+ return `Analyze this failed Solana transaction and diagnose the root cause.
72
+
73
+ Error Type : ${errorType}
74
+ Network : ${network}
75
+ Attempts : ${attempts}
76
+
77
+ Simulation Logs:
78
+ \`\`\`
79
+ ${logsBlock}
80
+ \`\`\``;
81
+ }
82
+ function noKeyFallback(errorType) {
83
+ return {
84
+ explanation: `Transaction failed with error: ${errorType}. Set the GROQ_API_KEY environment variable to enable AI-powered diagnostics.`,
85
+ fixSuggestion: "Add GROQ_API_KEY to your .env file. Get a free key at console.groq.com.",
86
+ confidenceScore: 0,
87
+ };
88
+ }
89
+ function apiFallback(errorType) {
90
+ return {
91
+ explanation: `Transaction failed with error: ${errorType}. AI analysis is temporarily unavailable.`,
92
+ fixSuggestion: "Inspect the simulation logs in the error object for program-specific error codes.",
93
+ confidenceScore: 0.1,
94
+ };
95
+ }
96
+ function clamp(n) {
97
+ return Math.min(1, Math.max(0, n));
98
+ }
99
+ //# sourceMappingURL=aiExplainer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiExplainer.js","sourceRoot":"","sources":["../../src/safeSend/aiExplainer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { Transaction, VersionedTransaction } from "@solana/web3.js";
2
+ import type { ErrorType } from "./types";
3
+ /**
4
+ * Apply an automatic fix for a recoverable simulation error.
5
+ *
6
+ * BLOCKHASH_EXPIRED — no-op here; the state machine's Step 2 always refreshes
7
+ * the blockhash at the top of every retry iteration, so no extra RPC call needed.
8
+ *
9
+ * COMPUTE_EXCEEDED — adds or increases the SetComputeUnitLimit instruction.
10
+ * Only possible for legacy Transaction; VersionedTransaction messages are
11
+ * compiled and cannot be modified post-construction.
12
+ */
13
+ export declare function applyFix(tx: Transaction | VersionedTransaction, errorType: ErrorType): Transaction | VersionedTransaction;
14
+ //# sourceMappingURL=autoFix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autoFix.d.ts","sourceRoot":"","sources":["../../src/safeSend/autoFix.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,oBAAoB,EAErB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AASzC;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CACtB,EAAE,EAAE,WAAW,GAAG,oBAAoB,EACtC,SAAS,EAAE,SAAS,GACnB,WAAW,GAAG,oBAAoB,CAMpC"}
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applyFix = applyFix;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const MAX_COMPUTE_UNITS = 1400000;
6
+ const DEFAULT_COMPUTE_UNITS = 400000;
7
+ const COMPUTE_UNIT_SCALE_FACTOR = 1.5;
8
+ // Discriminator byte for ComputeBudgetProgram.setComputeUnitLimit
9
+ const SET_UNIT_LIMIT_DISCRIMINATOR = 2;
10
+ /**
11
+ * Apply an automatic fix for a recoverable simulation error.
12
+ *
13
+ * BLOCKHASH_EXPIRED — no-op here; the state machine's Step 2 always refreshes
14
+ * the blockhash at the top of every retry iteration, so no extra RPC call needed.
15
+ *
16
+ * COMPUTE_EXCEEDED — adds or increases the SetComputeUnitLimit instruction.
17
+ * Only possible for legacy Transaction; VersionedTransaction messages are
18
+ * compiled and cannot be modified post-construction.
19
+ */
20
+ function applyFix(tx, errorType) {
21
+ if (errorType === "COMPUTE_EXCEEDED") {
22
+ return increaseComputeBudget(tx);
23
+ }
24
+ // BLOCKHASH_EXPIRED: Step 2 handles this — return unchanged.
25
+ return tx;
26
+ }
27
+ function increaseComputeBudget(tx) {
28
+ if (!(tx instanceof web3_js_1.Transaction)) {
29
+ // VersionedTransaction messages are immutable after compilation.
30
+ // Callers should build the transaction with a sufficient compute budget upfront.
31
+ return tx;
32
+ }
33
+ const BUDGET_PROGRAM_ID = web3_js_1.ComputeBudgetProgram.programId.toBase58();
34
+ const existingIdx = tx.instructions.findIndex((ix) => ix.programId.toBase58() === BUDGET_PROGRAM_ID &&
35
+ ix.data.length >= 5 &&
36
+ ix.data[0] === SET_UNIT_LIMIT_DISCRIMINATOR);
37
+ if (existingIdx >= 0) {
38
+ const current = new DataView(tx.instructions[existingIdx].data.buffer, tx.instructions[existingIdx].data.byteOffset).getUint32(1, true);
39
+ const increased = Math.min(Math.round(current * COMPUTE_UNIT_SCALE_FACTOR), MAX_COMPUTE_UNITS);
40
+ tx.instructions[existingIdx] = web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
41
+ units: increased,
42
+ });
43
+ }
44
+ else {
45
+ tx.instructions.unshift(web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: DEFAULT_COMPUTE_UNITS }));
46
+ }
47
+ return tx;
48
+ }
49
+ //# sourceMappingURL=autoFix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autoFix.js","sourceRoot":"","sources":["../../src/safeSend/autoFix.ts"],"names":[],"mappings":";;AAwBA,4BASC;AAjCD,6CAIyB;AAGzB,MAAM,iBAAiB,GAAG,OAAS,CAAC;AACpC,MAAM,qBAAqB,GAAG,MAAO,CAAC;AACtC,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAEtC,kEAAkE;AAClE,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAEvC;;;;;;;;;GASG;AACH,SAAgB,QAAQ,CACtB,EAAsC,EACtC,SAAoB;IAEpB,IAAI,SAAS,KAAK,kBAAkB,EAAE,CAAC;QACrC,OAAO,qBAAqB,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC;IACD,6DAA6D;IAC7D,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,qBAAqB,CAC5B,EAAsC;IAEtC,IAAI,CAAC,CAAC,EAAE,YAAY,qBAAW,CAAC,EAAE,CAAC;QACjC,iEAAiE;QACjE,iFAAiF;QACjF,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,iBAAiB,GAAG,8BAAoB,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;IAEpE,MAAM,WAAW,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,CAC3C,CAAC,EAAE,EAAE,EAAE,CACL,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,iBAAiB;QAC7C,EAAE,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC;QACnB,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,4BAA4B,CAC9C,CAAC;IAEF,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,OAAO,GAAG,IAAI,QAAQ,CAC1B,EAAE,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,EACxC,EAAE,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,UAAU,CAC7C,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAErB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CACxB,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,yBAAyB,CAAC,EAC/C,iBAAiB,CAClB,CAAC;QAEF,EAAE,CAAC,YAAY,CAAC,WAAW,CAAC,GAAG,8BAAoB,CAAC,mBAAmB,CAAC;YACtE,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,EAAE,CAAC,YAAY,CAAC,OAAO,CACrB,8BAAoB,CAAC,mBAAmB,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAC3E,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Connection } from "@solana/web3.js";
2
+ import type { SafeSendNetwork } from "./types";
3
+ export declare function getConnection(network: SafeSendNetwork): Connection;
4
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/safeSend/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAwB/C,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,UAAU,CAElE"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getConnection = getConnection;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const HELIUS_ENDPOINTS = {
6
+ "mainnet-beta": "https://mainnet.helius-rpc.com",
7
+ devnet: "https://devnet.helius-rpc.com",
8
+ };
9
+ // Zero-config fallback — FEMA proxy is Helius-backed; no API key required.
10
+ const FEMA_PROXY = "https://fema-rpc-proxy.fema-proxy.workers.dev";
11
+ /**
12
+ * Build the RPC URL for the given network.
13
+ * Uses HELIUS_API_KEY env var when available; falls back to the FEMA proxy.
14
+ * The URL is intentionally not exported — callers get a Connection, not a URL,
15
+ * to prevent the API key from leaking into application code.
16
+ */
17
+ function buildRpcUrl(network) {
18
+ const apiKey = process.env.HELIUS_API_KEY?.trim();
19
+ if (apiKey) {
20
+ return `${HELIUS_ENDPOINTS[network]}/?api-key=${apiKey}`;
21
+ }
22
+ return FEMA_PROXY;
23
+ }
24
+ function getConnection(network) {
25
+ return new web3_js_1.Connection(buildRpcUrl(network), "confirmed");
26
+ }
27
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/safeSend/connection.ts"],"names":[],"mappings":";;AAyBA,sCAEC;AA3BD,6CAA6C;AAG7C,MAAM,gBAAgB,GAAoC;IACxD,cAAc,EAAE,gCAAgC;IAChD,MAAM,EAAE,+BAA+B;CACxC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,UAAU,GAAG,+CAA+C,CAAC;AAEnE;;;;;GAKG;AACH,SAAS,WAAW,CAAC,OAAwB;IAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC;IAClD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,aAAa,MAAM,EAAE,CAAC;IAC3D,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAgB,aAAa,CAAC,OAAwB;IACpD,OAAO,IAAI,oBAAU,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { SimulationError } from "./types";
2
+ /**
3
+ * Pure function — converts raw simulation logs into a structured SimulationError.
4
+ * Order matters: more specific patterns are checked before UNKNOWN.
5
+ */
6
+ export declare function classifySimulationError(logs: string[]): SimulationError;
7
+ //# sourceMappingURL=errorClassifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorClassifier.d.ts","sourceRoot":"","sources":["../../src/safeSend/errorClassifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,eAAe,EAAE,MAAM,SAAS,CAAC;AAK1D;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,CAGvE"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.classifySimulationError = classifySimulationError;
4
+ // Error types that can be automatically recovered from.
5
+ const RECOVERABLE = new Set(["BLOCKHASH_EXPIRED", "COMPUTE_EXCEEDED"]);
6
+ /**
7
+ * Pure function — converts raw simulation logs into a structured SimulationError.
8
+ * Order matters: more specific patterns are checked before UNKNOWN.
9
+ */
10
+ function classifySimulationError(logs) {
11
+ const type = detectType(logs);
12
+ return { type, logs, recoverable: RECOVERABLE.has(type) };
13
+ }
14
+ function detectType(logs) {
15
+ const text = logs.join(" ").toLowerCase();
16
+ if (text.includes("insufficient funds") ||
17
+ text.includes("insufficient lamports") ||
18
+ text.includes("0x1") // common Solana insufficient-funds error code
19
+ ) {
20
+ return "INSUFFICIENT_FUNDS";
21
+ }
22
+ if (text.includes("blockhash not found") ||
23
+ text.includes("blockhash expired") ||
24
+ text.includes("recent blockhash") ||
25
+ text.includes("blockhashnot")) {
26
+ return "BLOCKHASH_EXPIRED";
27
+ }
28
+ if (text.includes("exceeded") &&
29
+ (text.includes("compute") || text.includes("budget") || text.includes("units"))) {
30
+ return "COMPUTE_EXCEEDED";
31
+ }
32
+ if (text.includes("invalid instruction") ||
33
+ text.includes("invalid program id") ||
34
+ text.includes("incorrect program id") ||
35
+ text.includes("unknown instruction")) {
36
+ return "INVALID_INSTRUCTION";
37
+ }
38
+ return "UNKNOWN";
39
+ }
40
+ //# sourceMappingURL=errorClassifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorClassifier.js","sourceRoot":"","sources":["../../src/safeSend/errorClassifier.ts"],"names":[],"mappings":";;AASA,0DAGC;AAVD,wDAAwD;AACxD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAY,CAAC,mBAAmB,EAAE,kBAAkB,CAAC,CAAC,CAAC;AAElF;;;GAGG;AACH,SAAgB,uBAAuB,CAAC,IAAc;IACpD,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED,SAAS,UAAU,CAAC,IAAc;IAChC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAE1C,IACE,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QACtC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,8CAA8C;MACnE,CAAC;QACD,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IAED,IACE,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QACpC,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QAClC,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QACjC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAC7B,CAAC;QACD,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IAED,IACE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;QACzB,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAC/E,CAAC;QACD,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IAED,IACE,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QACpC,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EACpC,CAAC;QACD,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { SafeSendOptions, SafeSendResult } from "./types";
2
+ export declare function safeSend(options: SafeSendOptions): Promise<SafeSendResult>;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/safeSend/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EAMf,MAAM,SAAS,CAAC;AAejB,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAsJhF"}
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.safeSend = safeSend;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const connection_1 = require("./connection");
6
+ const errorClassifier_1 = require("./errorClassifier");
7
+ const autoFix_1 = require("./autoFix");
8
+ const aiExplainer_1 = require("./aiExplainer");
9
+ const utils_1 = require("./utils");
10
+ // ─── Constants ────────────────────────────────────────────────────────────────
11
+ const MAX_RETRIES = 3;
12
+ const CONFIRMATION_TIMEOUT_MS = 60000;
13
+ const CONFIRMATION_POLL_MS = 2000;
14
+ // ─── Public API ───────────────────────────────────────────────────────────────
15
+ async function safeSend(options) {
16
+ // ── STEP 1: INPUT NORMALIZATION ─────────────────────────────────────────────
17
+ const validationError = (0, utils_1.validateInput)(options);
18
+ if (validationError) {
19
+ return buildFailure(options.network ?? "devnet", 0, {
20
+ type: "INVALID_INPUT",
21
+ explanation: validationError,
22
+ });
23
+ }
24
+ const { tx, wallet, network = "devnet", mode = "safe", ai = false } = options;
25
+ const connection = (0, connection_1.getConnection)(network);
26
+ let workingTx = tx;
27
+ let retriesUsed = 0;
28
+ // ── STATE MACHINE ───────────────────────────────────────────────────────────
29
+ for (;;) {
30
+ if (retriesUsed > MAX_RETRIES) {
31
+ return buildFailure(network, retriesUsed, { type: "MAX_RETRIES_EXCEEDED" });
32
+ }
33
+ // ── STEP 2: GET LATEST BLOCKHASH ──────────────────────────────────────────
34
+ let lastValidBlockHeight = 0;
35
+ try {
36
+ const bh = await connection.getLatestBlockhash("confirmed");
37
+ lastValidBlockHeight = bh.lastValidBlockHeight;
38
+ attachBlockhash(workingTx, bh.blockhash, bh.lastValidBlockHeight);
39
+ }
40
+ catch (err) {
41
+ const msg = (0, utils_1.sanitizeMessage)(err.message);
42
+ if (mode === "fast" || retriesUsed >= MAX_RETRIES) {
43
+ const aiFields = await fetchAIFields(ai, "NETWORK_FAILURE", [msg], network, retriesUsed + 1);
44
+ return buildFailure(network, retriesUsed, {
45
+ type: "NETWORK_FAILURE",
46
+ logs: [msg],
47
+ ...aiFields,
48
+ });
49
+ }
50
+ retriesUsed++;
51
+ continue;
52
+ }
53
+ // ── STEP 3: SIMULATION (CRITICAL GATE) ───────────────────────────────────
54
+ let simError = null;
55
+ try {
56
+ const { err, logs } = await runSimulation(connection, workingTx);
57
+ if (err !== null) {
58
+ simError = (0, errorClassifier_1.classifySimulationError)((0, utils_1.truncateLogs)(logs ?? []));
59
+ }
60
+ }
61
+ catch (err) {
62
+ const msg = (0, utils_1.sanitizeMessage)(err.message);
63
+ simError = { type: "UNKNOWN", logs: [msg], recoverable: false };
64
+ }
65
+ // ── STEP 3A: FAILURE CLASSIFICATION ──────────────────────────────────────
66
+ if (simError !== null) {
67
+ if (!simError.recoverable || retriesUsed >= MAX_RETRIES) {
68
+ const aiFields = await fetchAIFields(ai, simError.type, simError.logs, network, retriesUsed + 1);
69
+ return buildFailure(network, retriesUsed, {
70
+ type: simError.type,
71
+ logs: simError.logs,
72
+ ...aiFields,
73
+ });
74
+ }
75
+ // ── STEP 4: AUTO-FIX ENGINE — re-enter loop at Step 3 ──────────────────
76
+ workingTx = (0, autoFix_1.applyFix)(workingTx, simError.type);
77
+ retriesUsed++;
78
+ continue;
79
+ }
80
+ // ── STEP 5: WALLET SIGNING (USER CONTROLLED — never bypassed) ────────────
81
+ let signedTx;
82
+ try {
83
+ signedTx = await wallet.signTransaction(workingTx);
84
+ }
85
+ catch (err) {
86
+ const msg = (0, utils_1.sanitizeMessage)(err.message);
87
+ const aiFields = await fetchAIFields(ai, "SIGNING_REJECTED", [msg], network, retriesUsed + 1);
88
+ return buildFailure(network, retriesUsed, {
89
+ type: "SIGNING_REJECTED",
90
+ logs: [msg],
91
+ ...aiFields,
92
+ });
93
+ }
94
+ // ── STEP 6: TRANSACTION SUBMISSION ───────────────────────────────────────
95
+ let signature;
96
+ try {
97
+ const raw = serializeTx(signedTx);
98
+ signature = await connection.sendRawTransaction(raw, {
99
+ skipPreflight: true, // safe — already simulated in Step 3
100
+ preflightCommitment: "confirmed",
101
+ maxRetries: 2,
102
+ });
103
+ }
104
+ catch (err) {
105
+ const msg = (0, utils_1.sanitizeMessage)(err.message);
106
+ if (mode === "safe" && retriesUsed < MAX_RETRIES) {
107
+ retriesUsed++;
108
+ continue;
109
+ }
110
+ const aiFields = await fetchAIFields(ai, "SEND_FAILED", [msg], network, retriesUsed + 1);
111
+ return buildFailure(network, retriesUsed, {
112
+ type: "SEND_FAILED",
113
+ logs: [msg],
114
+ ...aiFields,
115
+ });
116
+ }
117
+ // ── STEP 7: CONFIRMATION LOOP ─────────────────────────────────────────────
118
+ const confirmResult = await waitForConfirmation(connection, signature, lastValidBlockHeight);
119
+ if (confirmResult === "confirmed") {
120
+ return { success: true, signature, network, retriesUsed };
121
+ }
122
+ // ── STEP 8: RETRY ENGINE (SAFE ONLY) ─────────────────────────────────────
123
+ // Only retry when the blockhash provably expired — transaction is dead,
124
+ // no risk of duplicating a confirmed send.
125
+ if (confirmResult === "expired" && mode === "safe" && retriesUsed < MAX_RETRIES) {
126
+ retriesUsed++;
127
+ continue; // Step 2 attaches a fresh blockhash
128
+ }
129
+ // ── STEP 9: FINAL RESPONSE ────────────────────────────────────────────────
130
+ const finalType = confirmResult === "expired" ? "BLOCKHASH_EXPIRED" : "CONFIRMATION_TIMEOUT";
131
+ const aiFields = await fetchAIFields(ai, finalType, [], network, retriesUsed + 1);
132
+ return buildFailure(network, retriesUsed, {
133
+ type: finalType,
134
+ ...(aiFields.explanation && {
135
+ explanation: `Transaction (${signature}) could not be confirmed. ${aiFields.explanation}`,
136
+ suggestedFix: aiFields.suggestedFix,
137
+ }),
138
+ });
139
+ }
140
+ }
141
+ // ─── Internal helpers ─────────────────────────────────────────────────────────
142
+ /**
143
+ * Fetch AI explanation fields when ai=true.
144
+ * Returns an empty object when ai=false so callers can spread it safely.
145
+ */
146
+ async function fetchAIFields(ai, type, logs, network, attempts) {
147
+ if (!ai)
148
+ return {};
149
+ const data = await (0, aiExplainer_1.explain)(type, logs, network, attempts);
150
+ return { explanation: data.explanation, suggestedFix: data.fixSuggestion };
151
+ }
152
+ function attachBlockhash(tx, blockhash, lastValidBlockHeight) {
153
+ if (tx instanceof web3_js_1.Transaction) {
154
+ tx.recentBlockhash = blockhash;
155
+ tx.lastValidBlockHeight = lastValidBlockHeight;
156
+ }
157
+ else {
158
+ tx.message.recentBlockhash = blockhash;
159
+ }
160
+ }
161
+ function serializeTx(tx) {
162
+ if (tx instanceof web3_js_1.Transaction)
163
+ return tx.serialize();
164
+ return tx.serialize();
165
+ }
166
+ async function runSimulation(connection, tx) {
167
+ // Cast required: web3.js has different overloads for Transaction vs VersionedTransaction.
168
+ // sigVerify: false allows simulation of an unsigned transaction.
169
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
170
+ const res = await connection.simulateTransaction(tx, tx instanceof web3_js_1.Transaction ? undefined : { sigVerify: false });
171
+ return { err: res.value.err ?? null, logs: res.value.logs ?? null };
172
+ }
173
+ async function waitForConfirmation(connection, signature, lastValidBlockHeight) {
174
+ const deadline = Date.now() + CONFIRMATION_TIMEOUT_MS;
175
+ while (Date.now() < deadline) {
176
+ try {
177
+ const blockHeight = await connection.getBlockHeight("confirmed");
178
+ if (blockHeight > lastValidBlockHeight)
179
+ return "expired";
180
+ const statuses = await connection.getSignatureStatuses([signature]);
181
+ const status = statuses?.value?.[0];
182
+ if (status?.err)
183
+ return "timeout"; // on-chain execution error — not retriable
184
+ if (status?.confirmationStatus === "confirmed" ||
185
+ status?.confirmationStatus === "finalized") {
186
+ return "confirmed";
187
+ }
188
+ }
189
+ catch {
190
+ // Transient RPC error — keep polling until deadline.
191
+ }
192
+ await sleep(CONFIRMATION_POLL_MS);
193
+ }
194
+ return "timeout";
195
+ }
196
+ function buildFailure(network, retriesUsed, error) {
197
+ return { success: false, network, retriesUsed, error };
198
+ }
199
+ function sleep(ms) {
200
+ return new Promise((resolve) => setTimeout(resolve, ms));
201
+ }
202
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/safeSend/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import { Transaction, VersionedTransaction } from "@solana/web3.js";
2
+ export type SafeSendNetwork = "devnet" | "mainnet-beta";
3
+ export type SafeSendMode = "safe" | "fast";
4
+ export type ErrorType = "INSUFFICIENT_FUNDS" | "BLOCKHASH_EXPIRED" | "COMPUTE_EXCEEDED" | "INVALID_INSTRUCTION" | "NETWORK_FAILURE" | "SEND_FAILED" | "SIGNING_REJECTED" | "CONFIRMATION_TIMEOUT" | "INVALID_INPUT" | "MAX_RETRIES_EXCEEDED" | "UNKNOWN";
5
+ export interface WalletAdapter {
6
+ signTransaction<T extends Transaction | VersionedTransaction>(tx: T): Promise<T>;
7
+ }
8
+ export interface SafeSendOptions {
9
+ tx: Transaction | VersionedTransaction;
10
+ wallet: WalletAdapter;
11
+ network?: SafeSendNetwork;
12
+ mode?: SafeSendMode;
13
+ ai?: boolean;
14
+ }
15
+ export interface SafeSendError {
16
+ type: ErrorType | string;
17
+ logs?: string[];
18
+ explanation?: string;
19
+ suggestedFix?: string;
20
+ }
21
+ export interface SafeSendResult {
22
+ success: boolean;
23
+ signature?: string;
24
+ network: SafeSendNetwork;
25
+ retriesUsed: number;
26
+ error?: SafeSendError;
27
+ }
28
+ export interface SimulationError {
29
+ type: ErrorType;
30
+ logs: string[];
31
+ recoverable: boolean;
32
+ }
33
+ export interface AIExplanation {
34
+ explanation: string;
35
+ fixSuggestion: string;
36
+ confidenceScore: number;
37
+ }
38
+ export type ConfirmationStatus = "confirmed" | "expired" | "timeout";
39
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/safeSend/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAIpE,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,cAAc,CAAC;AACxD,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC;AAI3C,MAAM,MAAM,SAAS,GACjB,oBAAoB,GACpB,mBAAmB,GACnB,kBAAkB,GAClB,qBAAqB,GACrB,iBAAiB,GACjB,aAAa,GACb,kBAAkB,GAClB,sBAAsB,GACtB,eAAe,GACf,sBAAsB,GACtB,SAAS,CAAC;AAId,MAAM,WAAW,aAAa;IAC5B,eAAe,CAAC,CAAC,SAAS,WAAW,GAAG,oBAAoB,EAAE,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAClF;AAID,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,WAAW,GAAG,oBAAoB,CAAC;IACvC,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,EAAE,CAAC,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAID,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/safeSend/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import type { SafeSendOptions } from "./types";
2
+ /**
3
+ * Strip API keys from RPC URLs that may appear in error messages.
4
+ * Helius and similar providers embed the key as ?api-key=<value>.
5
+ */
6
+ export declare function sanitizeMessage(message: string): string;
7
+ /**
8
+ * Truncate simulation logs to prevent oversized payloads reaching the caller.
9
+ * Keeps the first N lines which contain the most useful diagnostic info.
10
+ */
11
+ export declare function truncateLogs(logs: string[], maxLines?: number): string[];
12
+ /** Validate safeSend inputs. Returns an error string or null if valid. */
13
+ export declare function validateInput(options: SafeSendOptions): string | null;
14
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/safeSend/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,QAAQ,SAAK,GAAG,MAAM,EAAE,CAMpE;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAiCrE"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeMessage = sanitizeMessage;
4
+ exports.truncateLogs = truncateLogs;
5
+ exports.validateInput = validateInput;
6
+ const web3_js_1 = require("@solana/web3.js");
7
+ /**
8
+ * Strip API keys from RPC URLs that may appear in error messages.
9
+ * Helius and similar providers embed the key as ?api-key=<value>.
10
+ */
11
+ function sanitizeMessage(message) {
12
+ return message.replace(/([?&]api-key=)[^&\s"']*/gi, "$1***");
13
+ }
14
+ /**
15
+ * Truncate simulation logs to prevent oversized payloads reaching the caller.
16
+ * Keeps the first N lines which contain the most useful diagnostic info.
17
+ */
18
+ function truncateLogs(logs, maxLines = 20) {
19
+ if (logs.length <= maxLines)
20
+ return logs;
21
+ return [
22
+ ...logs.slice(0, maxLines),
23
+ `... (${logs.length - maxLines} more lines truncated)`,
24
+ ];
25
+ }
26
+ /** Validate safeSend inputs. Returns an error string or null if valid. */
27
+ function validateInput(options) {
28
+ if (!options.tx)
29
+ return "options.tx is required";
30
+ if (!(options.tx instanceof web3_js_1.Transaction) &&
31
+ !(options.tx instanceof web3_js_1.VersionedTransaction)) {
32
+ return "options.tx must be a Transaction or VersionedTransaction instance";
33
+ }
34
+ if (!options.wallet)
35
+ return "options.wallet is required";
36
+ if (typeof options.wallet.signTransaction !== "function") {
37
+ return "options.wallet must implement signTransaction()";
38
+ }
39
+ if (options.network !== undefined &&
40
+ options.network !== "devnet" &&
41
+ options.network !== "mainnet-beta") {
42
+ return 'options.network must be "devnet" or "mainnet-beta"';
43
+ }
44
+ if (options.mode !== undefined &&
45
+ options.mode !== "safe" &&
46
+ options.mode !== "fast") {
47
+ return 'options.mode must be "safe" or "fast"';
48
+ }
49
+ return null;
50
+ }
51
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/safeSend/utils.ts"],"names":[],"mappings":";;AAOA,0CAEC;AAMD,oCAMC;AAGD,sCAiCC;AAzDD,6CAAoE;AAGpE;;;GAGG;AACH,SAAgB,eAAe,CAAC,OAAe;IAC7C,OAAO,OAAO,CAAC,OAAO,CAAC,2BAA2B,EAAE,OAAO,CAAC,CAAC;AAC/D,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,IAAc,EAAE,QAAQ,GAAG,EAAE;IACxD,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,OAAO;QACL,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;QAC1B,QAAQ,IAAI,CAAC,MAAM,GAAG,QAAQ,wBAAwB;KACvD,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,SAAgB,aAAa,CAAC,OAAwB;IACpD,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,wBAAwB,CAAC;IAEjD,IACE,CAAC,CAAC,OAAO,CAAC,EAAE,YAAY,qBAAW,CAAC;QACpC,CAAC,CAAC,OAAO,CAAC,EAAE,YAAY,8BAAoB,CAAC,EAC7C,CAAC;QACD,OAAO,mEAAmE,CAAC;IAC7E,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,4BAA4B,CAAC;IAEzD,IAAI,OAAO,OAAO,CAAC,MAAM,CAAC,eAAe,KAAK,UAAU,EAAE,CAAC;QACzD,OAAO,iDAAiD,CAAC;IAC3D,CAAC;IAED,IACE,OAAO,CAAC,OAAO,KAAK,SAAS;QAC7B,OAAO,CAAC,OAAO,KAAK,QAAQ;QAC5B,OAAO,CAAC,OAAO,KAAK,cAAc,EAClC,CAAC;QACD,OAAO,oDAAoD,CAAC;IAC9D,CAAC;IAED,IACE,OAAO,CAAC,IAAI,KAAK,SAAS;QAC1B,OAAO,CAAC,IAAI,KAAK,MAAM;QACvB,OAAO,CAAC,IAAI,KAAK,MAAM,EACvB,CAAC;QACD,OAAO,uCAAuC,CAAC;IACjD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fema-pf-calc",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "description": "Intelligent Solana priority fee estimation engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,6 +22,7 @@
22
22
  "build": "tsc",
23
23
  "prepublishOnly": "npm run build",
24
24
  "dev": "ts-node test-fees.ts",
25
+ "test:safesend": "ts-node test-safesend.ts",
25
26
  "lint": "eslint src/**/*.ts"
26
27
  },
27
28
  "keywords": [
@@ -41,5 +42,8 @@
41
42
  "express": "^4.21.2",
42
43
  "ts-node": "^10.9.2",
43
44
  "typescript": "^5.8.3"
45
+ },
46
+ "dependencies": {
47
+ "groq-sdk": "^1.1.2"
44
48
  }
45
49
  }