apinow-sdk 0.2.0 → 0.4.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,6 +1,13 @@
1
1
  # ApiNow SDK
2
2
 
3
- The endpoint vending machine - SDK for interacting with ApiNow endpoints. This is the official SDK for [ApiNow.fun](https://apinow.fun).
3
+ A TypeScript SDK for interacting with ApiNow endpoints, supporting Ethereum (including Base), and Solana chains.
4
+
5
+ ## Features
6
+
7
+ - Multi-chain support (Ethereum, Base, Solana)
8
+ - Token transfers (ERC20 on ETH/Base, SPL on Solana)
9
+ - Fast mode for quicker transaction processing
10
+ - TypeScript types for better development experience
4
11
 
5
12
  ## Installation
6
13
 
@@ -8,78 +15,128 @@ The endpoint vending machine - SDK for interacting with ApiNow endpoints. This i
8
15
  npm install apinow-sdk
9
16
  ```
10
17
 
11
- ## Quick Start
18
+ ## Usage
12
19
 
13
- ```ts
20
+ ### Basic Example
21
+
22
+ ```typescript
14
23
  import apiNow from 'apinow-sdk';
15
24
 
16
- // One-shot purchase and response
25
+ // Get endpoint info
26
+ const info = await apiNow.info('https://apinow.fun/api/endpoints/your-endpoint');
27
+
28
+ // Send payment and get response
17
29
  const response = await apiNow.infoBuyResponse(
18
- 'https://apinow.fun/api/endpoints/my-endpoint',
19
- '0x123...private-key',
20
- 'https://eth-mainnet.g.alchemy.com/v2/YOUR-API-KEY'
30
+ 'https://apinow.fun/api/endpoints/your-endpoint',
31
+ 'YOUR_PRIVATE_KEY',
32
+ 'YOUR_RPC_URL'
21
33
  );
22
34
  ```
23
35
 
24
- ## API Reference
36
+ ### Fast Mode
25
37
 
26
- ### info(endpoint)
27
- Fetches endpoint metadata like required ETH amount and wallet address.
38
+ Fast mode skips transaction confirmation and only waits for the transaction to be in the mempool. This provides much faster responses but slightly less security:
28
39
 
29
- ```ts
30
- const info = await apiNow.info('https://apinow.fun/api/endpoints/my-endpoint');
31
- // Returns: {
32
- // requiredAmount: "0.1",
33
- // walletAddress: "0x123...",
34
- // httpMethod: "POST"
35
- // }
40
+ ```typescript
41
+ const response = await apiNow.infoBuyResponse(
42
+ 'https://apinow.fun/api/endpoints/your-endpoint',
43
+ 'YOUR_PRIVATE_KEY',
44
+ 'YOUR_RPC_URL',
45
+ { fastMode: true }
46
+ );
36
47
  ```
37
48
 
38
- ### buy(walletAddress, amount, privateKey, rpcUrl)
39
- Sends an ETH transaction to purchase endpoint access.
49
+ ### Chain-Specific Examples
50
+
51
+ #### Ethereum/Base
40
52
 
41
- ```ts
53
+ ```typescript
54
+ // Native ETH/BASE transfer
42
55
  const txHash = await apiNow.buy(
43
- "0x123...wallet", // Destination wallet
44
- ethers.parseEther("0.1"), // Amount in ETH
45
- "0x456...private-key", // Your private key
46
- "https://eth-mainnet.g.alchemy.com/v2/YOUR-API-KEY" // RPC URL
56
+ 'RECIPIENT_ADDRESS',
57
+ ethers.parseEther('0.1'),
58
+ 'YOUR_PRIVATE_KEY',
59
+ 'YOUR_RPC_URL',
60
+ 'eth'
47
61
  );
48
- ```
49
62
 
50
- ### txResponse(endpoint, txHash, options?)
51
- Gets the API response using your transaction hash.
52
-
53
- ```ts
54
- const response = await apiNow.txResponse(
55
- "https://apinow.fun/api/endpoints/my-endpoint",
56
- "0x789...txhash",
57
- {
58
- method: "POST", // Optional, defaults to GET
59
- data: { foo: "bar" } // Optional request body
60
- }
63
+ // ERC20 token transfer
64
+ const txHash = await apiNow.buy(
65
+ 'RECIPIENT_ADDRESS',
66
+ ethers.parseUnits('100', 18), // Use appropriate decimals
67
+ 'YOUR_PRIVATE_KEY',
68
+ 'YOUR_RPC_URL',
69
+ 'eth',
70
+ 'TOKEN_ADDRESS'
61
71
  );
62
72
  ```
63
73
 
64
- ### infoBuyResponse(endpoint, privateKey, rpcUrl, options?)
65
- Combines all steps: fetches info, sends payment, and gets response.
74
+ #### Solana
66
75
 
67
- ```ts
68
- // Complete example with all parameters
69
- const response = await apiNow.infoBuyResponse(
70
- "https://apinow.fun/api/endpoints/my-endpoint",
71
- "0x123...private-key",
72
- "https://eth-mainnet.g.alchemy.com/v2/YOUR-API-KEY",
73
- {
74
- method: "POST", // Optional, defaults to endpoint's httpMethod
75
- data: { // Optional request body
76
- query: "example",
77
- limit: 10
78
- }
79
- }
76
+ ```typescript
77
+ // Native SOL transfer
78
+ const txHash = await apiNow.buy(
79
+ 'RECIPIENT_ADDRESS',
80
+ BigInt(LAMPORTS_PER_SOL), // 1 SOL
81
+ 'YOUR_PRIVATE_KEY',
82
+ 'YOUR_RPC_URL',
83
+ 'sol'
84
+ );
85
+
86
+ // SPL token transfer
87
+ const txHash = await apiNow.buy(
88
+ 'RECIPIENT_ADDRESS',
89
+ BigInt(1000000), // Amount in raw units (e.g. 1.0 for 6 decimals)
90
+ 'YOUR_PRIVATE_KEY',
91
+ 'YOUR_RPC_URL',
92
+ 'sol',
93
+ 'TOKEN_ADDRESS'
80
94
  );
81
95
  ```
82
96
 
97
+ ## API Reference
98
+
99
+ ### `info(endpoint: string): Promise<InfoResponse>`
100
+
101
+ Gets information about an endpoint.
102
+
103
+ ### `buy(walletAddress: string, amount: bigint, pkey: string, rpc: string, chain?: 'eth' | 'sol', tokenAddress?: string, fastMode?: boolean): Promise<string>`
104
+
105
+ Sends a payment transaction. For tokens, provide the amount in raw units (e.g. wei for ERC20, raw units for SPL).
106
+
107
+ ### `txResponse(endpoint: string, txHash: string, opts?: TxResponseOptions): Promise<any>`
108
+
109
+ Gets the API response for a transaction.
110
+
111
+ ### `infoBuyResponse(endpoint: string, pkey: string, rpc: string, opts?: TxResponseOptions & { fastMode?: boolean }): Promise<any>`
112
+
113
+ Combines info, buy, and txResponse into a single call.
114
+
115
+ ## Types
116
+
117
+ ```typescript
118
+ interface TxResponseOptions {
119
+ method?: string;
120
+ data?: any;
121
+ }
122
+
123
+ interface InfoResponse {
124
+ requiredAmount: string;
125
+ walletAddress: string;
126
+ httpMethod: string;
127
+ tokenAddress?: string;
128
+ chain: 'eth' | 'sol';
129
+ }
130
+ ```
131
+
132
+ ## Error Handling
133
+
134
+ The SDK throws descriptive errors for various failure cases:
135
+ - Invalid endpoint URLs
136
+ - Transaction failures
137
+ - Network issues
138
+ - Invalid addresses or amounts
139
+
83
140
  ## License
84
141
 
85
142
  MIT
package/dist/index.d.ts CHANGED
@@ -7,12 +7,16 @@ interface InfoResponse {
7
7
  walletAddress: string;
8
8
  httpMethod: string;
9
9
  tokenAddress?: string;
10
+ chain: 'eth' | 'sol';
10
11
  }
11
12
  declare class ApiNow {
13
+ private handlers;
12
14
  info(endpoint: string): Promise<InfoResponse>;
13
- buy(walletAddress: string, amount: bigint, pkey: string, rpc: string, tokenAddress?: string): Promise<string>;
15
+ buy(walletAddress: string, amount: bigint, pkey: string, rpc: string, chain?: 'eth' | 'sol', tokenAddress?: string, fastMode?: boolean): Promise<string>;
14
16
  txResponse(endpoint: string, txHash: string, opts?: TxResponseOptions): Promise<any>;
15
- infoBuyResponse(endpoint: string, pkey: string, rpc: string, opts?: TxResponseOptions): Promise<any>;
17
+ infoBuyResponse(endpoint: string, pkey: string, rpc: string, opts?: TxResponseOptions & {
18
+ fastMode?: boolean;
19
+ }): Promise<any>;
16
20
  }
17
21
  declare const _default: ApiNow;
18
22
  export default _default;
package/dist/index.js CHANGED
@@ -5,19 +5,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const ethers_1 = require("ethers");
7
7
  const node_fetch_1 = __importDefault(require("node-fetch"));
8
- class ApiNow {
9
- async info(endpoint) {
10
- if (!endpoint.startsWith('https://apinow.fun/api/endpoints/')) {
11
- throw new Error('Invalid endpoint URL format');
12
- }
13
- console.log(`Fetching info from ${endpoint}`);
14
- const response = await (0, node_fetch_1.default)(`${endpoint}`);
15
- if (!response.ok) {
16
- throw new Error(`Failed to fetch endpoint info: ${response.status}`);
17
- }
18
- return response.json();
19
- }
20
- async buy(walletAddress, amount, pkey, rpc, tokenAddress) {
8
+ const web3_js_1 = require("@solana/web3.js");
9
+ const spl_token_1 = require("@solana/spl-token");
10
+ const bs58_1 = __importDefault(require("bs58"));
11
+ class EthereumHandler {
12
+ async buy(walletAddress, amount, pkey, rpc, tokenAddress, fastMode) {
21
13
  if (!rpc || typeof rpc !== 'string') {
22
14
  throw new Error('Invalid RPC URL');
23
15
  }
@@ -35,14 +27,12 @@ class ApiNow {
35
27
  ? 30000
36
28
  : 21000;
37
29
  if (tokenAddress) {
38
- // ERC20 transfer
39
30
  const abi = ["function transfer(address to, uint256 amount) returns (bool)"];
40
31
  const tokenContract = new ethers_1.ethers.Contract(tokenAddress, abi, wallet);
41
32
  const tx = await tokenContract.transfer(walletAddress, amount);
42
33
  return tx.hash;
43
34
  }
44
35
  else {
45
- // Native ETH transfer
46
36
  const tx = await wallet.sendTransaction({
47
37
  to: walletAddress,
48
38
  value: amount,
@@ -60,6 +50,135 @@ class ApiNow {
60
50
  throw new Error(`Transaction failed: ${error instanceof Error ? error.message : String(error)}`);
61
51
  }
62
52
  }
53
+ }
54
+ class SolanaHandler {
55
+ async sendWithRetry(connection, transaction, senderKeypair, fastMode, maxAttempts = 3) {
56
+ let lastError;
57
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
58
+ try {
59
+ console.log(`\nAttempt ${attempt}/${maxAttempts}`);
60
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('processed');
61
+ console.log('Got blockhash:', blockhash.slice(0, 10) + '...');
62
+ transaction.recentBlockhash = blockhash;
63
+ transaction.lastValidBlockHeight = lastValidBlockHeight;
64
+ transaction.feePayer = senderKeypair.publicKey;
65
+ transaction.signatures = [];
66
+ transaction.sign(senderKeypair);
67
+ const rawTx = transaction.serialize();
68
+ const signature = await connection.sendRawTransaction(rawTx, {
69
+ skipPreflight: false,
70
+ maxRetries: 1,
71
+ preflightCommitment: 'processed'
72
+ });
73
+ console.log('Transaction sent! Signature:', signature);
74
+ if (!fastMode) {
75
+ console.log('Waiting for confirmation...');
76
+ let confirmationAttempt = 1;
77
+ while (confirmationAttempt <= 5) {
78
+ try {
79
+ console.log(`Confirmation attempt ${confirmationAttempt}/5`);
80
+ await connection.confirmTransaction({
81
+ signature,
82
+ blockhash,
83
+ lastValidBlockHeight
84
+ }, 'processed');
85
+ console.log('Transaction confirmed!');
86
+ return signature;
87
+ }
88
+ catch (confirmError) {
89
+ const errorMessage = confirmError instanceof Error
90
+ ? confirmError.message
91
+ : 'Unknown confirmation error';
92
+ console.log('Confirmation failed:', errorMessage);
93
+ if (confirmationAttempt === 5)
94
+ throw confirmError;
95
+ confirmationAttempt++;
96
+ await new Promise(resolve => setTimeout(resolve, 1000));
97
+ }
98
+ }
99
+ }
100
+ return signature;
101
+ }
102
+ catch (error) {
103
+ const errorMessage = error instanceof Error
104
+ ? error.message
105
+ : 'Unknown error';
106
+ console.log('Attempt failed:', errorMessage);
107
+ lastError = error;
108
+ if (attempt < maxAttempts) {
109
+ console.log('Waiting 500ms before retry...');
110
+ await new Promise(resolve => setTimeout(resolve, 500));
111
+ }
112
+ }
113
+ }
114
+ throw lastError;
115
+ }
116
+ async buy(walletAddress, amount, pkey, rpc, tokenAddress, fastMode) {
117
+ const connection = new web3_js_1.Connection(rpc, {
118
+ commitment: 'processed',
119
+ confirmTransactionInitialTimeout: 10000
120
+ });
121
+ try {
122
+ const recipientPubkey = new web3_js_1.PublicKey(walletAddress);
123
+ const senderKeypair = web3_js_1.Keypair.fromSecretKey(bs58_1.default.decode(pkey));
124
+ const transaction = new web3_js_1.Transaction();
125
+ // Add priority fee instruction
126
+ transaction.add(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
127
+ microLamports: 50000
128
+ }));
129
+ if (tokenAddress) {
130
+ const mint = new web3_js_1.PublicKey(tokenAddress);
131
+ const senderATA = await (0, spl_token_1.getAssociatedTokenAddress)(mint, senderKeypair.publicKey);
132
+ const recipientATA = await (0, spl_token_1.getAssociatedTokenAddress)(mint, recipientPubkey);
133
+ // Get token decimals
134
+ const mintInfo = await (0, spl_token_1.getMint)(connection, mint);
135
+ console.log('Token decimals:', mintInfo.decimals);
136
+ console.log('Original amount:', amount.toString());
137
+ // Don't multiply by decimals since amount is already raw
138
+ transaction.add((0, spl_token_1.createTransferInstruction)(senderATA, recipientATA, senderKeypair.publicKey, Number(amount) // Use raw amount directly
139
+ ));
140
+ }
141
+ else {
142
+ // SOL transfer
143
+ transaction.add(web3_js_1.SystemProgram.transfer({
144
+ fromPubkey: senderKeypair.publicKey,
145
+ toPubkey: recipientPubkey,
146
+ lamports: Number(amount)
147
+ }));
148
+ }
149
+ return await this.sendWithRetry(connection, transaction, senderKeypair, !!fastMode);
150
+ }
151
+ catch (error) {
152
+ console.error('Detailed error:', error);
153
+ throw new Error(`Transaction failed: ${error instanceof Error ? error.message : String(error)}`);
154
+ }
155
+ }
156
+ }
157
+ class ApiNow {
158
+ constructor() {
159
+ this.handlers = {
160
+ eth: new EthereumHandler(),
161
+ sol: new SolanaHandler()
162
+ };
163
+ }
164
+ async info(endpoint) {
165
+ if (!endpoint.startsWith('https://apinow.fun/api/endpoints/')) {
166
+ throw new Error('Invalid endpoint URL format');
167
+ }
168
+ console.log(`Fetching info from ${endpoint}`);
169
+ const response = await (0, node_fetch_1.default)(`${endpoint}`);
170
+ if (!response.ok) {
171
+ throw new Error(`Failed to fetch endpoint info: ${response.status}`);
172
+ }
173
+ return response.json();
174
+ }
175
+ async buy(walletAddress, amount, pkey, rpc, chain = 'eth', tokenAddress, fastMode) {
176
+ const handler = this.handlers[chain];
177
+ if (!handler) {
178
+ throw new Error(`Unsupported chain: ${chain}`);
179
+ }
180
+ return handler.buy(walletAddress, amount, pkey, rpc, tokenAddress, fastMode);
181
+ }
63
182
  async txResponse(endpoint, txHash, opts = {}) {
64
183
  if (!endpoint.startsWith('https://apinow.fun/api/endpoints/')) {
65
184
  throw new Error('Invalid endpoint URL format');
@@ -81,8 +200,10 @@ class ApiNow {
81
200
  }
82
201
  async infoBuyResponse(endpoint, pkey, rpc, opts = {}) {
83
202
  const info = await this.info(endpoint);
84
- const amount = ethers_1.ethers.parseEther(info.requiredAmount);
85
- const txHash = await this.buy(info.walletAddress, amount, pkey, rpc, info.tokenAddress);
203
+ const amount = info.chain === 'sol'
204
+ ? BigInt(Math.round(Number(info.requiredAmount) * web3_js_1.LAMPORTS_PER_SOL))
205
+ : ethers_1.ethers.parseEther(info.requiredAmount);
206
+ const txHash = await this.buy(info.walletAddress, amount, pkey, rpc, info.chain, info.tokenAddress, opts.fastMode);
86
207
  console.log('infoBuyResponse:', { endpoint, txHash, ...opts });
87
208
  const response = await this.txResponse(endpoint, txHash, {
88
209
  method: opts.method || info.httpMethod,
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "apinow-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "ApiNow SDK · The endpoint vending machine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "type": "module",
7
8
  "files": [
8
9
  "dist"
9
10
  ],
@@ -20,6 +21,9 @@
20
21
  "author": "Your Name",
21
22
  "license": "MIT",
22
23
  "dependencies": {
24
+ "@solana/spl-token": "^0.4.12",
25
+ "@solana/web3.js": "^1.98.0",
26
+ "bs58": "^6.0.0",
23
27
  "ethers": "^6.13.5",
24
28
  "node-fetch": "^3.3.2"
25
29
  },