tickatlas 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/CHANGELOG.md +57 -0
- package/LICENSE +21 -0
- package/README.md +351 -0
- package/dist/index.cjs +795 -0
- package/dist/index.d.cts +865 -0
- package/dist/index.d.ts +865 -0
- package/dist/index.mjs +768 -0
- package/package.json +74 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the `tickatlas` JavaScript/TypeScript SDK are documented
|
|
4
|
+
here. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
|
|
5
|
+
and [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-06-15
|
|
8
|
+
|
|
9
|
+
Initial public release. Built against TickAtlas API `v1` (app `1.0.0`) per the
|
|
10
|
+
authoritative SDK contract (`SPEC.md`).
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `TickAtlas` client class covering all **21** `/v1` endpoints plus the
|
|
15
|
+
`/health` infra probe:
|
|
16
|
+
- Symbols: `getSymbols`, `getSymbol`
|
|
17
|
+
- Quotes: `getQuote`, `getQuotes`
|
|
18
|
+
- History: `getOhlc`, `getTicks`
|
|
19
|
+
- Indicators: `getIndicator`, `getIndicators`, `listIndicators`,
|
|
20
|
+
`getIndicatorHistory`, `getMulti`
|
|
21
|
+
- Screener: `screen`
|
|
22
|
+
- Analytics: `getSummary`, `getSpread`, `compareSpread`, `getSessions`,
|
|
23
|
+
`getHeatmap`, `getCalendar`
|
|
24
|
+
- Account: `getAccount`, `getLayout`, `saveLayout` (write)
|
|
25
|
+
- Infra: `health`
|
|
26
|
+
- Full TypeScript types for every request parameter object and response model.
|
|
27
|
+
- Typed exception hierarchy: `TickAtlasError`, `TickAtlasAPIError`,
|
|
28
|
+
`AuthenticationError`, `PermissionDeniedError`, `NotFoundError`,
|
|
29
|
+
`ValidationError`, `RateLimitError`, `ServerError`, `TickAtlasNetworkError`,
|
|
30
|
+
and `TickAtlasConfigError`, with HTTP-status + `error.code` mapping.
|
|
31
|
+
- `as const` enums/catalogues for autocomplete: `Timeframes`,
|
|
32
|
+
`HeatmapTimeframes`, `SymbolCategories`, `SpreadPeriods`, `CalendarImpacts`,
|
|
33
|
+
`Bias`, `BiasStrengths`, `HeatmapTypes`, `IndicatorCategories`, `Plans`,
|
|
34
|
+
`SortDirections`, the full 42-id `Indicators` catalogue,
|
|
35
|
+
`IndicatorsByCategory`, and `ALL_INDICATORS`. Methods also accept raw strings.
|
|
36
|
+
- Automatic retries for `429`/`5xx`/network errors with exponential backoff and
|
|
37
|
+
full jitter; honours `Retry-After` (then `X-RateLimit-Reset`,
|
|
38
|
+
`reset_in_seconds`) on `429`.
|
|
39
|
+
- Request timeouts via `AbortController` (default 30s); configurable `timeout`,
|
|
40
|
+
`maxRetries`, `backoffBase`, `backoffCap`, and an injectable `fetch`.
|
|
41
|
+
- API-key resolution from an explicit option or `TICKATLAS_API_KEY`; base URL
|
|
42
|
+
from option, `TICKATLAS_BASE_URL`, or the production default. Browser-safe
|
|
43
|
+
`process` guarding; `User-Agent` set on Node only.
|
|
44
|
+
- Zero runtime dependencies (platform `fetch`); dual **ESM + CJS** build with
|
|
45
|
+
`.d.ts` declarations and an `exports` map. Targets Node 18+ and browsers.
|
|
46
|
+
- Unit tests (vitest) with a mocked `fetch` covering success parsing for every
|
|
47
|
+
method, error→exception mapping, and the retry/`Retry-After` behaviour; plus a
|
|
48
|
+
gated, read-only live integration suite.
|
|
49
|
+
|
|
50
|
+
### Notes
|
|
51
|
+
|
|
52
|
+
- The WebSocket quote stream is **not** part of `0.1.0` and is tracked for a
|
|
53
|
+
future release.
|
|
54
|
+
- `saveLayout` (`PUT /monitor/layout`) is the only mutating method and is
|
|
55
|
+
documented as advanced/optional.
|
|
56
|
+
|
|
57
|
+
[0.1.0]: https://github.com/abuzant/tickatlas-sdk/releases/tag/js-v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TickAtlas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# tickatlas
|
|
2
|
+
|
|
3
|
+
Official JavaScript / TypeScript SDK for the [TickAtlas](https://tickatlas.com) market-data API.
|
|
4
|
+
|
|
5
|
+
Real-time quotes, OHLC candles, tick data, **42 technical indicators**, a market screener, currency-strength heatmaps, an economic calendar, and account/quota info — for forex, metals, commodities, indices, crypto, and stocks.
|
|
6
|
+
|
|
7
|
+
- **Zero runtime dependencies.** Uses the platform `fetch` — works in **Node 18+** and modern **browsers**.
|
|
8
|
+
- **Dual package:** ships **ESM**, **CommonJS**, and full **TypeScript declarations**.
|
|
9
|
+
- **Fully typed:** every request parameter and response model, plus a typed exception hierarchy.
|
|
10
|
+
- **Resilient:** automatic retries with exponential backoff + jitter, honouring `Retry-After` on rate limits.
|
|
11
|
+
|
|
12
|
+
> Covers all **21** `/v1` endpoints plus the `/health` probe. The WebSocket quote stream is out of scope for `0.1.0` (tracked for a future release).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install tickatlas
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Requires Node.js **18 or newer** (for the built-in `fetch`/`AbortController`), or any modern browser.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Authentication
|
|
27
|
+
|
|
28
|
+
Authenticate with your API key (sent as the `X-API-Key` header). The key is resolved in this order:
|
|
29
|
+
|
|
30
|
+
1. The explicit `apiKey` constructor option.
|
|
31
|
+
2. The `TICKATLAS_API_KEY` environment variable (Node only).
|
|
32
|
+
|
|
33
|
+
If neither is present, the constructor throws a `TickAtlasConfigError`.
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { TickAtlas } from "tickatlas";
|
|
37
|
+
|
|
38
|
+
// Explicit key
|
|
39
|
+
const client = new TickAtlas({ apiKey: "tk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" });
|
|
40
|
+
|
|
41
|
+
// …or rely on the TICKATLAS_API_KEY env var
|
|
42
|
+
const client2 = new TickAtlas();
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
> **Never** hardcode, log, or commit your API key. Prefer the `TICKATLAS_API_KEY` environment variable. This SDK never writes your key to disk or logs.
|
|
46
|
+
|
|
47
|
+
### Base URL
|
|
48
|
+
|
|
49
|
+
Defaults to `https://tickatlas.com/v1`. Override for staging/self-hosted deployments via the `baseURL` option or the `TICKATLAS_BASE_URL` env var (option wins).
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
const client = new TickAtlas({
|
|
53
|
+
apiKey: process.env.TICKATLAS_API_KEY,
|
|
54
|
+
baseURL: "https://staging.tickatlas.com/v1",
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Client options
|
|
59
|
+
|
|
60
|
+
| Option | Default | Description |
|
|
61
|
+
| ------------- | ----------------------------- | --------------------------------------------- |
|
|
62
|
+
| `apiKey` | `TICKATLAS_API_KEY` env | API key (`X-API-Key` header). |
|
|
63
|
+
| `baseURL` | `https://tickatlas.com/v1` | API base URL (`TICKATLAS_BASE_URL` env). |
|
|
64
|
+
| `timeout` | `30000` | Per-request timeout in ms (`AbortController`). |
|
|
65
|
+
| `maxRetries` | `3` | Retries for 429 / 5xx / network errors. |
|
|
66
|
+
| `backoffBase` | `500` | Exponential-backoff base in ms. |
|
|
67
|
+
| `backoffCap` | `30000` | Maximum backoff delay in ms. |
|
|
68
|
+
| `fetch` | global `fetch` | Custom `fetch` implementation (advanced). |
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Quickstart
|
|
73
|
+
|
|
74
|
+
### TypeScript
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { TickAtlas, Indicators, Timeframes } from "tickatlas";
|
|
78
|
+
|
|
79
|
+
const client = new TickAtlas({ apiKey: process.env.TICKATLAS_API_KEY });
|
|
80
|
+
|
|
81
|
+
// A single real-time quote
|
|
82
|
+
const quote = await client.getQuote("EURUSD");
|
|
83
|
+
console.log(`${quote.symbol}: ${quote.bid} / ${quote.ask} (spread ${quote.spread_pips} pips)`);
|
|
84
|
+
|
|
85
|
+
// RSI(14) on the H1 timeframe
|
|
86
|
+
const rsi = await client.getIndicator("EURUSD", Indicators.RSI_14, {
|
|
87
|
+
timeframe: Timeframes.H1,
|
|
88
|
+
});
|
|
89
|
+
console.log(`RSI: ${rsi.value}`);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### JavaScript (ESM)
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
import { TickAtlas } from "tickatlas";
|
|
96
|
+
|
|
97
|
+
const client = new TickAtlas({ apiKey: process.env.TICKATLAS_API_KEY });
|
|
98
|
+
const quote = await client.getQuote("EURUSD");
|
|
99
|
+
console.log(quote.bid, quote.ask);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### JavaScript (CommonJS)
|
|
103
|
+
|
|
104
|
+
```js
|
|
105
|
+
const { TickAtlas } = require("tickatlas");
|
|
106
|
+
|
|
107
|
+
(async () => {
|
|
108
|
+
const client = new TickAtlas({ apiKey: process.env.TICKATLAS_API_KEY });
|
|
109
|
+
const quote = await client.getQuote("EURUSD");
|
|
110
|
+
console.log(quote.bid, quote.ask);
|
|
111
|
+
})();
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Both the `import` and `require` forms are wired through the package `exports` map, with `.d.ts` types for either entry point.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Enums & constants
|
|
119
|
+
|
|
120
|
+
For autocomplete, the SDK exports `as const` objects. **You can always pass raw strings instead** — these exist purely for convenience.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import {
|
|
124
|
+
Timeframes, // M1 M5 M15 M30 H1 H4 D1
|
|
125
|
+
HeatmapTimeframes, // H1 H4 D1 W1
|
|
126
|
+
Indicators, // all 42 indicator ids
|
|
127
|
+
IndicatorsByCategory,
|
|
128
|
+
ALL_INDICATORS,
|
|
129
|
+
SpreadPeriods, // 1h 24h 7d 30d
|
|
130
|
+
CalendarImpacts, // high medium low
|
|
131
|
+
SymbolCategories, // forex metals commodities indices crypto stocks
|
|
132
|
+
} from "tickatlas";
|
|
133
|
+
|
|
134
|
+
client.getIndicator("EURUSD", Indicators.MACD_hist, { timeframe: Timeframes.H4 });
|
|
135
|
+
client.getIndicator("EURUSD", "MACD_hist", { timeframe: "H4" }); // identical
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Indicator naming gotchas** (the names below are the *correct* ones — common doc typos 404):
|
|
139
|
+
`SAR` (not `Parabolic_SAR`), `Volumes` (not `Tick_Volume`), `WilliamsR_14` (no underscore before `R`), `ADX_plusDI` / `ADX_minusDI`. `EMA` stops at `EMA_50`; `SMA` goes to `SMA_200`. There is no `RSI_9` or `EMA_200`, and only three Ichimoku keys.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Endpoint reference
|
|
144
|
+
|
|
145
|
+
All methods return a `Promise` of the **unwrapped, typed** `data` payload (the `{ success, data }` envelope is handled for you).
|
|
146
|
+
|
|
147
|
+
### Symbols
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
await client.getSymbols({ category: "forex", search: "EUR", offset: 0, limit: 100 });
|
|
151
|
+
await client.getSymbol("EURUSD"); // full contract spec
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Quotes
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
await client.getQuote("EURUSD", { includeSources: true });
|
|
158
|
+
await client.getQuotes(["EURUSD", "GBPUSD", "USDJPY"], ["bid", "ask", "spread_pips"]);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`getQuotes` is a `POST` under the hood (the API's batch endpoint is POST-only); `fields` is optional and defaults to all five.
|
|
162
|
+
|
|
163
|
+
### OHLC & ticks
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
await client.getOhlc("EURUSD", {
|
|
167
|
+
timeframe: "H1",
|
|
168
|
+
from: "2026-05-01T00:00:00Z",
|
|
169
|
+
to: "2026-05-25T00:00:00Z",
|
|
170
|
+
limit: 500,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Ticks require from/to (ISO 8601); the range must be <= 1 hour. Plan: pro/enterprise.
|
|
174
|
+
await client.getTicks("EURUSD", "2026-05-25T13:00:00Z", "2026-05-25T13:30:00Z");
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Indicators
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
await client.getIndicator("EURUSD", "RSI_14", { timeframe: "H1" });
|
|
181
|
+
await client.getIndicators("EURUSD", { timeframe: "H1", category: "oscillator" });
|
|
182
|
+
await client.listIndicators(); // the full catalogue with descriptions
|
|
183
|
+
|
|
184
|
+
// History (plan: starter+)
|
|
185
|
+
await client.getIndicatorHistory("EURUSD", "RSI_14", { timeframe: "H1", limit: 500 });
|
|
186
|
+
|
|
187
|
+
// Batch across symbols (supplying `from` switches to historical mode, plan: starter+)
|
|
188
|
+
await client.getMulti(["EURUSD", "GBPUSD"], ["RSI_14", "ADX"], { timeframe: "H1" });
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Screener
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
// Find oversold symbols by RSI. Note: minVal/maxVal -> min_val/max_val.
|
|
195
|
+
await client.screen("RSI_14", {
|
|
196
|
+
timeframe: "H1",
|
|
197
|
+
maxVal: 30,
|
|
198
|
+
sort: "asc",
|
|
199
|
+
offset: 0,
|
|
200
|
+
limit: 50,
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Summary, spread & sessions
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
await client.getSummary("EURUSD", "H4"); // market-bias summary
|
|
208
|
+
await client.getSpread("EURUSD", "24h"); // spread statistics
|
|
209
|
+
await client.compareSpread(["EURUSD", "GBPUSD"], "24h");
|
|
210
|
+
await client.getSessions(); // market session clock
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Heatmap & calendar
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
await client.getHeatmap({ type: "strength", timeframe: "H4" });
|
|
217
|
+
await client.getHeatmap({ correlations: true }); // correlation matrix
|
|
218
|
+
|
|
219
|
+
await client.getCalendar({
|
|
220
|
+
currencies: ["USD", "EUR"], // string or string[]
|
|
221
|
+
impact: "high",
|
|
222
|
+
nextHours: 24,
|
|
223
|
+
limit: 100,
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Account & layout
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
await client.getAccount(); // { name, plan, prepaid_credits, daily_quota, daily_used }
|
|
231
|
+
await client.getLayout(); // saved dashboard layout (or null)
|
|
232
|
+
|
|
233
|
+
// ADVANCED / WRITE — overwrites the saved dashboard layout for this API key.
|
|
234
|
+
await client.saveLayout([{ widget: "quote", symbol: "EURUSD" }]);
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
> `saveLayout` is the **only** mutating method in the SDK. Use it deliberately.
|
|
238
|
+
|
|
239
|
+
### Health probe
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
await client.health(); // { status, components: { redis, postgres } }
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Error handling
|
|
248
|
+
|
|
249
|
+
Every failure throws a typed error. Catch the base class, or branch on specific subclasses / the stable `code` string.
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
import {
|
|
253
|
+
TickAtlasError,
|
|
254
|
+
TickAtlasAPIError,
|
|
255
|
+
AuthenticationError,
|
|
256
|
+
PermissionDeniedError,
|
|
257
|
+
NotFoundError,
|
|
258
|
+
ValidationError,
|
|
259
|
+
RateLimitError,
|
|
260
|
+
ServerError,
|
|
261
|
+
TickAtlasNetworkError,
|
|
262
|
+
} from "tickatlas";
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
const quote = await client.getQuote("NOPE");
|
|
266
|
+
} catch (e) {
|
|
267
|
+
if (e instanceof NotFoundError) {
|
|
268
|
+
console.error("Symbol not found:", e.code); // SYMBOL_NOT_FOUND
|
|
269
|
+
} else if (e instanceof RateLimitError) {
|
|
270
|
+
console.error(`Rate limited; retry after ${e.retryAfter}s`);
|
|
271
|
+
} else if (e instanceof TickAtlasAPIError) {
|
|
272
|
+
console.error(`API error ${e.statusCode} (${e.code}): ${e.message}`);
|
|
273
|
+
console.error("request id:", e.requestId);
|
|
274
|
+
console.error("context:", e.raw); // raw error object — read extra fields here
|
|
275
|
+
} else if (e instanceof TickAtlasNetworkError) {
|
|
276
|
+
console.error("Network/timeout failure:", e.isTimeout ? "timeout" : "connection");
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Exception hierarchy
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
TickAtlasError base for everything
|
|
285
|
+
├── TickAtlasAPIError server returned a structured error
|
|
286
|
+
│ │ .statusCode .code .message .details .requestId .raw
|
|
287
|
+
│ ├── AuthenticationError HTTP 401 (MISSING_API_KEY, INVALID_API_KEY)
|
|
288
|
+
│ ├── PermissionDeniedError HTTP 403 (API_KEY_DISABLED, PLAN_UPGRADE_REQUIRED, …)
|
|
289
|
+
│ ├── NotFoundError HTTP 404 (SYMBOL_NOT_FOUND, DATA_NOT_FOUND, INDICATOR_NOT_FOUND)
|
|
290
|
+
│ ├── ValidationError HTTP 400 & 422 (INVALID_*, RANGE_TOO_LARGE, VALIDATION_ERROR, …)
|
|
291
|
+
│ ├── RateLimitError HTTP 429 (RATE_LIMIT_EXCEEDED, QUOTA_EXCEEDED) — has .retryAfter
|
|
292
|
+
│ └── ServerError HTTP 5xx (INTERNAL_ERROR, SERVICE_UNAVAILABLE)
|
|
293
|
+
└── TickAtlasNetworkError no HTTP response (connection / timeout / DNS) — has .isTimeout
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
`TickAtlasConfigError` (also extends `TickAtlasError`) is thrown at construction time for misconfiguration, e.g. a missing API key.
|
|
297
|
+
|
|
298
|
+
The `.raw` property exposes the full server `error` object, so you can read forward-compatible context fields (`valid_timeframes`, `required_plan`, `retention_period`, …) that aren't first-class properties.
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Retries & rate limiting
|
|
303
|
+
|
|
304
|
+
By default the client makes up to **4 attempts** (1 + `maxRetries`) and retries **only** on:
|
|
305
|
+
|
|
306
|
+
- `429` (rate limit / quota),
|
|
307
|
+
- `5xx` (server errors), and
|
|
308
|
+
- network / timeout errors.
|
|
309
|
+
|
|
310
|
+
All other errors fail fast. Backoff is **exponential with full jitter** (`base * 2^attempt`, capped at `backoffCap`). On `429`, the client honours the server's **`Retry-After`** header (falling back to `X-RateLimit-Reset`, then the body's `reset_in_seconds`) instead of the computed backoff. All `/v1` endpoints are read-only/idempotent (except the explicit `saveLayout` write), so retries are safe.
|
|
311
|
+
|
|
312
|
+
Tune the behaviour per client:
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
const client = new TickAtlas({
|
|
316
|
+
apiKey: process.env.TICKATLAS_API_KEY,
|
|
317
|
+
timeout: 10_000,
|
|
318
|
+
maxRetries: 5,
|
|
319
|
+
backoffBase: 250,
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Each response also carries `X-RateLimit-Limit` / `-Remaining` / `-Reset` and an `X-Request-ID` (echoed on `TickAtlasAPIError.requestId`).
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Contributing
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
git clone https://github.com/abuzant/tickatlas-sdk.git
|
|
331
|
+
cd tickatlas-sdk/javascript
|
|
332
|
+
|
|
333
|
+
npm install
|
|
334
|
+
npm run build # tsup -> dist/ (ESM .mjs + CJS .cjs + .d.ts)
|
|
335
|
+
npm run typecheck # tsc --noEmit
|
|
336
|
+
npm test # vitest (unit tests, fully mocked — no network)
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
The unit suite mocks `fetch` and never touches the network. There is a separate, **read-only** integration suite that is **skipped** unless both `RUN_INTEGRATION=1` and `TICKATLAS_API_KEY` are set:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
RUN_INTEGRATION=1 TICKATLAS_API_KEY=tk_xxx npm run test:integration
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
It never exercises the write endpoint (`saveLayout`). Please don't commit API keys.
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## License
|
|
350
|
+
|
|
351
|
+
[MIT](./LICENSE) © TickAtlas
|