@steempro/sds 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/LICENSE +21 -0
- package/README.md +328 -2
- package/dist/index.cjs +13997 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +8599 -0
- package/dist/index.d.ts +8599 -0
- package/dist/index.js +13959 -0
- package/dist/index.js.map +1 -0
- package/docs/METHODS.md +4468 -0
- package/documentation.md +14814 -0
- package/package.json +65 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 faisalamin9696
|
|
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,329 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @steempro/sds
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Typed JavaScript / TypeScript client for the **Steem Blockchain Data Services
|
|
4
|
+
(SDS)** REST API — [sds0.steemworld.org](https://sds0.steemworld.org).
|
|
5
|
+
|
|
6
|
+
- **Every module and method** of the SDS reference: 22 modules, 285 methods,
|
|
7
|
+
fully typed with generated parameter/result interfaces.
|
|
8
|
+
- **Promise *and* node-style callback** support on every method.
|
|
9
|
+
- **`mapSds()`** — turns SDS's column oriented `{ cols, rows }` payloads into
|
|
10
|
+
plain row objects (and passes everything else through unchanged).
|
|
11
|
+
- **Structured errors** — one error class per failure mode, each with a stable
|
|
12
|
+
machine readable `code`.
|
|
13
|
+
- **Bring your own instance** — `sds0`, `sds1`, `sds`, or any custom SDS URL.
|
|
14
|
+
- **Retries, timeouts, abort signals, hooks**, client-side validation and
|
|
15
|
+
introspection APIs.
|
|
16
|
+
- ESM + CJS builds, zero runtime dependencies, Node 18+ / Deno / Bun / browsers
|
|
17
|
+
(anything with `fetch`).
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm i @steempro/sds
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
📚 **[Full documentation](documentation.md)** — every one of the 285 methods
|
|
24
|
+
indexed, with signatures, parameters and runnable examples.
|
|
25
|
+
[Method tables](docs/METHODS.md) · [README](README.md).
|
|
26
|
+
|
|
27
|
+
## Quick start
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { SDS } from '@steempro/sds';
|
|
31
|
+
|
|
32
|
+
const sds = new SDS(); // → https://sds0.steemworld.org
|
|
33
|
+
|
|
34
|
+
// Promise style
|
|
35
|
+
const stats = await sds.chain.getChainStats();
|
|
36
|
+
|
|
37
|
+
// Callback style (last argument is always the callback)
|
|
38
|
+
sds.posts.getPost('steemchiller', 'hello', (error, post) => {
|
|
39
|
+
if (error) return console.error(error.code, error.message);
|
|
40
|
+
console.log(post);
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
ESM and CommonJS are both supported:
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
const { SDS } = require('@steempro/sds');
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Choosing an SDS instance
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
new SDS(); // sds0 (default)
|
|
54
|
+
new SDS({ instance: 'sds1' }); // bundled instance name
|
|
55
|
+
new SDS({ instance: 'sds' }); // bundled instance name
|
|
56
|
+
new SDS({ baseUrl: 'https://my-sds.example.org' }); // any custom URL
|
|
57
|
+
new SDS({ instance: 'sds9', instances: { sds9: 'https://sds9.example.org' } });
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Register an instance for the whole process:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { registerInstance, listInstances } from '@steempro/sds';
|
|
64
|
+
|
|
65
|
+
registerInstance('sds9', 'https://sds9.example.org');
|
|
66
|
+
const sds = new SDS({ instance: 'sds9' });
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`DEFAULT_SDS_INSTANCES` contains the bundled names (`sds`, `sds0`, `sds1`).
|
|
70
|
+
|
|
71
|
+
## Calling methods
|
|
72
|
+
|
|
73
|
+
Every generated method accepts its parameters **positionally (in route
|
|
74
|
+
order)** or as a **single object keyed by parameter name**, plus an optional
|
|
75
|
+
trailing callback:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
// positional (route order)
|
|
79
|
+
await sds.chain.getAccountNamesByPrefix('ste', 50);
|
|
80
|
+
|
|
81
|
+
// object style
|
|
82
|
+
await sds.chain.getAccountNamesByPrefix({ prefix: 'ste', limit: 50 });
|
|
83
|
+
|
|
84
|
+
// callback style — either form
|
|
85
|
+
sds.chain.getAccountNamesByPrefix({ prefix: 'ste' }, (err, names) => { … });
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Optional trailing parameters are simply omitted — SDS applies their documented
|
|
89
|
+
defaults. If a parameter is skipped in the middle of a route, the client fills
|
|
90
|
+
it with the documented default (or the literal `null` placeholder SDS accepts).
|
|
91
|
+
|
|
92
|
+
**Community parameters** (e.g. `community` on `communities_api` / `feeds_api`)
|
|
93
|
+
take a **hive community id** — always `hive-` prefixed, e.g. `hive-160125`.
|
|
94
|
+
Bare ids (`160125`), titles (`steemit-news`) and regular accounts (`alice`)
|
|
95
|
+
pass SDS but come back empty, so the client rejects them during validation
|
|
96
|
+
(pass `validate: false` to bypass):
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
await sds.communities.getCommunity('hive-160125'); // ✅ real data
|
|
100
|
+
await sds.communities.getCommunity('160125'); // ❌ SDSValidationError
|
|
101
|
+
// "…must be a hive community id
|
|
102
|
+
// starting with \"hive-\" (e.g. \"hive-160125\")"
|
|
103
|
+
// The rule is exported for your own checks:
|
|
104
|
+
import { isCommunityParam, COMMUNITY_ID_PATTERN } from '@steempro/sds';
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Timestamp parameters** (`fromTime`, `toTime`, `blockTime`, …) accept **any
|
|
108
|
+
date form** — a `Date`, a date string or unix seconds — and are converted to
|
|
109
|
+
unix **seconds** (the unit SDS expects) before the request is sent:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
await sds.accountHistory.getHistoryByTime(
|
|
113
|
+
'steemit',
|
|
114
|
+
new Date('2020-09-14T00:00:00Z'), // Date
|
|
115
|
+
'2020-09-15 12:30:00', // date string — zone-less means UTC
|
|
116
|
+
100,
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
await sds.chain.getBlockInfoByTime('2020-09-13 12:26:40'); // → 1600000000
|
|
120
|
+
await sds.chain.getBlockInfoByTime(1600000000000); // ms auto-detected → 1600000000
|
|
121
|
+
|
|
122
|
+
// A value that cannot be understood throws before anything is sent:
|
|
123
|
+
// SDSValidationError: Parameter "fromTime" of account_history_api.getHistoryByTime
|
|
124
|
+
// must be a timestamp, got "yesterday". Pass a Date, a date/time string (e.g.
|
|
125
|
+
// "2020-09-13", "2020-09-13 12:30:00", "2020-09-13T12:30:00+02:00") or a unix
|
|
126
|
+
// timestamp in seconds (12+ digit numbers are read as milliseconds).
|
|
127
|
+
|
|
128
|
+
// The conversion is exported for your own code:
|
|
129
|
+
import { coerceTimestamp, isTimestampParam } from '@steempro/sds';
|
|
130
|
+
coerceTimestamp('2020-09-13'); // 1599955200 (2020-09-13T00:00:00Z)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Accepted forms: `Date` objects, `2020-09-13`, `2020/09/13`, `2020-09`, date-times
|
|
134
|
+
with or without seconds (`2020-09-13 12:30`, `2020-09-13T12:30:00`), anything with
|
|
135
|
+
an explicit zone (`Z`, `+02:00` — those keep their zone), other formats `Date`
|
|
136
|
+
parses (RFC 2822, `May 1, 2020`, …) and unix seconds. Timestamps inside JSON
|
|
137
|
+
queries (`{ type: 'transfer', fromTime: '2020-09-13' }`) are converted the same
|
|
138
|
+
way.
|
|
139
|
+
|
|
140
|
+
### Generic entry points
|
|
141
|
+
|
|
142
|
+
Not everything needs a generated wrapper:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
// By name, with params array + per call options
|
|
146
|
+
await sds.call('chain_api', 'getAccountNames', [10, 0], { timeout: 5000 });
|
|
147
|
+
|
|
148
|
+
// Even methods missing from the bundled reference work (raw segments)
|
|
149
|
+
await sds.call('brand_new_api', 'getThing', ['a', 'b']);
|
|
150
|
+
|
|
151
|
+
// Raw GET, unwraps the { code, result } envelope
|
|
152
|
+
await sds.request('/chain_api/getConfig');
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Mapping `{ cols, rows }` responses with `mapSds`
|
|
156
|
+
|
|
157
|
+
Some SDS list/search methods return a column oriented table instead of objects:
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{ "cols": { "link_id": 0, "author": 6, "permlink": 7 },
|
|
161
|
+
"rows": [[114136936, 0, 69.305, 0, "", "", "alice", "hello"]] }
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`mapSds()` converts that to plain row objects, and **passes any other payload
|
|
165
|
+
through unchanged**, so it is safe to chain on any call:
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import { mapSds, isSDSTable } from '@steempro/sds';
|
|
169
|
+
|
|
170
|
+
const rows = mapSds(await sds.feeds.getActivePostsByCreated({ limit: 1 }));
|
|
171
|
+
// [{ link_id: 114136936, author: 'alice', permlink: 'hello', … }, …]
|
|
172
|
+
|
|
173
|
+
// …or as a promise continuation:
|
|
174
|
+
const rows2 = await sds.feeds.getActivePostsByTrending().then(mapSds);
|
|
175
|
+
|
|
176
|
+
// Narrow first when the payload type is unknown:
|
|
177
|
+
const payload: unknown = await sds.request('/feeds_api/getActivePostsByTrending');
|
|
178
|
+
const rows3 = isSDSTable(payload) ? mapSds(payload) : payload;
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
It maps by the `cols` **name → index** entries (not by key order), supports
|
|
182
|
+
array style `cols`, keeps already keyed rows, handles single-column scalar
|
|
183
|
+
rows, returns `[]` for an empty table, and unwraps raw `{ code, result }`
|
|
184
|
+
envelopes first. A non-table payload (plain object, array, scalar) is returned
|
|
185
|
+
as-is, and the overloads preserve that type (`mapSds<T>(payload)`).
|
|
186
|
+
|
|
187
|
+
## Error handling
|
|
188
|
+
|
|
189
|
+
Every failure is an `SDSError` subclass with a stable `code`, plus the
|
|
190
|
+
`module`, `method` and `url` of the failing call:
|
|
191
|
+
|
|
192
|
+
| Class | `code` | When |
|
|
193
|
+
| --------------------- | ---------------------- | ------------------------------------------------ |
|
|
194
|
+
| `SDSValidationError` | `ERR_SDS_VALIDATION` | Parameter failed type/range/allow-list validation |
|
|
195
|
+
| `SDSArgumentError` | `ERR_SDS_ARGUMENT` | Unknown method/instance/parameter, wrong arity |
|
|
196
|
+
| `SDSNetworkError` | `ERR_SDS_NETWORK` | Request never reached SDS (DNS, CORS, offline) |
|
|
197
|
+
| `SDSTimeoutError` | `ERR_SDS_TIMEOUT` | Request exceeded `timeout` |
|
|
198
|
+
| `SDSAbortError` | `ERR_SDS_ABORT` | Cancelled through an `AbortSignal` |
|
|
199
|
+
| `SDSHttpError` | `ERR_SDS_HTTP` | Non-success HTTP status (e.g. 404 unknown route) |
|
|
200
|
+
| `SDSResponseError` | `ERR_SDS_RESPONSE` | HTTP 200 but not the expected JSON envelope |
|
|
201
|
+
| `SDSApiError` | `ERR_SDS_API` | Application error: `{ code: -1, error: "…" }` |
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
import { SDSApiError, isSDSError } from '@steempro/sds';
|
|
205
|
+
|
|
206
|
+
try {
|
|
207
|
+
await sds.posts.getPost('alice', 'missing');
|
|
208
|
+
} catch (error) {
|
|
209
|
+
if (error instanceof SDSApiError) {
|
|
210
|
+
console.log(error.apiCode, error.errorMessage); // -1, "Link id … does not exist"
|
|
211
|
+
}
|
|
212
|
+
if (isSDSError(error)) console.log(error.toJSON()); // safe to log / serialize
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Callback style delivers the same errors: `callback(error)` on failure,
|
|
217
|
+
`callback(null, result)` on success. Validation errors are passed to the
|
|
218
|
+
callback rather than thrown.
|
|
219
|
+
|
|
220
|
+
## Retries, timeouts, cancellation
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
const sds = new SDS({
|
|
224
|
+
timeout: 10_000, // per request, ms (default 30_000)
|
|
225
|
+
retries: 2, // network / timeout / 5xx / 429 retries (default 2)
|
|
226
|
+
retryDelay: 300, // exponential backoff base, ms (default 300)
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// Per call overrides + cancellation
|
|
230
|
+
const controller = new AbortController();
|
|
231
|
+
await sds.call('chain_api', 'getConfig', null, {
|
|
232
|
+
timeout: 2000,
|
|
233
|
+
retries: 0,
|
|
234
|
+
signal: controller.signal,
|
|
235
|
+
headers: { 'x-api-key': '…' },
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Application errors (`ERR_SDS_API`) and 4xx responses are never retried.
|
|
240
|
+
|
|
241
|
+
## Derived clients
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
const fast = sds.withOptions({ timeout: 3000 });
|
|
245
|
+
const authed = sds.withOptions({ headers: { authorization: `Bearer ${token}` } });
|
|
246
|
+
const quiet = sds.withOptions({ retries: 0 });
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Hooks (logging / tracing)
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
const sds = new SDS({
|
|
253
|
+
onRequest: ({ url, module, method, attempt }) => console.log('→', url),
|
|
254
|
+
onResponse: ({ url, status, durationMs, ok }) => console.log('←', status, durationMs, ok),
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Introspection — list all methods and parameters
|
|
259
|
+
|
|
260
|
+
The bundled reference can be queried at runtime:
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
import { listModules, listMethods, findMethod, API_REFERENCE } from '@steempro/sds';
|
|
264
|
+
|
|
265
|
+
sds.listModules(); // 22 modules
|
|
266
|
+
sds.listMethods('chain_api'); // methods of one module
|
|
267
|
+
sds.describeMethod('chain_api.getAccountNames');
|
|
268
|
+
// → { name, path, description, params: [{ name, type, optional, default, min, max, … }], result }
|
|
269
|
+
|
|
270
|
+
sds.hasMethod('posts_api', 'getPost'); // true
|
|
271
|
+
sds.referenceVersion; // SDS reference version of the bundle
|
|
272
|
+
API_REFERENCE; // full metadata (source, version, modules)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
A human readable list of **every module, method and parameter** is generated
|
|
276
|
+
into [`docs/METHODS.md`](./docs/METHODS.md).
|
|
277
|
+
|
|
278
|
+
## TypeScript
|
|
279
|
+
|
|
280
|
+
The package ships its own types (`ESM` + `CJS` + `.d.ts`). Every method has
|
|
281
|
+
generated argument interfaces and result types:
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
import type { ChainGetAccountNamesArgs, PostsGetPostArgs } from '@steempro/sds';
|
|
285
|
+
|
|
286
|
+
const args: ChainGetAccountNamesArgs = { limit: 10, offset: 0 };
|
|
287
|
+
const names = await sds.chain.getAccountNames(args);
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Result types map SDS's `JSON Object` / `JSON Array` / `integer` / `string`
|
|
291
|
+
returns to `SDSJsonObject` / `SDSJsonArray` / `number` / `string`; pass a type
|
|
292
|
+
parameter to narrow them:
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
const config = await sds.chain.getConfig<{ STM: string }>();
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Options reference
|
|
299
|
+
|
|
300
|
+
| Option | Default | Description |
|
|
301
|
+
| -------------- | ------------------ | ------------------------------------------------------- |
|
|
302
|
+
| `instance` | `'sds0'` | Bundled instance name or full URL |
|
|
303
|
+
| `baseUrl` | – | Full base URL (takes precedence over `instance`) |
|
|
304
|
+
| `instances` | – | Extra `{ name: url }` pairs for this client |
|
|
305
|
+
| `timeout` | `30000` | Request timeout in ms (`0` disables) |
|
|
306
|
+
| `retries` | `2` | Retries for network/timeout/5xx/429 |
|
|
307
|
+
| `retryDelay` | `300` | Exponential backoff base in ms |
|
|
308
|
+
| `headers` | `{}` | Extra headers for every request |
|
|
309
|
+
| `fetch` | `globalThis.fetch` | Custom fetch implementation |
|
|
310
|
+
| `validate` | `true` | Client-side parameter validation |
|
|
311
|
+
| `encode` | `true` | URL-encode path segments |
|
|
312
|
+
| `onRequest` | – | Hook before each attempt |
|
|
313
|
+
| `onResponse` | – | Hook after each attempt (success or failure) |
|
|
314
|
+
|
|
315
|
+
## Development
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
npm install
|
|
319
|
+
npm run scrape # refresh data/api.json from the live SDS reference
|
|
320
|
+
npm run generate # regenerate src/generated/* and docs/METHODS.md
|
|
321
|
+
npm run typecheck
|
|
322
|
+
npm test # unit tests (mocked fetch)
|
|
323
|
+
npm run test:live # tests against the real SDS (SDS_LIVE_INSTANCE=sds1 to switch)
|
|
324
|
+
npm run build # dist/ (ESM + CJS + types)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## License
|
|
328
|
+
|
|
329
|
+
MIT
|