@kkkermit/trading212.js 0.0.0-stage → 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 +7 -0
- package/LICENSE +21 -0
- package/README.md +290 -2
- package/package.json +134 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @kkkermit/trading212.js
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- dcfed11: First release: a typed client for every Trading 212 Public API endpoint, with a live-trading switch, safe errors with hints, rate limiting, pagination, a fake Trading 212 for tests and a `doctor` command.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kkkermit
|
|
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
CHANGED
|
@@ -1,3 +1,291 @@
|
|
|
1
|
-
|
|
1
|
+
<h1><img src="docs/public/logo.svg" alt="trading212.js" height="64"></h1>
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/Kkkermit/Trading212.js/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@kkkermit/trading212.js)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
A TypeScript client for the [Trading 212 Public API](https://docs.trading212.com/api) that is safe around real
|
|
9
|
+
money, tells you how to fix what went wrong, and comes with a fake Trading 212 to test your code against.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { Trading212 } from "@kkkermit/trading212.js";
|
|
13
|
+
|
|
14
|
+
const t212 = new Trading212({ environment: "demo", apiKey, apiSecret });
|
|
15
|
+
|
|
16
|
+
const { totalValue, holdings } = await t212.portfolio.snapshot();
|
|
17
|
+
const apple = await t212.instruments.resolve("Apple");
|
|
18
|
+
const order = await t212.orders.buy({ ticker: apple.ticker, quantity: 0.5 });
|
|
19
|
+
await t212.orders.waitFor(order); // FILLED
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
> [!WARNING]
|
|
23
|
+
> **Unofficial.** Not affiliated with or endorsed by Trading 212. The API is in beta and can change. Live trading
|
|
24
|
+
> uses real money: test on demo first, and read [Safety](#safety-around-real-money).
|
|
25
|
+
|
|
26
|
+
## Why this one
|
|
27
|
+
|
|
28
|
+
- **A live client cannot trade by accident.** It only reads until you pass `trading: "enabled"`, and so does any
|
|
29
|
+
client pointed at a custom `baseUrl`, because a proxy could forward to live. Orders are never
|
|
30
|
+
retried, a request that may or may not have executed throws `OrderOutcomeUnknownError` rather than a plain
|
|
31
|
+
failure, and `{ dryRun: true }` shows the exact request without sending it.
|
|
32
|
+
- **Errors tell you what to do.** Every error is a named class with a `hint` in plain English. A 403 names the
|
|
33
|
+
permission your key lacks. A 401 explains that demo keys do not work on live. An order that is too small says
|
|
34
|
+
so, and one selling more than you hold points you at the shares locked in pies.
|
|
35
|
+
- **Your key stays secret.** Credentials are redacted from every log line, error, hook event and test recording,
|
|
36
|
+
and a test suite proves it by echoing them back from a hostile server. Redirects are refused, pagination links
|
|
37
|
+
are pinned to Trading 212's host, and signed download links never receive your key.
|
|
38
|
+
- **Rate limits are handled.** Every endpoint has its own budget, generated from the official spec, corrected from
|
|
39
|
+
the response headers, and shared by every client using the same key in your process. Calls are paced the way
|
|
40
|
+
Trading 212 recommends, so you should not see a 429.
|
|
41
|
+
- **Common tasks take one call.** Turn "Apple" into `AAPL_US_EQ`, sell a whole position without the
|
|
42
|
+
4-decimal-place error, wait for an order to fill, export a year of history as CSV in one call, check whether a
|
|
43
|
+
market is open, and get your portfolio's weights and profit in one call.
|
|
44
|
+
- **Test without the network.** `createFakeTrading212()` gives you the real client talking to an in-memory Trading
|
|
45
|
+
212 that fills orders, tracks cash and positions, paginates history, and fails on demand.
|
|
46
|
+
- **`npx @kkkermit/trading212.js doctor`** checks your key, environment and every permission in one go.
|
|
47
|
+
- **Small and modern.** Zero runtime dependencies, about 14 kB minified and compressed, ESM and CommonJS, full types.
|
|
48
|
+
Works on Node 22+, Bun and Deno.
|
|
49
|
+
|
|
50
|
+
### How it compares
|
|
51
|
+
|
|
52
|
+
There are several community clients for this API on npm, all young. When this library was written (November
|
|
53
|
+
2026), none of the ones reviewed shipped a fake server for tests, a command-line check, or errors that name the
|
|
54
|
+
missing permission and say how to fix it. Several have runtime dependencies. Compare for yourself:
|
|
55
|
+
`trading212-api`, `t212-sdk`, `@mingchuno/trading212-client` and `@azaini/t212-sdk` are the main ones.
|
|
56
|
+
|
|
57
|
+
## Install
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
npm install @kkkermit/trading212.js
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Node 22 or later, Bun or Deno. Server-side only: Trading 212 refuses requests from web pages, and a key in a page is
|
|
64
|
+
public, so the client refuses to start in a browser.
|
|
65
|
+
|
|
66
|
+
New to it? [Getting started](https://kkkermit.github.io/Trading212.js/getting-started/) goes from install to a working script step by step,
|
|
67
|
+
starting with a try-out that needs no key. The [examples](examples) are complete programs.
|
|
68
|
+
|
|
69
|
+
## Get a key
|
|
70
|
+
|
|
71
|
+
In the Trading 212 app, go to **Settings > API (Beta)** and create a key. You will see the secret **once**, so save
|
|
72
|
+
it straight into your secret manager.
|
|
73
|
+
|
|
74
|
+
- **A key works in one environment only.** Make a demo key while the app is in practice mode, and a separate one
|
|
75
|
+
for live.
|
|
76
|
+
- **Tick only the permissions you need.** A dashboard needs no `orders:execute`.
|
|
77
|
+
- **Restrict the key to your server's IP address** if it runs somewhere fixed.
|
|
78
|
+
- Only **Invest** and **Stocks ISA** accounts can use the API.
|
|
79
|
+
|
|
80
|
+
Then check it:
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
T212_ENV=demo T212_API_KEY=... T212_API_SECRET=... npx @kkkermit/trading212.js doctor
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The output looks like this:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
✓ settings: environment demo, key 37 characters, secret 43 characters
|
|
90
|
+
✓ sign in: account 12345678 (GBP) on demo
|
|
91
|
+
✓ portfolio: allowed
|
|
92
|
+
✗ history:dividends: not on this key (create one with "history:dividends" ticked)
|
|
93
|
+
· exports: live only
|
|
94
|
+
· orders:execute: not checked: it would need a real order
|
|
95
|
+
✓ trading: orders can be placed on demo
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Quick start
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { Trading212 } from "@kkkermit/trading212.js";
|
|
102
|
+
|
|
103
|
+
// Reads T212_ENV, T212_API_KEY and T212_API_SECRET. There is no default environment, on purpose.
|
|
104
|
+
const t212 = Trading212.fromEnv();
|
|
105
|
+
|
|
106
|
+
const me = await t212.verify(); // { environment, accountId, currency, trading }
|
|
107
|
+
const positions = await t212.positions.list();
|
|
108
|
+
|
|
109
|
+
for await (const dividend of t212.history.dividends.all()) {
|
|
110
|
+
console.log(dividend.paidOn, dividend.ticker, dividend.amount);
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## What it covers
|
|
115
|
+
|
|
116
|
+
Every one of the 22 operations in Trading 212's Public API, on both of its environments. A test fails the build if
|
|
117
|
+
the official spec gains an operation this library does not implement.
|
|
118
|
+
|
|
119
|
+
| Environment | Host | What it is |
|
|
120
|
+
| ----------- | ----------------------------- | -------------------------------------------------------- |
|
|
121
|
+
| `demo` | `https://demo.trading212.com` | Paper trading with practice money. Trading is on. |
|
|
122
|
+
| `live` | `https://live.trading212.com` | Your real account ("prod"). No trading until you opt in. |
|
|
123
|
+
|
|
124
|
+
There is no third environment: "production" and "real" mean `live`, and "paper", "practice" and "sandbox" mean
|
|
125
|
+
`demo`. The client asks you to name one of the two and never guesses.
|
|
126
|
+
|
|
127
|
+
| Method | Endpoint | Permission | Limit |
|
|
128
|
+
| -------------------------------------------------- | ---------------------------------- | ---------------------- | -------- |
|
|
129
|
+
| `account.summary()` | `GET /equity/account/summary` | `account` | 1 / 5 s |
|
|
130
|
+
| `positions.list()`, `positions.get()` | `GET /equity/positions` | `portfolio` | 1 / 1 s |
|
|
131
|
+
| `instruments.list()`, `search()`, `resolve()` | `GET /equity/metadata/instruments` | `metadata` | 1 / 50 s |
|
|
132
|
+
| `exchanges.list()`, `exchanges.status()` | `GET /equity/metadata/exchanges` | `metadata` | 1 / 30 s |
|
|
133
|
+
| `orders.list()` | `GET /equity/orders` | `orders:read` | 1 / 5 s |
|
|
134
|
+
| `orders.get()`, `orders.waitFor()`¹ | `GET /equity/orders/{id}` | `orders:read` | 1 / 1 s |
|
|
135
|
+
| `orders.cancel()` | `DELETE /equity/orders/{id}` | `orders:execute` | 50 / min |
|
|
136
|
+
| `orders.market()`, `buy()`, `sell()`, `sellAll()`² | `POST /equity/orders/market` | `orders:execute` | 50 / min |
|
|
137
|
+
| `orders.limit()` | `POST /equity/orders/limit` | `orders:execute` | 1 / 2 s |
|
|
138
|
+
| `orders.stop()` | `POST /equity/orders/stop` | `orders:execute` | 1 / 2 s |
|
|
139
|
+
| `orders.stopLimit()` | `POST /equity/orders/stop_limit` | `orders:execute` | 1 / 2 s |
|
|
140
|
+
| `history.orders.list()`, `.all()` | `GET /equity/history/orders` | `history:orders` | 20 / min |
|
|
141
|
+
| `history.dividends.list()`, `.all()` | `GET /equity/history/dividends` | `history:dividends` | 20 / min |
|
|
142
|
+
| `history.transactions.list()`, `.all()` | `GET /equity/history/transactions` | `history:transactions` | 20 / min |
|
|
143
|
+
| `reports.list()`, `reports.waitFor()` | `GET /equity/history/exports` | not stated in the spec | 1 / min |
|
|
144
|
+
| `reports.request()`, `reports.export()` | `POST /equity/history/exports` | not stated in the spec | 1 / 30 s |
|
|
145
|
+
| `pies.list()` | `GET /equity/pies` | `pies:read` | 1 / 30 s |
|
|
146
|
+
| `pies.get()` | `GET /equity/pies/{id}` | `pies:read` | 1 / 5 s |
|
|
147
|
+
| `pies.create()` | `POST /equity/pies` | `pies:write` | 1 / 5 s |
|
|
148
|
+
| `pies.update()` | `POST /equity/pies/{id}` | `pies:write` | 1 / 5 s |
|
|
149
|
+
| `pies.duplicate()` | `POST /equity/pies/{id}/duplicate` | `pies:write` | 1 / 5 s |
|
|
150
|
+
| `pies.delete()` | `DELETE /equity/pies/{id}` | `pies:write` | 1 / 5 s |
|
|
151
|
+
|
|
152
|
+
¹ Also needs `history:orders`, to find the order once it has left the pending list. ² `sellAll()` also needs
|
|
153
|
+
`portfolio`, to read the position.
|
|
154
|
+
|
|
155
|
+
Paths are under `/api/v0`. `portfolio.snapshot()` combines the account summary and positions. CSV exports are
|
|
156
|
+
live only: demo refuses them, as the contract tests confirm. Trading 212 has deprecated the pie
|
|
157
|
+
endpoints, which still work. The exported `ENDPOINTS` table holds the same facts at run time. See the
|
|
158
|
+
[documentation](#documentation) for each part.
|
|
159
|
+
|
|
160
|
+
## Safety around real money
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
// A live client reads, but refuses every order before anything is sent.
|
|
164
|
+
const reader = new Trading212({ environment: "live", apiKey, apiSecret });
|
|
165
|
+
await reader.orders.buy({ ticker: "AAPL_US_EQ", quantity: 1 }); // throws TradingDisabledError
|
|
166
|
+
|
|
167
|
+
// Preview exactly what would be sent, on any client.
|
|
168
|
+
const preview = await reader.orders.buy({ ticker: "AAPL_US_EQ", quantity: 1 }, { dryRun: true });
|
|
169
|
+
// { dryRun: true, url: "https://live.trading212.com/api/v0/equity/orders/market", body: {...}, wouldSend: false }
|
|
170
|
+
|
|
171
|
+
// Trading on live is a deliberate choice.
|
|
172
|
+
const trader = new Trading212({ environment: "live", apiKey, apiSecret, trading: "enabled" });
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
- **Orders are never retried.** Reads are, with backoff.
|
|
176
|
+
- **If an order may have executed** (a timeout, a dropped connection, a 5xx), you get `OrderOutcomeUnknownError`.
|
|
177
|
+
Check `orders.list()` and `history.orders.list()` before trying again. If the connection never opened (DNS failure,
|
|
178
|
+
connection refused), you get a `NetworkError` with `sent: false` instead, and it is safe to retry.
|
|
179
|
+
- **`buy()` and `sell()` take a positive quantity** and set the sign themselves, so a stray minus sign cannot turn a
|
|
180
|
+
sale into a purchase. The low-level `market()`, `limit()`, `stop()` and `stopLimit()` follow the API's
|
|
181
|
+
convention, where a negative quantity sells.
|
|
182
|
+
- **Orders are checked before sending:** a ticker without spaces, at most 4 decimal places, a positive price,
|
|
183
|
+
`timeValidity` stated, and `extendedHours` on market orders only. Every problem is reported at once.
|
|
184
|
+
|
|
185
|
+
## Errors
|
|
186
|
+
|
|
187
|
+
Every error extends `Trading212Error`, with `code`, `hint`, `status`, `request`, `rateLimit`, the redacted `body`
|
|
188
|
+
and Trading 212's own `apiCode`. `instanceof` works even if two copies of the package are loaded.
|
|
189
|
+
|
|
190
|
+
| Error | When |
|
|
191
|
+
| -------------------------- | ------------------------------------------------------------- |
|
|
192
|
+
| `ConfigurationError` | Bad options or environment variables. Nothing was sent |
|
|
193
|
+
| `AuthenticationError` | 401: wrong key or secret, or a key from the other environment |
|
|
194
|
+
| `MissingScopeError` | 403: the key lacks `error.scope`, such as `orders:execute` |
|
|
195
|
+
| `NotAvailableInDemoError` | 403: live-only features, such as CSV exports |
|
|
196
|
+
| `PermissionError` | Any other 403, such as an IP restriction |
|
|
197
|
+
| `ValidationError` | Invalid request, before sending (`error.issues`) or a 400 |
|
|
198
|
+
| `OrderRejectedError` | A refused order, with `error.reason` |
|
|
199
|
+
| `NotFoundError` | 404 |
|
|
200
|
+
| `InstrumentNotFoundError` | `resolve()` found none or several, with `error.suggestions` |
|
|
201
|
+
| `RateLimitError` | 429, with `retryAfterMs` and `resetAt` |
|
|
202
|
+
| `TimeoutError` | 408, or no answer within `timeoutMs` |
|
|
203
|
+
| `OrderOutcomeUnknownError` | An order may or may not have executed |
|
|
204
|
+
| `TradingDisabledError` | An order on live without `trading: "enabled"` |
|
|
205
|
+
| `NetworkError` | The connection failed; `sent` says whether it left |
|
|
206
|
+
| `ServerError` | 5xx |
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
import { isTrading212Error, MissingScopeError } from "@kkkermit/trading212.js";
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
await t212.orders.sellAll("AAPL_US_EQ");
|
|
213
|
+
} catch (error) {
|
|
214
|
+
if (error instanceof MissingScopeError) console.error(`Missing ${error.scope}: ${error.hint}`);
|
|
215
|
+
else if (isTrading212Error(error))
|
|
216
|
+
logger.error(error.message, error.toLog()); // safe to log as-is
|
|
217
|
+
else throw error;
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Logging and hooks
|
|
222
|
+
|
|
223
|
+
The client is silent by default. Give it a logger and it writes one line per event: every order at `info`, every
|
|
224
|
+
read at `debug`, and retries, long rate-limit waits and orders with an unknown outcome at `warn`. Every field is
|
|
225
|
+
redacted first.
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
import { consoleLogger, fieldsFirst } from "@kkkermit/trading212.js";
|
|
229
|
+
|
|
230
|
+
new Trading212({ ...options, logger: consoleLogger({ level: "info" }) });
|
|
231
|
+
// [trading212] INFO POST /api/v0/equity/orders/market returned 200 in 212 ms endpoint=placeMarketOrder status=200 …
|
|
232
|
+
new Trading212({ ...options, logger: fieldsFirst(pino()) }); // pino and bunyan take (fields, message)
|
|
233
|
+
new Trading212({
|
|
234
|
+
...options,
|
|
235
|
+
hooks: { onResponse: ({ endpoint, status, durationMs }) => metrics.observe(endpoint, durationMs) },
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Testing your code
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import { createFakeTrading212 } from "@kkkermit/trading212.js/testing";
|
|
243
|
+
|
|
244
|
+
const { client, server } = createFakeTrading212({
|
|
245
|
+
state: { cash: 1000, positions: [{ ticker: "AAPL_US_EQ", quantity: 2 }] },
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
await client.orders.sell({ ticker: "AAPL_US_EQ", quantity: 1 });
|
|
249
|
+
expect(server.position("AAPL_US_EQ")?.quantity).toBe(1);
|
|
250
|
+
|
|
251
|
+
server.marketOpen = false; // the next order is refused with market-closed
|
|
252
|
+
server.failNext("getAccountSummary", { status: 503 }); // or { network: "ECONNRESET" }
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
`scriptedFetch()` is there too, for testing at the HTTP level.
|
|
256
|
+
|
|
257
|
+
## Documentation
|
|
258
|
+
|
|
259
|
+
The full documentation is at **[kkkermit.github.io/Trading212.js](https://kkkermit.github.io/Trading212.js/)**. Its source is the MDX in
|
|
260
|
+
[`docs/src/content/docs`](docs/src/content/docs).
|
|
261
|
+
|
|
262
|
+
- [Getting started](https://kkkermit.github.io/Trading212.js/getting-started/): install, keys, the doctor and a first script
|
|
263
|
+
- [Key concepts](https://kkkermit.github.io/Trading212.js/concepts/) and [your first program](https://kkkermit.github.io/Trading212.js/tutorial/), for beginners
|
|
264
|
+
- [Recipes](https://kkkermit.github.io/Trading212.js/recipes/): complete programs for common tasks, in TypeScript and JavaScript
|
|
265
|
+
- [API coverage](https://kkkermit.github.io/Trading212.js/reference/api-coverage/): every endpoint, its method, permission and limit
|
|
266
|
+
- [Orders](https://kkkermit.github.io/Trading212.js/guides/orders/): order types, quantities, `sellAll`, `waitFor`, dry runs
|
|
267
|
+
- [Instruments and market hours](https://kkkermit.github.io/Trading212.js/guides/instruments-and-markets/), [history](https://kkkermit.github.io/Trading212.js/guides/history/),
|
|
268
|
+
[CSV reports](https://kkkermit.github.io/Trading212.js/guides/reports/) and the [portfolio](https://kkkermit.github.io/Trading212.js/guides/account-and-portfolio/)
|
|
269
|
+
- [Errors](https://kkkermit.github.io/Trading212.js/guides/errors/): every error, what causes it and how to fix it
|
|
270
|
+
- [Rate limits](https://kkkermit.github.io/Trading212.js/guides/rate-limits/), [logging and hooks](https://kkkermit.github.io/Trading212.js/guides/logging/) and
|
|
271
|
+
[configuration](https://kkkermit.github.io/Trading212.js/reference/configuration/)
|
|
272
|
+
- [Testing your code](https://kkkermit.github.io/Trading212.js/guides/testing/): the fake server and scripted fetch
|
|
273
|
+
- [Safety and security](https://kkkermit.github.io/Trading212.js/guides/safety/)
|
|
274
|
+
- The [reference](https://kkkermit.github.io/Trading212.js/reference/client/): every method, option, helper, error and type
|
|
275
|
+
- [FAQ and troubleshooting](https://kkkermit.github.io/Trading212.js/help/faq/)
|
|
276
|
+
|
|
277
|
+
## Status
|
|
278
|
+
|
|
279
|
+
Version 0.x while the API is in beta. Types and endpoint metadata are generated from Trading 212's OpenAPI spec, and
|
|
280
|
+
a weekly job checks for changes. The spec does not document error bodies, so the ones demo really sends are recorded in
|
|
281
|
+
`fixtures/errors.json` and replayed by the tests; the few refusals not seen there yet are handled defensively. The
|
|
282
|
+
contract tests in `tests/contract` check the rest against demo when run with a demo key.
|
|
283
|
+
|
|
284
|
+
## Contributing and security
|
|
285
|
+
|
|
286
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) and [AGENTS.md](AGENTS.md), and follow the [code of conduct](CODE_OF_CONDUCT.md).
|
|
287
|
+
Report vulnerabilities privately as described in [SECURITY.md](SECURITY.md).
|
|
288
|
+
|
|
289
|
+
## Licence
|
|
290
|
+
|
|
291
|
+
[MIT](LICENSE). "Trading 212" is a trademark of its owner, used here only to say what this library talks to.
|
package/package.json
CHANGED
|
@@ -1,6 +1,135 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@kkkermit/trading212.js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Unofficial, zero-dependency TypeScript client for the Trading 212 Public API: typed, rate-limit aware, safe around live money, with errors that tell you how to fix them.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"trading212",
|
|
7
|
+
"trading 212",
|
|
8
|
+
"t212",
|
|
9
|
+
"stocks",
|
|
10
|
+
"isa",
|
|
11
|
+
"investing",
|
|
12
|
+
"trading",
|
|
13
|
+
"api",
|
|
14
|
+
"sdk",
|
|
15
|
+
"client",
|
|
16
|
+
"typescript"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "kkkermit",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/Kkkermit/Trading212.js.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/Kkkermit/Trading212.js/issues"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/Kkkermit/Trading212.js#readme",
|
|
28
|
+
"type": "module",
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=22"
|
|
32
|
+
},
|
|
33
|
+
"main": "./dist/index.cjs",
|
|
34
|
+
"module": "./dist/index.js",
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"import": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"default": "./dist/index.js"
|
|
41
|
+
},
|
|
42
|
+
"require": {
|
|
43
|
+
"types": "./dist/index.d.cts",
|
|
44
|
+
"default": "./dist/index.cjs"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"./testing": {
|
|
48
|
+
"import": {
|
|
49
|
+
"types": "./dist/testing.d.ts",
|
|
50
|
+
"default": "./dist/testing.js"
|
|
51
|
+
},
|
|
52
|
+
"require": {
|
|
53
|
+
"types": "./dist/testing.d.cts",
|
|
54
|
+
"default": "./dist/testing.cjs"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"./csv": {
|
|
58
|
+
"import": {
|
|
59
|
+
"types": "./dist/csv.d.ts",
|
|
60
|
+
"default": "./dist/csv.js"
|
|
61
|
+
},
|
|
62
|
+
"require": {
|
|
63
|
+
"types": "./dist/csv.d.cts",
|
|
64
|
+
"default": "./dist/csv.cjs"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"./package.json": "./package.json"
|
|
68
|
+
},
|
|
69
|
+
"bin": {
|
|
70
|
+
"trading212": "./dist/cli.js"
|
|
71
|
+
},
|
|
72
|
+
"files": [
|
|
73
|
+
"dist",
|
|
74
|
+
"README.md",
|
|
75
|
+
"LICENSE",
|
|
76
|
+
"CHANGELOG.md"
|
|
77
|
+
],
|
|
78
|
+
"publishConfig": {
|
|
79
|
+
"access": "public",
|
|
80
|
+
"provenance": true
|
|
81
|
+
},
|
|
82
|
+
"scripts": {
|
|
83
|
+
"build": "tsup",
|
|
84
|
+
"check": "npm run typecheck && npm run lint && npm run format:check && npm run test && npm run build && npm run check:package && npm run size",
|
|
85
|
+
"check:package": "publint --strict && attw --pack . --profile node16",
|
|
86
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p examples && tsc --noEmit -p docs/src/examples",
|
|
87
|
+
"lint": "eslint .",
|
|
88
|
+
"lint:fix": "eslint . --fix",
|
|
89
|
+
"format": "prettier --write .",
|
|
90
|
+
"format:check": "prettier --check .",
|
|
91
|
+
"test": "vitest run --coverage",
|
|
92
|
+
"test:watch": "vitest",
|
|
93
|
+
"test:demo": "vitest run --config vitest.contract.config.ts",
|
|
94
|
+
"size": "size-limit",
|
|
95
|
+
"generate": "tsx scripts/generateApi.ts",
|
|
96
|
+
"generate:check": "tsx scripts/generateApi.ts --check",
|
|
97
|
+
"spec:fetch": "tsx scripts/fetchSpec.ts",
|
|
98
|
+
"fixtures:capture": "tsx scripts/captureErrors.ts",
|
|
99
|
+
"secrets": "secretlint \"**/*\"",
|
|
100
|
+
"changeset": "changeset",
|
|
101
|
+
"release": "npm run check && changeset publish",
|
|
102
|
+
"prepare": "husky",
|
|
103
|
+
"smoke": "node scripts/smoke.mjs && node scripts/smoke.cjs",
|
|
104
|
+
"example": "tsx --tsconfig examples/tsconfig.json",
|
|
105
|
+
"docs:dev": "node scripts/docs.mjs dev",
|
|
106
|
+
"docs:build": "node scripts/docs.mjs build"
|
|
107
|
+
},
|
|
108
|
+
"devDependencies": {
|
|
109
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
110
|
+
"@changesets/cli": "^3.0.3",
|
|
111
|
+
"@commitlint/cli": "^21.2.4",
|
|
112
|
+
"@eslint/js": "^10.0.1",
|
|
113
|
+
"@secretlint/secretlint-rule-preset-recommend": "^13.1.0",
|
|
114
|
+
"@size-limit/preset-small-lib": "^14.3.0",
|
|
115
|
+
"@types/node": "^22.20.5",
|
|
116
|
+
"@vitest/coverage-v8": "^5.1.0",
|
|
117
|
+
"eslint": "^10.14.0",
|
|
118
|
+
"eslint-config-prettier": "^10.1.8",
|
|
119
|
+
"husky": "^9.1.7",
|
|
120
|
+
"lint-staged": "^17.6.0",
|
|
121
|
+
"prettier": "^3.9.10",
|
|
122
|
+
"publint": "^0.3.25",
|
|
123
|
+
"secretlint": "^13.1.0",
|
|
124
|
+
"size-limit": "^14.3.0",
|
|
125
|
+
"tsup": "^9.0.0",
|
|
126
|
+
"tsx": "^4.23.15",
|
|
127
|
+
"typescript": "~6.0.3",
|
|
128
|
+
"typescript-eslint": "^8.72.1",
|
|
129
|
+
"vitest": "^5.1.0",
|
|
130
|
+
"yaml": "^2.9.1"
|
|
131
|
+
},
|
|
132
|
+
"overrides": {
|
|
133
|
+
"minimatch": "^11.0.5"
|
|
134
|
+
}
|
|
135
|
+
}
|