apistack-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/index.d.ts +31 -0
- package/index.js +71 -0
- package/package.json +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# apistack-sdk
|
|
2
|
+
|
|
3
|
+
Official JavaScript client for [APIStack](https://apistack.online): 100+ production APIs (email and phone validation, business days and holidays, loan and mortgage calculators, DNS/SSL/WHOIS, reference data, AI text tools) behind one API key. Free plan: 1,000 calls/month.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install apistack-sdk
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
import { APIStack } from 'apistack-sdk'
|
|
11
|
+
|
|
12
|
+
const apistack = new APIStack() // reads APISTACK_API_KEY
|
|
13
|
+
|
|
14
|
+
const email = await apistack.post('/api/utilities/email-address-validator/v1', { email: 'jane.doe@gmial.com' })
|
|
15
|
+
console.log(email.data.isValid, email.data.typoSuggestion) // false { suggestion: 'gmail.com', ... }
|
|
16
|
+
|
|
17
|
+
const loan = await apistack.get('/api/finance/loan-calculator/v1/payment', { principal: 350000, rate: 6.5, term: 30 })
|
|
18
|
+
console.log(loan.paymentCalculation.monthlyPayment) // 2212.24
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Every API's path, parameters and a live tester are in the [catalog](https://apistack.online/tools).
|
|
22
|
+
Errors throw `APIStackError` with `status`, `code` and the response `body`. 429 and 5xx responses are retried with backoff (`maxRetries`, default 2).
|
|
23
|
+
|
|
24
|
+
**AI agents:** you don't need this package. Connect the MCP server at `https://apistack.online/api/mcp/connect` instead ([setup](https://apistack.online/mcp)).
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface APIStackOptions {
|
|
2
|
+
/** Defaults to process.env.APISTACK_API_KEY */
|
|
3
|
+
apiKey?: string
|
|
4
|
+
/** Defaults to https://apistack.online */
|
|
5
|
+
baseUrl?: string
|
|
6
|
+
/** Per-request timeout, default 30000 */
|
|
7
|
+
timeoutMs?: number
|
|
8
|
+
/** Retries for network errors, 429 and 5xx; default 2 */
|
|
9
|
+
maxRetries?: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface RequestOptions {
|
|
13
|
+
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
|
|
14
|
+
body?: unknown
|
|
15
|
+
query?: Record<string, string | number | boolean | null | undefined>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export declare class APIStackError extends Error {
|
|
19
|
+
status?: number
|
|
20
|
+
code?: string
|
|
21
|
+
body?: unknown
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export declare class APIStack {
|
|
25
|
+
constructor(options?: APIStackOptions)
|
|
26
|
+
request<T = any>(path: string, options?: RequestOptions): Promise<T>
|
|
27
|
+
get<T = any>(path: string, query?: RequestOptions['query']): Promise<T>
|
|
28
|
+
post<T = any>(path: string, body?: unknown): Promise<T>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default APIStack
|
package/index.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const DEFAULT_BASE_URL = 'https://apistack.online'
|
|
2
|
+
|
|
3
|
+
export class APIStackError extends Error {
|
|
4
|
+
constructor(message, { status, code, body } = {}) {
|
|
5
|
+
super(message)
|
|
6
|
+
this.name = 'APIStackError'
|
|
7
|
+
this.status = status
|
|
8
|
+
this.code = code
|
|
9
|
+
this.body = body
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms))
|
|
14
|
+
|
|
15
|
+
export class APIStack {
|
|
16
|
+
/**
|
|
17
|
+
* @param {{ apiKey?: string, baseUrl?: string, timeoutMs?: number, maxRetries?: number }} [options]
|
|
18
|
+
*/
|
|
19
|
+
constructor({ apiKey = globalThis.process?.env?.APISTACK_API_KEY, baseUrl = DEFAULT_BASE_URL, timeoutMs = 30000, maxRetries = 2 } = {}) {
|
|
20
|
+
if (!apiKey) throw new APIStackError('Missing API key: pass { apiKey } or set APISTACK_API_KEY')
|
|
21
|
+
this.apiKey = apiKey
|
|
22
|
+
this.baseUrl = baseUrl.replace(/\/$/, '')
|
|
23
|
+
this.timeoutMs = timeoutMs
|
|
24
|
+
this.maxRetries = maxRetries
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Call any APIStack endpoint, e.g. request('/api/utilities/base64/v1', { body: { operation: 'encode', text: 'hi' } }).
|
|
29
|
+
* Defaults to POST when a body is given, GET otherwise. Retries 429 and 5xx responses with backoff.
|
|
30
|
+
*/
|
|
31
|
+
async request(path, { method, body, query } = {}) {
|
|
32
|
+
const url = new URL(path.startsWith('/') ? path : `/${path}`, this.baseUrl)
|
|
33
|
+
for (const [key, value] of Object.entries(query || {})) {
|
|
34
|
+
if (value !== undefined && value !== null) url.searchParams.set(key, String(value))
|
|
35
|
+
}
|
|
36
|
+
const verb = (method || (body === undefined ? 'GET' : 'POST')).toUpperCase()
|
|
37
|
+
|
|
38
|
+
for (let attempt = 0; ; attempt++) {
|
|
39
|
+
let response
|
|
40
|
+
try {
|
|
41
|
+
response = await fetch(url, {
|
|
42
|
+
method: verb,
|
|
43
|
+
headers: { 'x-api-key': this.apiKey, ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}) },
|
|
44
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
45
|
+
signal: AbortSignal.timeout(this.timeoutMs)
|
|
46
|
+
})
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (attempt < this.maxRetries) { await sleep(500 * 2 ** attempt); continue }
|
|
49
|
+
throw new APIStackError(`Request failed: ${error.message}`)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const text = await response.text()
|
|
53
|
+
let data
|
|
54
|
+
try { data = text ? JSON.parse(text) : null } catch { data = text }
|
|
55
|
+
|
|
56
|
+
if (response.ok) return data
|
|
57
|
+
if ((response.status === 429 || response.status >= 500) && attempt < this.maxRetries) {
|
|
58
|
+
const retryAfter = Number(response.headers.get('retry-after'))
|
|
59
|
+
await sleep(retryAfter > 0 ? retryAfter * 1000 : 500 * 2 ** attempt)
|
|
60
|
+
continue
|
|
61
|
+
}
|
|
62
|
+
const message = (data && (data.message || (typeof data.error === 'string' ? data.error : data.error?.message))) || `HTTP ${response.status}`
|
|
63
|
+
throw new APIStackError(message, { status: response.status, code: data?.code || data?.error?.code, body: data })
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get(path, query) { return this.request(path, { method: 'GET', query }) }
|
|
68
|
+
post(path, body) { return this.request(path, { method: 'POST', body }) }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export default APIStack
|
package/package.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "apistack-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official client for APIStack: 100+ developer APIs (validation, dates, finance, web/DNS/SSL, reference data, AI text) behind one key",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./index.js",
|
|
7
|
+
"types": "./index.d.ts",
|
|
8
|
+
"exports": { ".": { "types": "./index.d.ts", "default": "./index.js" } },
|
|
9
|
+
"files": ["index.js", "index.d.ts", "README.md"],
|
|
10
|
+
"engines": { "node": ">=18" },
|
|
11
|
+
"keywords": ["api", "apistack", "mcp", "ai-agents", "validation", "business-days", "finance"],
|
|
12
|
+
"homepage": "https://apistack.online/docs",
|
|
13
|
+
"license": "MIT"
|
|
14
|
+
}
|