@mywebapi.com/sdk 0.1.2 → 0.2.1

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  TypeScript client for the CPlugin WebAPI v2 — a management API for trading-platform servers.
4
4
 
5
- **Status:** Published on the public npm registry as [`@mywebapi.com/sdk`](https://www.npmjs.com/package/@mywebapi.com/sdk) (early access, current version `0.1.2`). The API shape is stable; while the package is at `0.x`, minor releases may introduce breaking changes, so pin a version in production. Versioning follows [semver](https://semver.org/).
5
+ **Status:** Version `0.2.1`. The package keeps the generated REST catalog and typed MT4/MT5 realtime clients in one entry point; minor releases may introduce breaking changes while the package remains at `0.x`. Pin a version in production.
6
6
 
7
7
  - **Auto-generated types** from the live OpenAPI spec — all endpoints, DTOs, and enums are exact and stay in sync with the server.
8
8
  - **Unified entry point** — `CPluginWebApiClient` with `mt4` and `mt5` namespaces; credentials and token management configured once at instantiation.
@@ -27,20 +27,19 @@ The SDK manages OAuth2 access tokens for you — pass `clientId` / `clientSecret
27
27
  import { CPluginWebApiClient, ApiError, collectAll } from '@mywebapi.com/sdk';
28
28
 
29
29
  const client = new CPluginWebApiClient({
30
- env: 'prod', // or 'staging' or { baseUrl, authUrl }
30
+ env: 'prod', // or 'staging' or { env: 'custom', apiBaseUrl, authority }
31
31
  clientId: 'your-client-id',
32
32
  clientSecret: process.env.CPLUGIN_WEBAPI_CLIENT_SECRET!,
33
33
  });
34
34
 
35
- // MT4 server time
35
+ // server time (mt4 namespace)
36
36
  const tp = '3029d415-d0a6-4710-a9c1-8cb063ef872f';
37
37
  const time = await client.mt4.getServerTime(tp);
38
- console.log('MT4 server time:', time.data.timestamp);
38
+ console.log('server time (mt4):', time);
39
39
 
40
- // MT5 server time
40
+ // server time (mt5 namespace)
41
41
  const mt5Time = await client.mt5.getServerTime(tp);
42
- console.log('MT5 server time:', mt5Time.data.timestamp);
43
-
42
+ console.log('server time (mt5):', mt5Time);
44
43
  // Pagination — single page with cursor capture
45
44
  const page = await client.paged(() =>
46
45
  client.mt4.getOnlineGet(tp, { limit: 50 }),
@@ -81,38 +80,57 @@ try {
81
80
  }
82
81
  ```
83
82
 
84
- ### From environment variables
83
+ ### Configuration from environment variables
85
84
 
86
- `CPluginWebApiClient.fromEnvironment()` builds a client from `CPLUGIN_WEBAPI_ENV` (or `CPLUGIN_WEBAPI_BASE_URL` + `CPLUGIN_WEBAPI_AUTH_URL`), `CPLUGIN_WEBAPI_CLIENT_ID`, and `CPLUGIN_WEBAPI_CLIENT_SECRET`. Missing variables raise an `Error` that names the missing key.
85
+ The client constructor is the single configuration API. Read environment variables in the application and pass the supported fields explicitly; there is no `fromEnvironment()` factory.
87
86
 
88
87
  ```typescript
89
- const client = CPluginWebApiClient.fromEnvironment();
90
- const tp = process.env.CPLUGIN_WEBAPI_TRADE_PLATFORM!;
91
- const time = await client.mt4.getServerTime(tp);
88
+ const client = new CPluginWebApiClient({
89
+ env: (process.env.CPLUGIN_WEBAPI_ENV === 'staging' ? 'staging' : 'prod'),
90
+ clientId: process.env.CPLUGIN_WEBAPI_CLIENT_ID!,
91
+ clientSecret: process.env.CPLUGIN_WEBAPI_CLIENT_SECRET!,
92
+ });
92
93
  ```
93
94
 
94
- ### Static token (advanced / testing)
95
+ ### Request deadlines and cancellation
95
96
 
96
- For scenarios with a pre-issued JWT (CI fixtures, short-lived service-account tokens, test rigs), pass a `token` instead of `clientId` / `clientSecret`. No refresh is performed — when the token expires, the API returns errors.
97
+ REST operations and each OAuth discovery/token request have a bounded deadline. Configure the REST deadline with `timeoutMs` (the default is 30 seconds):
97
98
 
98
99
  ```typescript
99
100
  const client = new CPluginWebApiClient({
100
101
  env: 'prod',
101
- token: 'eyJhbGc...',
102
+ clientId: process.env.CPLUGIN_WEBAPI_CLIENT_ID!,
103
+ clientSecret: process.env.CPLUGIN_WEBAPI_CLIENT_SECRET!,
104
+ timeoutMs: 10_000,
102
105
  });
106
+ ```
103
107
 
104
- const tp = '3029d415-d0a6-4710-a9c1-8cb063ef872f';
105
- const time = await client.mt4.getServerTime(tp);
108
+ The deadline covers token acquisition, the API request, and response-body decoding. Cancellation and timeout errors are propagated rather than being reported as malformed JSON.
109
+
110
+ ### Static token (advanced realtime/testing)
111
+
112
+ The unified REST client uses client credentials. For a pre-issued JWT in a test rig or a direct realtime client, use the exported `StaticTokenProvider`; no refresh is performed.
113
+
114
+ ```typescript
115
+ import { MT4V2SignalRClient, StaticTokenProvider } from '@mywebapi.com/sdk';
116
+
117
+ const rt = new MT4V2SignalRClient({
118
+ baseUrl: 'https://cloud.mywebapi.com',
119
+ tradePlatform: process.env.CPLUGIN_WEBAPI_TRADE_PLATFORM!,
120
+ tokenProvider: new StaticTokenProvider(process.env.CPLUGIN_WEBAPI_ACCESS_TOKEN!),
121
+ });
106
122
  ```
107
123
 
108
124
  ## Retries
109
125
 
110
- Idempotent requests retry automatically on transient errors (`429`, `502`, `503`, `504`, and `408`). Retry-eligible:
111
126
 
112
- - `GET` and `HEAD` — always idempotent per HTTP spec.
113
- - `POST` / `PATCH` / `PUT` / `DELETE` — only when you supply an `Idempotency-Key` header via method options.
127
+ Only requests that are safe to replay retry automatically on transient errors (`408`, `429`, `502`, `503`, `504`) and retryable network failures:
114
128
 
115
- Backoff is exponential (default 3 attempts, base 500 ms, factor 2, ±25% jitter) with `Retry-After` honoured (both `delta-seconds` and HTTP-date forms). Override per-client:
129
+ - `GET`, `HEAD`, and `OPTIONS` — safe by definition.
130
+ - `PUT` and `DELETE` — treated as idempotent by the transport.
131
+ - `POST` and `PATCH` — never repeated automatically, even when an `Idempotency-Key` header is present.
132
+
133
+ An aborted request is never retried. Backoff is exponential (default 3 attempts, base 500 ms, factor 2, ±25% jitter) with `Retry-After` honoured (both `delta-seconds` and HTTP-date forms). Override per-client:
116
134
 
117
135
  ```typescript
118
136
  const client = new CPluginWebApiClient({
@@ -149,7 +167,7 @@ try {
149
167
 
150
168
  ## Idempotency
151
169
 
152
- Mutating endpoints (POST / PATCH / PUT / DELETE) accept an optional `Idempotency-Key` header for safe retries. Pass it in the options object:
170
+ Mutating endpoints accept an optional `Idempotency-Key` header, which is forwarded to the server for its own deduplication. The SDK does not treat this header as permission to replay `POST` or `PATCH`.
153
171
 
154
172
  ```typescript
155
173
  const tp = '3029d415-d0a6-4710-a9c1-8cb063ef872f';
@@ -162,7 +180,7 @@ await client.mt4.patchUserRecordLogin(
162
180
  );
163
181
  ```
164
182
 
165
- Any string ≤255 chars is valid. Two calls with the same key within the server's `cacheTimeout` window return the cached response. Supplying a key also marks the request as idempotent for the retry layer, enabling automatic retry on transient failures.
183
+ The server may return a cached response for a repeated key within its configured window; this is independent of the SDK transport retry policy.
166
184
 
167
185
  ## Pagination helpers
168
186
 
@@ -208,8 +226,7 @@ for await (const pageItems of paginate((cursor) =>
208
226
 
209
227
  ```bash
210
228
  bun install
211
- bun run fetch-spec # download swagger.json from running WebAPI (WEBAPI_BASE_URL env)
212
- bun run generate # regenerate src/generated/api.d.ts
229
+ bun run generate # regenerate src/generated/
213
230
  bun run typecheck
214
231
 
215
232
  # Integration tests against the live WebAPI — needs env vars (or a .env file):
@@ -222,11 +239,8 @@ bun run build # outputs dist/index.js + dist/*.d.ts
222
239
 
223
240
  ## SignalR (real-time streams)
224
241
 
225
- Real-time streaming is **built into this package** — there is no separate SignalR package. The only extra is the optional peer dependency `@microsoft/signalr`, installed **only if you use real-time** (the REST surface works without it):
242
+ Real-time streaming clients are exported from this package. `@microsoft/signalr` is a required runtime dependency and is installed with the SDK; the build keeps the official package external so consumers can use their normal bundler/runtime.
226
243
 
227
- ```sh
228
- bun add @microsoft/signalr # or: npm install @microsoft/signalr
229
- ```
230
244
 
231
245
  Open a hub from the same client — it reuses the client's environment and OAuth token:
232
246
 
@@ -240,7 +254,7 @@ for await (const tick of rt.streamTicks('EURUSD')) {
240
254
  await rt.stop();
241
255
  ```
242
256
 
243
- MT4 hubs expose ticks, trades, margin-call, user and symbol streams; MT5 hubs expose connection status and margin-call updates.
257
+ The `mt4` hubs expose ticks, trades, margin-call, user and symbol streams; the `mt5` hubs expose connection status and margin-call updates.
244
258
 
245
259
  ## What's next
246
260
 
package/dist/auth.d.ts CHANGED
@@ -2,6 +2,7 @@ export interface TokenProvider {
2
2
  /** Return a valid bearer token. May trigger a network call on first use or after expiry. */
3
3
  getToken(opts?: {
4
4
  forceRefresh?: boolean;
5
+ signal?: AbortSignal;
5
6
  }): Promise<string>;
6
7
  }
7
8
  export declare class StaticTokenProvider implements TokenProvider {
@@ -9,18 +10,23 @@ export declare class StaticTokenProvider implements TokenProvider {
9
10
  constructor(token: string);
10
11
  getToken(_opts?: {
11
12
  forceRefresh?: boolean;
13
+ signal?: AbortSignal;
12
14
  }): Promise<string>;
13
15
  }
14
16
  export interface ClientCredentialsOptions {
15
17
  clientId: string;
16
18
  clientSecret: string;
17
- /** IdentityServer base URL, e.g. `https://identity.example`. Discovery doc resolved as `${identityUrl}/.well-known/openid-configuration`. */
19
+ /** IdentityServer base URL. Discovery is resolved below this origin. */
18
20
  identityUrl: string;
19
21
  scopes?: readonly string[];
20
- /** Inject a custom fetch (tests, instrumentation). Defaults to global `fetch`. */
22
+ /** Inject a custom fetch (tests, instrumentation). Defaults to global fetch. */
21
23
  fetch?: typeof fetch;
22
- /** Treat a token as expired this many seconds before its true expiry. RFC 6749 §10.4 — buffer for clock drift + flight time. */
24
+ /** Treat a token as expired this many seconds before its true expiry. */
23
25
  clockSkewSeconds?: number;
26
+ /** Per-discovery/token-request deadline. Defaults to 30 seconds. */
27
+ timeoutMs?: number;
28
+ /** Only tests may opt into plain HTTP on loopback hosts. */
29
+ allowInsecureLoopback?: boolean;
24
30
  }
25
31
  export declare class OAuth2TokenError extends Error {
26
32
  readonly status: number;
@@ -38,15 +44,19 @@ export declare class ClientCredentialsTokenProvider implements TokenProvider {
38
44
  private readonly clientId;
39
45
  private readonly clientSecret;
40
46
  private readonly identityUrl;
47
+ private readonly identityOrigin;
41
48
  private readonly scopes;
42
49
  private readonly fetchFn;
43
50
  private readonly clockSkewMs;
51
+ private readonly timeoutMs;
52
+ private readonly allowInsecureLoopback;
44
53
  private cached;
45
54
  private discoveryPromise;
46
55
  private refreshPromise;
47
56
  constructor(opts: ClientCredentialsOptions);
48
57
  getToken(opts?: {
49
58
  forceRefresh?: boolean;
59
+ signal?: AbortSignal;
50
60
  }): Promise<string>;
51
61
  private acquireToken;
52
62
  private getDiscovery;