@taphubhq/sdk-core 0.13.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TabHub
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,119 @@
1
+ # @taphubhq/sdk-core
2
+
3
+ Framework-agnostic TypeScript SDK for the TabHub platform.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ pnpm add @taphubhq/sdk-core
9
+ ```
10
+
11
+ ## Minimum Integration
12
+
13
+ ```ts
14
+ import { TaphubClient } from '@taphubhq/sdk-core';
15
+
16
+ const client = new TaphubClient({
17
+ agencyId: 'acme-corp',
18
+ // Shared API base. The SDK derives:
19
+ // - grid-api → ${endpoint}/grid-api/grid-gql
20
+ // - user-service → ${endpoint}/taphub-user-service/th-user-gql
21
+ endpoint: 'https://builder.taptrading.net/api',
22
+ });
23
+
24
+ // Session-token login via user-service GraphQL (preferred).
25
+ await client.auth.loginWithSession(upstreamSessionToken);
26
+
27
+ const me = await client.user.me();
28
+ ```
29
+
30
+ ### Login methods
31
+
32
+ | Method | Transport | Status |
33
+ |---------------------------------|--------------------|-------------|
34
+ | `loginWithSession(sessionToken)` | user-service GraphQL | **Preferred** |
35
+ | `createDemoUser(username?)` | grid-api GraphQL | Active |
36
+ | `loginWithGoogle(idToken)` | grid-api REST | `@deprecated` |
37
+ | `demoLogin(username?)` | grid-api REST | `@deprecated` |
38
+
39
+ REST-backed methods continue to work until the gateway retires the routes in a follow-up change.
40
+
41
+ ## Error Handling
42
+
43
+ All SDK failures throw a subclass of `TaphubError`. Use `instanceof` to discriminate.
44
+
45
+ ```ts
46
+ import {
47
+ TaphubError,
48
+ TaphubAuthError,
49
+ TaphubNetworkError,
50
+ TaphubValidationError,
51
+ TaphubServerError,
52
+ TaphubSlippageError,
53
+ } from '@taphubhq/sdk-core';
54
+
55
+ try {
56
+ await client.bid.placeBid(input);
57
+ } catch (e) {
58
+ if (e instanceof TaphubSlippageError) {
59
+ showSlippageBanner(e.clientCoef, e.serverCoef, e.slippage);
60
+ } else if (e instanceof TaphubAuthError) {
61
+ redirectToLogin();
62
+ } else if (e instanceof TaphubValidationError) {
63
+ showFieldError(e.code);
64
+ } else if (e instanceof TaphubNetworkError) {
65
+ showOfflineBanner();
66
+ }
67
+ }
68
+ ```
69
+
70
+ ### Wire error code → SDK error class
71
+
72
+ The GraphQL transport classifies errors by the first entry's `extensions.code` at HTTP 200 with `errors[]` (the GraphQL convention used by grid-api).
73
+
74
+ | Wire `extensions.code` | SDK class | Typed fields |
75
+ |-----------------------------------------------------------|--------------------------|---------------------------------------|
76
+ | `Unauthorized`, `TokenExpired`, `NotAuthenticated` | `TaphubAuthError` | `code` |
77
+ | `Bid_CoefficientMismatch` (with valid `meta.{clientCoef,serverCoef,slippage}`) | `TaphubSlippageError` | `code`, `clientCoef`, `serverCoef`, `slippage` |
78
+ | Any other code | `TaphubValidationError` | `code` |
79
+ | HTTP 5xx (any code) | `TaphubServerError` | `code` |
80
+ | Fetch failure / `AbortSignal` cancellation | `TaphubNetworkError` | `code` (`NetworkUnreachable` / `Aborted`) |
81
+
82
+ `TaphubSlippageError extends TaphubValidationError`, so existing `instanceof TaphubValidationError` catch blocks keep working. Place the `TaphubSlippageError` check first when both branches exist.
83
+
84
+ ### Slippage error fallback
85
+
86
+ `TaphubSlippageError` is only thrown when `extensions.meta.clientCoef`, `extensions.meta.serverCoef`, and `extensions.meta.slippage` are all finite numbers. The `slippage` field is the client-submitted tolerance percent (e.g. `5` for 5%). If `meta` is missing or malformed, the SDK falls back to a generic `TaphubValidationError` with `code === 'Bid_CoefficientMismatch'`. Consumers SHOULD treat the generic fallback as the same user-facing rejection but without typed coefficient access.
87
+
88
+ ## Network quality
89
+
90
+ The client exposes a passive network-quality monitor at `client.network`. It samples real GraphQL, REST, and MQTT traffic that the app produces and reports a smoothed quality signal.
91
+
92
+ ```ts
93
+ import type { NetworkQuality } from '@taphubhq/sdk-core';
94
+
95
+ const current: NetworkQuality = client.network.getCurrent();
96
+ // → { network: 'good' | 'fair' | 'poor' | 'offline',
97
+ // backend: 'ok' | 'degraded' | 'down',
98
+ // rtt, jitter, lossRate, mqttConnected, samplesInWindow, lastUpdated }
99
+
100
+ const off = client.network.subscribe(({ previous, current }) => {
101
+ if (current.network !== previous.network) showBanner(current.network);
102
+ });
103
+ // later: off();
104
+
105
+ client.network.reset(); // clears window state, e.g. on sign-in
106
+ ```
107
+
108
+ `network` and `backend` are independent signals. HTTP 5xx and GraphQL `errors[]` populate `backend` (`degraded` / `down`) without polluting `network`, so the UI can distinguish a weak user connection from a backend incident.
109
+
110
+ The monitor is always present, even when `mqttEndpoint` is not configured. In SSR / Node environments where `navigator` is undefined, construction does not throw — only the browser fallback paths are skipped.
111
+
112
+ ### Caveats
113
+
114
+ - Connection samples from `navigator.connection` are used only as a cold-start fallback; once 3 real samples accumulate they no longer contribute to the EMA.
115
+ - MQTT QoS1 `puback` timing is not yet plumbed; v1 derives MQTT signal from `connect` / `reconnect` / `disconnect` events only.
116
+
117
+ ## License
118
+
119
+ MIT