apinow-sdk 0.26.0 → 0.27.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/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ const program = new Command();
7
7
  program
8
8
  .name('apinow')
9
9
  .description('CLI for APINow.fun — search, inspect, and call pay-per-request APIs')
10
- .version('0.26.0');
10
+ .version('0.27.0');
11
11
  // ─── Helpers ───
12
12
  function getPrivateKey(opts) {
13
13
  const raw = opts.key || process.env.APINOW_WALLET_PKEY || process.env.PRIVATE_KEY;
package/dist/index.d.ts CHANGED
@@ -18,11 +18,31 @@ export interface PriceDiscovery {
18
18
  network: string;
19
19
  upstreamAccepts: any[];
20
20
  }
21
- export interface ApinowConfig {
21
+ /**
22
+ * Agent/server path — signs everything with a raw private key. Enables
23
+ * both x402 paid calls and signed-auth write calls.
24
+ */
25
+ export interface ApinowServerConfig {
22
26
  privateKey: `0x${string}`;
23
27
  baseUrl?: string;
24
28
  fetch?: typeof globalThis.fetch;
25
29
  }
30
+ /**
31
+ * Browser/wallet path — you provide a `signer` (any EIP-191 `personal_sign`
32
+ * function, e.g. from wagmi's `walletClient.signMessage`) and the connected
33
+ * `address`. Enables signed-auth writes. Paid x402 calls are NOT provided by
34
+ * this path — construct the x402 fetch yourself (see useX402Fetch pattern in
35
+ * the skill docs) and pass it to `paidFetch` if you need unified behaviour.
36
+ */
37
+ export interface ApinowBrowserConfig {
38
+ signer: (message: string) => Promise<`0x${string}` | string>;
39
+ address: `0x${string}`;
40
+ baseUrl?: string;
41
+ fetch?: typeof globalThis.fetch;
42
+ /** Optional externally-prepared x402 fetch for paid calls. */
43
+ paidFetch?: typeof globalThis.fetch;
44
+ }
45
+ export type ApinowConfig = ApinowServerConfig | ApinowBrowserConfig;
26
46
  export interface GenerateUIOptions {
27
47
  endpointName: string;
28
48
  namespace: string;
package/dist/index.js CHANGED
@@ -2,6 +2,9 @@ import { x402Client, wrapFetchWithPayment } from '@x402/fetch';
2
2
  import { registerExactEvmScheme } from '@x402/evm/exact/client';
3
3
  import { privateKeyToAccount } from 'viem/accounts';
4
4
  const APINOW_BASE = 'https://apinow.fun';
5
+ function isServerConfig(c) {
6
+ return 'privateKey' in c && typeof c.privateKey === 'string';
7
+ }
5
8
  // ─── SDK ───
6
9
  // Prevent undici (Node 20+ / Vercel) from crashing when @x402/fetch retries
7
10
  // a POST with a cloned Request body stream and the server returns a 3xx redirect.
@@ -23,31 +26,50 @@ async function followRedirects(res) {
23
26
  return res;
24
27
  }
25
28
  export function createClient(config) {
26
- const { privateKey, baseUrl = APINOW_BASE, fetch: customFetch } = config;
27
- const account = privateKeyToAccount(privateKey);
28
- const client = new x402Client();
29
- registerExactEvmScheme(client, { signer: account });
30
- const safeFetch = makeSafeFetch(customFetch ?? fetch);
31
- const rawFetchWithPayment = wrapFetchWithPayment(safeFetch, client);
32
- const fetchWithPayment = (async (input, init) => {
33
- const res = await rawFetchWithPayment(input, init);
34
- return followRedirects(res);
35
- });
29
+ const server = isServerConfig(config);
30
+ const baseUrl = config.baseUrl ?? APINOW_BASE;
31
+ const customFetch = config.fetch;
32
+ // Resolve address + signer from whichever config shape the caller passed.
33
+ const account = server ? privateKeyToAccount(config.privateKey) : null;
34
+ const address = server
35
+ ? account.address
36
+ : config.address.toLowerCase();
37
+ const signMessage = server
38
+ ? (msg) => account.signMessage({ message: msg })
39
+ : (msg) => Promise.resolve(config.signer(msg)).then((s) => String(s));
40
+ // x402 paid fetch — only available when a private key is provided. Browsers
41
+ // should build their own x402 fetch (see skill.md useX402Fetch) and pass it
42
+ // as `paidFetch` to fall back through here.
43
+ const paidFetchExternal = !server ? config.paidFetch : undefined;
44
+ const fetchWithPayment = server
45
+ ? (() => {
46
+ const client = new x402Client();
47
+ registerExactEvmScheme(client, { signer: account });
48
+ const safeFetch = makeSafeFetch(customFetch ?? fetch);
49
+ const rawFetchWithPayment = wrapFetchWithPayment(safeFetch, client);
50
+ return (async (input, init) => {
51
+ const res = await rawFetchWithPayment(input, init);
52
+ return followRedirects(res);
53
+ });
54
+ })()
55
+ : (paidFetchExternal ??
56
+ (() => {
57
+ throw new Error('createClient: paid calls require a `privateKey` config or an explicit `paidFetch`. Pass an x402-wrapped fetch to make paid calls from the browser.');
58
+ }));
36
59
  /**
37
60
  * Produce an `Authorization: Bearer <msg>||<sig>||<addr>` header signed by
38
- * the wallet's private key. Backend verifies with ethers.recoverAddress and
39
- * rejects messages older than ~10 min.
40
- *
41
- * Exposed as a public helper so agents can sign custom write calls too.
61
+ * the wallet. Backend verifies with ethers.recoverAddress and rejects
62
+ * messages older than ~10 min. Works for both server (privateKey) and
63
+ * browser (walletClient.signMessage) configs.
42
64
  */
43
65
  async function signAuthHeader() {
44
66
  const issuedAt = new Date().toISOString();
45
67
  const nonce = Math.random().toString(36).slice(2) + Date.now().toString(36);
46
- const message = `APINow auth\naddress: ${account.address}\nissuedAt: ${issuedAt}\nnonce: ${nonce}`;
47
- const signature = await account.signMessage({ message });
68
+ const message = `APINow auth\naddress: ${address}\nissuedAt: ${issuedAt}\nnonce: ${nonce}`;
69
+ const signature = await signMessage(message);
48
70
  return {
49
- Authorization: `Bearer ${message}||${signature}||${account.address}`,
50
- 'x-wallet-address': account.address,
71
+ Authorization: `Bearer ${message}||${signature}||${address}`,
72
+ 'x-wallet-address': address,
51
73
  };
52
74
  }
53
75
  /**
@@ -75,7 +97,7 @@ export function createClient(config) {
75
97
  return res.json();
76
98
  }
77
99
  return {
78
- wallet: account.address,
100
+ wallet: address,
79
101
  /**
80
102
  * Produce a signed `Authorization` header for custom write calls.
81
103
  * Pairs with `x-wallet-address`. Backend accepts msg within ~10 min.
@@ -210,7 +232,7 @@ export function createClient(config) {
210
232
  * List workflows you created (convenience for `listWorkflows({ creator: yourWallet })`).
211
233
  */
212
234
  async listMyWorkflows(opts = {}) {
213
- return this.listWorkflows({ ...opts, creator: account.address });
235
+ return this.listWorkflows({ ...opts, creator: address });
214
236
  },
215
237
  // ─── Workflow Versions ───
216
238
  /**
@@ -374,7 +396,7 @@ export function createClient(config) {
374
396
  const res = await fetch(`${baseUrl}/api/ai/generate-ui`, {
375
397
  method: 'POST',
376
398
  headers: { 'Content-Type': 'application/json' },
377
- body: JSON.stringify({ ...opts, walletAddress: account.address }),
399
+ body: JSON.stringify({ ...opts, walletAddress: address }),
378
400
  });
379
401
  if (!res.ok) {
380
402
  const text = await res.text();
@@ -409,7 +431,7 @@ export function createClient(config) {
409
431
  * Check free-tier UI generation eligibility for a wallet.
410
432
  */
411
433
  async checkFreeUI() {
412
- const params = new URLSearchParams({ checkFree: '1', wallet: account.address });
434
+ const params = new URLSearchParams({ checkFree: '1', wallet: address });
413
435
  const res = await fetch(`${baseUrl}/api/ai/generate-ui?${params}`);
414
436
  if (!res.ok)
415
437
  throw new Error(`Failed to check free tier: ${res.status}`);
@@ -419,7 +441,7 @@ export function createClient(config) {
419
441
  * Like, dislike, or comment on a generated UI.
420
442
  */
421
443
  async reactToUI(id, action, comment) {
422
- const body = { id, action, wallet: account.address };
444
+ const body = { id, action, wallet: address };
423
445
  if (comment)
424
446
  body.comment = comment;
425
447
  const res = await fetch(`${baseUrl}/api/ai/generate-ui`, {
@@ -440,7 +462,7 @@ export function createClient(config) {
440
462
  const res = await fetch(`${baseUrl}/api/ai/generate-ui`, {
441
463
  method: 'DELETE',
442
464
  headers: { 'Content-Type': 'application/json' },
443
- body: JSON.stringify({ id, wallet: account.address }),
465
+ body: JSON.stringify({ id, wallet: address }),
444
466
  });
445
467
  if (!res.ok) {
446
468
  const text = await res.text();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apinow-sdk",
3
- "version": "0.26.0",
3
+ "version": "0.27.0",
4
4
  "description": "Pay-per-call API SDK & CLI for APINow.fun — endpoints + workflows, wraps x402 so you don't have to",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",