@taphubhq/sdk-core 0.26.1 → 0.27.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/README.md +12 -0
- package/dist/index.cjs +62 -1
- package/dist/index.d.mts +109 -1
- package/dist/index.d.ts +109 -1
- package/dist/index.js +62 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,18 @@ For React bindings (hooks, providers, i18n), use
|
|
|
12
12
|
pnpm add @taphubhq/sdk-core
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
### Server compatibility
|
|
16
|
+
|
|
17
|
+
The SDK's queries select the fields they need unconditionally, so a release that
|
|
18
|
+
adds a field also raises the minimum grid-api it runs against. Check this before
|
|
19
|
+
upgrading in an environment you do not deploy the server to.
|
|
20
|
+
|
|
21
|
+
| sdk-core | Needs grid-api serving | Or else |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| 0.27.0+ | `Bid.cellCandle { o h l c final touchSec touchPrice }` | `myBids` fails GraphQL validation and returns **no bids** |
|
|
24
|
+
|
|
25
|
+
Deploy grid-api before the client, on every environment.
|
|
26
|
+
|
|
15
27
|
## Minimum Integration
|
|
16
28
|
|
|
17
29
|
```ts
|
package/dist/index.cjs
CHANGED
|
@@ -661,7 +661,22 @@ function normaliseBid(node) {
|
|
|
661
661
|
refundAmount: node.refund_amount ?? null,
|
|
662
662
|
slippage: node.slippage,
|
|
663
663
|
createdAt: node.created_at || null,
|
|
664
|
-
meta: parseMeta(node.meta)
|
|
664
|
+
meta: parseMeta(node.meta),
|
|
665
|
+
// Absent and explicit null both mean "no candle" — an older server, an unselected
|
|
666
|
+
// field, a pending bid and purged ticks must all read the same to a consumer.
|
|
667
|
+
// `final` null (nullable Boolean) collapses to absent = settled, so only a real
|
|
668
|
+
// `false` puts the row in the in-progress presentation.
|
|
669
|
+
cellCandle: node.cellCandle ? {
|
|
670
|
+
o: node.cellCandle.o,
|
|
671
|
+
h: node.cellCandle.h,
|
|
672
|
+
l: node.cellCandle.l,
|
|
673
|
+
c: node.cellCandle.c,
|
|
674
|
+
...typeof node.cellCandle.final === "boolean" ? { final: node.cellCandle.final } : {},
|
|
675
|
+
// Both legs or neither — see BidCellCandle.touchSec. Nulls (a non-win,
|
|
676
|
+
// or an older server) collapse to absent so a consumer only has to
|
|
677
|
+
// check one of them.
|
|
678
|
+
...typeof node.cellCandle.touchSec === "number" && typeof node.cellCandle.touchPrice === "string" ? { touchSec: node.cellCandle.touchSec, touchPrice: node.cellCandle.touchPrice } : {}
|
|
679
|
+
} : null
|
|
665
680
|
};
|
|
666
681
|
}
|
|
667
682
|
function normaliseBids(list) {
|
|
@@ -682,6 +697,7 @@ var PLACE_BID_MUTATION = `mutation PlaceBid($input: PlaceBidInput!) {
|
|
|
682
697
|
var MY_BIDS_QUERY = `query MyBids($statuses: [BidStatus!], $limit: Int, $offset: Int, $pairId: ID) {
|
|
683
698
|
myBids(statuses: $statuses, limit: $limit, offset: $offset, pairId: $pairId) {
|
|
684
699
|
id user_id pair_id currency amount coefficient time1 time2 price1 price2 status payout refund_rate refund_amount slippage created_at meta
|
|
700
|
+
cellCandle { o h l c final touchSec touchPrice }
|
|
685
701
|
}
|
|
686
702
|
}`;
|
|
687
703
|
var CANCEL_BID_MUTATION = `mutation CancelBid($input: CancelBidInput!) {
|
|
@@ -1849,6 +1865,23 @@ function mapWireBidResult(raw, topicPairId) {
|
|
|
1849
1865
|
userId: p.user_id
|
|
1850
1866
|
};
|
|
1851
1867
|
if (typeof p.balance === "string") data.balance = p.balance;
|
|
1868
|
+
const candle = p.cellCandle;
|
|
1869
|
+
if (candle && typeof candle.o === "string" && typeof candle.h === "string" && typeof candle.l === "string" && typeof candle.c === "string") {
|
|
1870
|
+
data.cellCandle = {
|
|
1871
|
+
o: candle.o,
|
|
1872
|
+
h: candle.h,
|
|
1873
|
+
l: candle.l,
|
|
1874
|
+
c: candle.c,
|
|
1875
|
+
final: candle.final !== "false"
|
|
1876
|
+
};
|
|
1877
|
+
if (typeof candle.touchSec === "string" && typeof candle.touchPrice === "string") {
|
|
1878
|
+
const touchSec = Number.parseInt(candle.touchSec, 10);
|
|
1879
|
+
if (Number.isFinite(touchSec)) {
|
|
1880
|
+
data.cellCandle.touchSec = touchSec;
|
|
1881
|
+
data.cellCandle.touchPrice = candle.touchPrice;
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1852
1885
|
if (topicPairId !== void 0) data.pairId = topicPairId;
|
|
1853
1886
|
return { event: "bidWon", data };
|
|
1854
1887
|
}
|
|
@@ -1857,6 +1890,32 @@ function mapWireBidResult(raw, topicPairId) {
|
|
|
1857
1890
|
if (topicPairId !== void 0) data.pairId = topicPairId;
|
|
1858
1891
|
return { event: "bidLost", data };
|
|
1859
1892
|
}
|
|
1893
|
+
case "cell_candle_final": {
|
|
1894
|
+
const candle = p.cellCandle;
|
|
1895
|
+
if (!candle || typeof candle.o !== "string" || typeof candle.h !== "string" || typeof candle.l !== "string" || typeof candle.c !== "string") {
|
|
1896
|
+
return null;
|
|
1897
|
+
}
|
|
1898
|
+
const data = {
|
|
1899
|
+
bidId: p.bidId,
|
|
1900
|
+
userId: p.user_id,
|
|
1901
|
+
cellCandle: {
|
|
1902
|
+
o: candle.o,
|
|
1903
|
+
h: candle.h,
|
|
1904
|
+
l: candle.l,
|
|
1905
|
+
c: candle.c,
|
|
1906
|
+
final: candle.final !== "false"
|
|
1907
|
+
}
|
|
1908
|
+
};
|
|
1909
|
+
if (typeof candle.touchSec === "string" && typeof candle.touchPrice === "string") {
|
|
1910
|
+
const touchSec = Number.parseInt(candle.touchSec, 10);
|
|
1911
|
+
if (Number.isFinite(touchSec)) {
|
|
1912
|
+
data.cellCandle.touchSec = touchSec;
|
|
1913
|
+
data.cellCandle.touchPrice = candle.touchPrice;
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
if (topicPairId !== void 0) data.pairId = topicPairId;
|
|
1917
|
+
return { event: "cellCandleFinal", data };
|
|
1918
|
+
}
|
|
1860
1919
|
default:
|
|
1861
1920
|
console.warn(`Unknown bid_result type "${String(p.type)}"`);
|
|
1862
1921
|
return null;
|
|
@@ -1974,6 +2033,7 @@ var RealtimeModule = class extends import_eventemitter35.default {
|
|
|
1974
2033
|
else if (mapped.event === "bidAccepted") channel.emit("bidAccepted", mapped.data);
|
|
1975
2034
|
else if (mapped.event === "bidWon") channel.emit("bidWon", mapped.data);
|
|
1976
2035
|
else if (mapped.event === "bidLost") channel.emit("bidLost", mapped.data);
|
|
2036
|
+
else if (mapped.event === "cellCandleFinal") channel.emit("cellCandleFinal", mapped.data);
|
|
1977
2037
|
else if (mapped.event === "balanceUpdate") channel.emit("balanceUpdate", mapped.data);
|
|
1978
2038
|
else if (mapped.event === "configUpdate") channel.emit("configUpdate", mapped.data);
|
|
1979
2039
|
else if (mapped.event === "idealConfigUpdate")
|
|
@@ -2106,6 +2166,7 @@ var RealtimeModule = class extends import_eventemitter35.default {
|
|
|
2106
2166
|
if (!mapped) return;
|
|
2107
2167
|
if (mapped.event === "bidWon") channel.emit("bidWon", mapped.data);
|
|
2108
2168
|
else if (mapped.event === "bidLost") channel.emit("bidLost", mapped.data);
|
|
2169
|
+
else if (mapped.event === "cellCandleFinal") channel.emit("cellCandleFinal", mapped.data);
|
|
2109
2170
|
};
|
|
2110
2171
|
const onError = (err) => {
|
|
2111
2172
|
channel.emit("error", err);
|
package/dist/index.d.mts
CHANGED
|
@@ -326,6 +326,39 @@ interface BidMeta {
|
|
|
326
326
|
/** Display pair, e.g. "ETH/USD". */
|
|
327
327
|
pairName: string;
|
|
328
328
|
}
|
|
329
|
+
/**
|
|
330
|
+
* The OHLC of a bid's cell window — what price did inside [time1, time2] on the bid's
|
|
331
|
+
* own pair, reduced from every stored tick covering it.
|
|
332
|
+
*
|
|
333
|
+
* Values are Decimal strings, not numbers: the archive stores 8 decimal places and
|
|
334
|
+
* parsing to a JS number here would round them before the UI ever sees them.
|
|
335
|
+
*/
|
|
336
|
+
interface BidCellCandle {
|
|
337
|
+
o: string;
|
|
338
|
+
h: string;
|
|
339
|
+
l: string;
|
|
340
|
+
c: string;
|
|
341
|
+
/**
|
|
342
|
+
* Whether the candle had CLOSED when it settled the bid.
|
|
343
|
+
*
|
|
344
|
+
* `false` = the values can still move: a 1m/5m win settles the instant the
|
|
345
|
+
* band is touched (the verdict is permanent) but the candle's O/C and extremes
|
|
346
|
+
* keep moving until it closes — delivered live over MQTT, and by `myBids` when
|
|
347
|
+
* the touching candle has not closed at read time. The UI shows such a value
|
|
348
|
+
* in the same not-yet-settled language the pending row uses. Absent (a server
|
|
349
|
+
* that predates the flag) means settled.
|
|
350
|
+
*/
|
|
351
|
+
final?: boolean;
|
|
352
|
+
/**
|
|
353
|
+
* The WINNING TICK (TH-146 "success ticker"): the unix SECOND at which price
|
|
354
|
+
* entered the bid's band, and the price inside the band it entered at — what
|
|
355
|
+
* the popover shows as "reached <price> at <time>". Both present or both
|
|
356
|
+
* absent: a bid that did not win has no single moment that won it, and a
|
|
357
|
+
* server predating the field sends neither.
|
|
358
|
+
*/
|
|
359
|
+
touchSec?: number;
|
|
360
|
+
touchPrice?: string;
|
|
361
|
+
}
|
|
329
362
|
interface Bid {
|
|
330
363
|
id: string;
|
|
331
364
|
userId: string;
|
|
@@ -363,6 +396,16 @@ interface Bid {
|
|
|
363
396
|
* display pair instead of mapping `pairId` yourself.
|
|
364
397
|
*/
|
|
365
398
|
meta?: BidMeta | null;
|
|
399
|
+
/**
|
|
400
|
+
* What price did inside this bid's cell window, served with the bid itself so a
|
|
401
|
+
* consumer never has to fetch it separately (openspec ux-260819-bid-detail-popover).
|
|
402
|
+
*
|
|
403
|
+
* Null in three cases a consumer should treat alike: the bid is still pending, its
|
|
404
|
+
* ticks are no longer stored, or the caller's query did not select the field. A
|
|
405
|
+
* cancelled bid DOES carry one — its window still elapsed — and the server attaches
|
|
406
|
+
* no verdict about what the outcome would have been.
|
|
407
|
+
*/
|
|
408
|
+
cellCandle?: BidCellCandle | null;
|
|
366
409
|
}
|
|
367
410
|
interface CancelBidResult {
|
|
368
411
|
bid: Bid;
|
|
@@ -1166,6 +1209,37 @@ interface MqttBidWonEvent {
|
|
|
1166
1209
|
payout: string;
|
|
1167
1210
|
userId: string;
|
|
1168
1211
|
balance?: string;
|
|
1212
|
+
/**
|
|
1213
|
+
* OHLC of the candle whose band touch declared this win — the bid's
|
|
1214
|
+
* `cellCandle`, shipped with the result so the client never has to refetch the
|
|
1215
|
+
* bid list to learn it (openspec ux-260819, revised D2e).
|
|
1216
|
+
*
|
|
1217
|
+
* Sent on live wins and on D10 recovery alike (recovery hands over the stored
|
|
1218
|
+
* candle whose touch it found). Absent only on any grid-api older than that
|
|
1219
|
+
* change.
|
|
1220
|
+
*/
|
|
1221
|
+
cellCandle?: {
|
|
1222
|
+
o: string;
|
|
1223
|
+
h: string;
|
|
1224
|
+
l: string;
|
|
1225
|
+
c: string;
|
|
1226
|
+
/**
|
|
1227
|
+
* Whether that candle had CLOSED when it settled the bid. A 1m/5m win settles
|
|
1228
|
+
* the instant the band is touched — safe, because a touch is permanent — but
|
|
1229
|
+
* the candle's O/C and extremes can still move until it closes. `false` means
|
|
1230
|
+
* the client must present the value as not-yet-settled rather than final.
|
|
1231
|
+
*/
|
|
1232
|
+
final: boolean;
|
|
1233
|
+
/**
|
|
1234
|
+
* The WINNING TICK (TH-146 "success ticker"): the unix SECOND at which price
|
|
1235
|
+
* entered the bid's band, and the price inside the band it entered at. The
|
|
1236
|
+
* engine's predicate is a range overlap, so this is neither the candle's
|
|
1237
|
+
* close nor a raw extreme. Both present or both absent — a server that
|
|
1238
|
+
* predates the field sends neither.
|
|
1239
|
+
*/
|
|
1240
|
+
touchSec?: number;
|
|
1241
|
+
touchPrice?: string;
|
|
1242
|
+
};
|
|
1169
1243
|
/**
|
|
1170
1244
|
* Pair the won bid belongs to, e.g. "grid-ETH-USD". Derived from the result
|
|
1171
1245
|
* topic (`game/{agencyId}:{pairId}/user/.../bid_result`) since the won payload
|
|
@@ -1175,6 +1249,38 @@ interface MqttBidWonEvent {
|
|
|
1175
1249
|
*/
|
|
1176
1250
|
pairId?: string;
|
|
1177
1251
|
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Follow-up patch grid-api publishes when the window of a building-candle win
|
|
1254
|
+
* closes (wire type `cell_candle_final`): the CLOSED o/h/l/c of the candle the
|
|
1255
|
+
* bid settled on, replacing the in-progress values the `bidWon` event carried
|
|
1256
|
+
* with `cellCandle.final: false` (openspec ux-260819, design D2g).
|
|
1257
|
+
*
|
|
1258
|
+
* A patch, not a result: consumers must only update the bid's stored candle —
|
|
1259
|
+
* never replay win side effects (sound, payout, balance).
|
|
1260
|
+
*/
|
|
1261
|
+
interface MqttCellCandleFinalEvent {
|
|
1262
|
+
bidId: string;
|
|
1263
|
+
userId: string;
|
|
1264
|
+
cellCandle: {
|
|
1265
|
+
o: string;
|
|
1266
|
+
h: string;
|
|
1267
|
+
l: string;
|
|
1268
|
+
c: string;
|
|
1269
|
+
/** Always true — the whole point of the event is that the candle closed. */
|
|
1270
|
+
final: boolean;
|
|
1271
|
+
/**
|
|
1272
|
+
* The WINNING TICK (TH-146 "success ticker"): the unix SECOND at which price
|
|
1273
|
+
* entered the bid's band, and the price inside the band it entered at. The
|
|
1274
|
+
* engine's predicate is a range overlap, so this is neither the candle's
|
|
1275
|
+
* close nor a raw extreme. Both present or both absent — a server that
|
|
1276
|
+
* predates the field sends neither.
|
|
1277
|
+
*/
|
|
1278
|
+
touchSec?: number;
|
|
1279
|
+
touchPrice?: string;
|
|
1280
|
+
};
|
|
1281
|
+
/** Pair the bid belongs to (see {@link MqttBidWonEvent.pairId}). */
|
|
1282
|
+
pairId?: string;
|
|
1283
|
+
}
|
|
1178
1284
|
interface MqttBidLostEvent {
|
|
1179
1285
|
bidId: string;
|
|
1180
1286
|
/** Pair the lost bid belongs to (see {@link MqttBidWonEvent.pairId}). */
|
|
@@ -1268,6 +1374,7 @@ interface GameChannelEvents {
|
|
|
1268
1374
|
bidAccepted: [MqttBidAcceptedEvent];
|
|
1269
1375
|
bidWon: [MqttBidWonEvent];
|
|
1270
1376
|
bidLost: [MqttBidLostEvent];
|
|
1377
|
+
cellCandleFinal: [MqttCellCandleFinalEvent];
|
|
1271
1378
|
bidCancelled: [MqttBidCancelledEvent];
|
|
1272
1379
|
balanceUpdate: [MqttBalanceEvent];
|
|
1273
1380
|
configUpdate: [MqttConfigEvent];
|
|
@@ -1298,6 +1405,7 @@ declare class MigrationChannel extends EventEmitter<MigrationChannelEvents> {
|
|
|
1298
1405
|
interface UserBidsChannelEvents {
|
|
1299
1406
|
bidWon: [MqttBidWonEvent];
|
|
1300
1407
|
bidLost: [MqttBidLostEvent];
|
|
1408
|
+
cellCandleFinal: [MqttCellCandleFinalEvent];
|
|
1301
1409
|
error: [Error];
|
|
1302
1410
|
}
|
|
1303
1411
|
/**
|
|
@@ -1848,4 +1956,4 @@ declare function computeBaseline(candleClose: number, candleTimeSec: number, cel
|
|
|
1848
1956
|
baselineTime: number;
|
|
1849
1957
|
};
|
|
1850
1958
|
|
|
1851
|
-
export { type AgencyPairFilter, AgencyPairModule, type AgencyPairStats, type AgencyPairStatus, AuthModule, type BackendHealth, type Bid, BidModule, type BidStatus, CANDLE_EVENT, type CancelBidResult, type Candle, type CandleEventType, type CoefficientInput, type Constraints, type Currency, DEFAULT_CHART_HISTORY_LIMIT, DEFAULT_PROBE_TTL_SECONDS, DEFAULT_REGION, type ErrorMessageCatalog, type ErrorMessageMeta, type ErrorMessagesResponse, GameChannel, type GameConfig, type GridConfig, KNOWN_REGIONS, type KnownRegion, type LeaderboardEntry, LeaderboardModule, type LeaderboardPeriod, type LeaderboardSortBy, LocaleModule, type LocaleRefreshResult, type LocaleResponse, type LocaleTranslations, type LoginResult, type Me, MigrationChannel, type MigrationChannelEvents, type MigrationCompletedEvent, type MqttAcceptedBid, type MqttAgencyPairStatsEvent, type MqttAuthConfig, type MqttBalanceEvent, type MqttBidAcceptedEvent, type MqttBidLostEvent, type MqttBidWonEvent, type MqttCandleEvent, type MqttConfigEvent, type MqttIdealConfigEvent, type MqttWalletBalanceEvent, type MyRank, type NetworkLevel, type NetworkQuality, NetworkQualityMonitor, type Pair, type PairInfo, PairModule, type PlaceBidInput, type ProbeNearestRegionOptions, REGION_PROBE_CACHE_KEY, type RankBoard, type RankEntry, type RankPeriod, type RankSort, RealtimeModule, type RefreshTokenResult, type RegionDomainMap, type Sample, type SampleReason, type SignalSource, type SortDir, TaphubAuthError, TaphubClient, type TaphubClientConfig, TaphubError, TaphubEventBus, type TaphubEventMap, TaphubNetworkError, TaphubServerError, TaphubSlippageError, TaphubStorage, type TaphubStorageAdapter, TaphubValidationError, type User, UserBidsChannel, type UserBidsChannelEvents, UserModule, type UserPnL, type UserPnLPeriod, type Wallet as UserWallet, type Wallet$1 as Wallet, type WalletBalanceReason, WalletChannel, adaptiveSimpson, autoDetectStorage, calculateCoefficientWrapper, calculateProbHit, calculateProbWin, calculateProbWin_v2, computeBaseline, errorFunction, isCancelled, isKnownRegion, isLoss, isPending, isTerminal, isWin, normalCDF, normalPDF, normaliseLang, pairIdFromBidResultTopic, probeNearestRegion, resolveRegionBaseUrl, roundCoefToSignificantDigits };
|
|
1959
|
+
export { type AgencyPairFilter, AgencyPairModule, type AgencyPairStats, type AgencyPairStatus, AuthModule, type BackendHealth, type Bid, type BidCellCandle, BidModule, type BidStatus, CANDLE_EVENT, type CancelBidResult, type Candle, type CandleEventType, type CoefficientInput, type Constraints, type Currency, DEFAULT_CHART_HISTORY_LIMIT, DEFAULT_PROBE_TTL_SECONDS, DEFAULT_REGION, type ErrorMessageCatalog, type ErrorMessageMeta, type ErrorMessagesResponse, GameChannel, type GameConfig, type GridConfig, KNOWN_REGIONS, type KnownRegion, type LeaderboardEntry, LeaderboardModule, type LeaderboardPeriod, type LeaderboardSortBy, LocaleModule, type LocaleRefreshResult, type LocaleResponse, type LocaleTranslations, type LoginResult, type Me, MigrationChannel, type MigrationChannelEvents, type MigrationCompletedEvent, type MqttAcceptedBid, type MqttAgencyPairStatsEvent, type MqttAuthConfig, type MqttBalanceEvent, type MqttBidAcceptedEvent, type MqttBidLostEvent, type MqttBidWonEvent, type MqttCandleEvent, type MqttCellCandleFinalEvent, type MqttConfigEvent, type MqttIdealConfigEvent, type MqttWalletBalanceEvent, type MyRank, type NetworkLevel, type NetworkQuality, NetworkQualityMonitor, type Pair, type PairInfo, PairModule, type PlaceBidInput, type ProbeNearestRegionOptions, REGION_PROBE_CACHE_KEY, type RankBoard, type RankEntry, type RankPeriod, type RankSort, RealtimeModule, type RefreshTokenResult, type RegionDomainMap, type Sample, type SampleReason, type SignalSource, type SortDir, TaphubAuthError, TaphubClient, type TaphubClientConfig, TaphubError, TaphubEventBus, type TaphubEventMap, TaphubNetworkError, TaphubServerError, TaphubSlippageError, TaphubStorage, type TaphubStorageAdapter, TaphubValidationError, type User, UserBidsChannel, type UserBidsChannelEvents, UserModule, type UserPnL, type UserPnLPeriod, type Wallet as UserWallet, type Wallet$1 as Wallet, type WalletBalanceReason, WalletChannel, adaptiveSimpson, autoDetectStorage, calculateCoefficientWrapper, calculateProbHit, calculateProbWin, calculateProbWin_v2, computeBaseline, errorFunction, isCancelled, isKnownRegion, isLoss, isPending, isTerminal, isWin, normalCDF, normalPDF, normaliseLang, pairIdFromBidResultTopic, probeNearestRegion, resolveRegionBaseUrl, roundCoefToSignificantDigits };
|
package/dist/index.d.ts
CHANGED
|
@@ -326,6 +326,39 @@ interface BidMeta {
|
|
|
326
326
|
/** Display pair, e.g. "ETH/USD". */
|
|
327
327
|
pairName: string;
|
|
328
328
|
}
|
|
329
|
+
/**
|
|
330
|
+
* The OHLC of a bid's cell window — what price did inside [time1, time2] on the bid's
|
|
331
|
+
* own pair, reduced from every stored tick covering it.
|
|
332
|
+
*
|
|
333
|
+
* Values are Decimal strings, not numbers: the archive stores 8 decimal places and
|
|
334
|
+
* parsing to a JS number here would round them before the UI ever sees them.
|
|
335
|
+
*/
|
|
336
|
+
interface BidCellCandle {
|
|
337
|
+
o: string;
|
|
338
|
+
h: string;
|
|
339
|
+
l: string;
|
|
340
|
+
c: string;
|
|
341
|
+
/**
|
|
342
|
+
* Whether the candle had CLOSED when it settled the bid.
|
|
343
|
+
*
|
|
344
|
+
* `false` = the values can still move: a 1m/5m win settles the instant the
|
|
345
|
+
* band is touched (the verdict is permanent) but the candle's O/C and extremes
|
|
346
|
+
* keep moving until it closes — delivered live over MQTT, and by `myBids` when
|
|
347
|
+
* the touching candle has not closed at read time. The UI shows such a value
|
|
348
|
+
* in the same not-yet-settled language the pending row uses. Absent (a server
|
|
349
|
+
* that predates the flag) means settled.
|
|
350
|
+
*/
|
|
351
|
+
final?: boolean;
|
|
352
|
+
/**
|
|
353
|
+
* The WINNING TICK (TH-146 "success ticker"): the unix SECOND at which price
|
|
354
|
+
* entered the bid's band, and the price inside the band it entered at — what
|
|
355
|
+
* the popover shows as "reached <price> at <time>". Both present or both
|
|
356
|
+
* absent: a bid that did not win has no single moment that won it, and a
|
|
357
|
+
* server predating the field sends neither.
|
|
358
|
+
*/
|
|
359
|
+
touchSec?: number;
|
|
360
|
+
touchPrice?: string;
|
|
361
|
+
}
|
|
329
362
|
interface Bid {
|
|
330
363
|
id: string;
|
|
331
364
|
userId: string;
|
|
@@ -363,6 +396,16 @@ interface Bid {
|
|
|
363
396
|
* display pair instead of mapping `pairId` yourself.
|
|
364
397
|
*/
|
|
365
398
|
meta?: BidMeta | null;
|
|
399
|
+
/**
|
|
400
|
+
* What price did inside this bid's cell window, served with the bid itself so a
|
|
401
|
+
* consumer never has to fetch it separately (openspec ux-260819-bid-detail-popover).
|
|
402
|
+
*
|
|
403
|
+
* Null in three cases a consumer should treat alike: the bid is still pending, its
|
|
404
|
+
* ticks are no longer stored, or the caller's query did not select the field. A
|
|
405
|
+
* cancelled bid DOES carry one — its window still elapsed — and the server attaches
|
|
406
|
+
* no verdict about what the outcome would have been.
|
|
407
|
+
*/
|
|
408
|
+
cellCandle?: BidCellCandle | null;
|
|
366
409
|
}
|
|
367
410
|
interface CancelBidResult {
|
|
368
411
|
bid: Bid;
|
|
@@ -1166,6 +1209,37 @@ interface MqttBidWonEvent {
|
|
|
1166
1209
|
payout: string;
|
|
1167
1210
|
userId: string;
|
|
1168
1211
|
balance?: string;
|
|
1212
|
+
/**
|
|
1213
|
+
* OHLC of the candle whose band touch declared this win — the bid's
|
|
1214
|
+
* `cellCandle`, shipped with the result so the client never has to refetch the
|
|
1215
|
+
* bid list to learn it (openspec ux-260819, revised D2e).
|
|
1216
|
+
*
|
|
1217
|
+
* Sent on live wins and on D10 recovery alike (recovery hands over the stored
|
|
1218
|
+
* candle whose touch it found). Absent only on any grid-api older than that
|
|
1219
|
+
* change.
|
|
1220
|
+
*/
|
|
1221
|
+
cellCandle?: {
|
|
1222
|
+
o: string;
|
|
1223
|
+
h: string;
|
|
1224
|
+
l: string;
|
|
1225
|
+
c: string;
|
|
1226
|
+
/**
|
|
1227
|
+
* Whether that candle had CLOSED when it settled the bid. A 1m/5m win settles
|
|
1228
|
+
* the instant the band is touched — safe, because a touch is permanent — but
|
|
1229
|
+
* the candle's O/C and extremes can still move until it closes. `false` means
|
|
1230
|
+
* the client must present the value as not-yet-settled rather than final.
|
|
1231
|
+
*/
|
|
1232
|
+
final: boolean;
|
|
1233
|
+
/**
|
|
1234
|
+
* The WINNING TICK (TH-146 "success ticker"): the unix SECOND at which price
|
|
1235
|
+
* entered the bid's band, and the price inside the band it entered at. The
|
|
1236
|
+
* engine's predicate is a range overlap, so this is neither the candle's
|
|
1237
|
+
* close nor a raw extreme. Both present or both absent — a server that
|
|
1238
|
+
* predates the field sends neither.
|
|
1239
|
+
*/
|
|
1240
|
+
touchSec?: number;
|
|
1241
|
+
touchPrice?: string;
|
|
1242
|
+
};
|
|
1169
1243
|
/**
|
|
1170
1244
|
* Pair the won bid belongs to, e.g. "grid-ETH-USD". Derived from the result
|
|
1171
1245
|
* topic (`game/{agencyId}:{pairId}/user/.../bid_result`) since the won payload
|
|
@@ -1175,6 +1249,38 @@ interface MqttBidWonEvent {
|
|
|
1175
1249
|
*/
|
|
1176
1250
|
pairId?: string;
|
|
1177
1251
|
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Follow-up patch grid-api publishes when the window of a building-candle win
|
|
1254
|
+
* closes (wire type `cell_candle_final`): the CLOSED o/h/l/c of the candle the
|
|
1255
|
+
* bid settled on, replacing the in-progress values the `bidWon` event carried
|
|
1256
|
+
* with `cellCandle.final: false` (openspec ux-260819, design D2g).
|
|
1257
|
+
*
|
|
1258
|
+
* A patch, not a result: consumers must only update the bid's stored candle —
|
|
1259
|
+
* never replay win side effects (sound, payout, balance).
|
|
1260
|
+
*/
|
|
1261
|
+
interface MqttCellCandleFinalEvent {
|
|
1262
|
+
bidId: string;
|
|
1263
|
+
userId: string;
|
|
1264
|
+
cellCandle: {
|
|
1265
|
+
o: string;
|
|
1266
|
+
h: string;
|
|
1267
|
+
l: string;
|
|
1268
|
+
c: string;
|
|
1269
|
+
/** Always true — the whole point of the event is that the candle closed. */
|
|
1270
|
+
final: boolean;
|
|
1271
|
+
/**
|
|
1272
|
+
* The WINNING TICK (TH-146 "success ticker"): the unix SECOND at which price
|
|
1273
|
+
* entered the bid's band, and the price inside the band it entered at. The
|
|
1274
|
+
* engine's predicate is a range overlap, so this is neither the candle's
|
|
1275
|
+
* close nor a raw extreme. Both present or both absent — a server that
|
|
1276
|
+
* predates the field sends neither.
|
|
1277
|
+
*/
|
|
1278
|
+
touchSec?: number;
|
|
1279
|
+
touchPrice?: string;
|
|
1280
|
+
};
|
|
1281
|
+
/** Pair the bid belongs to (see {@link MqttBidWonEvent.pairId}). */
|
|
1282
|
+
pairId?: string;
|
|
1283
|
+
}
|
|
1178
1284
|
interface MqttBidLostEvent {
|
|
1179
1285
|
bidId: string;
|
|
1180
1286
|
/** Pair the lost bid belongs to (see {@link MqttBidWonEvent.pairId}). */
|
|
@@ -1268,6 +1374,7 @@ interface GameChannelEvents {
|
|
|
1268
1374
|
bidAccepted: [MqttBidAcceptedEvent];
|
|
1269
1375
|
bidWon: [MqttBidWonEvent];
|
|
1270
1376
|
bidLost: [MqttBidLostEvent];
|
|
1377
|
+
cellCandleFinal: [MqttCellCandleFinalEvent];
|
|
1271
1378
|
bidCancelled: [MqttBidCancelledEvent];
|
|
1272
1379
|
balanceUpdate: [MqttBalanceEvent];
|
|
1273
1380
|
configUpdate: [MqttConfigEvent];
|
|
@@ -1298,6 +1405,7 @@ declare class MigrationChannel extends EventEmitter<MigrationChannelEvents> {
|
|
|
1298
1405
|
interface UserBidsChannelEvents {
|
|
1299
1406
|
bidWon: [MqttBidWonEvent];
|
|
1300
1407
|
bidLost: [MqttBidLostEvent];
|
|
1408
|
+
cellCandleFinal: [MqttCellCandleFinalEvent];
|
|
1301
1409
|
error: [Error];
|
|
1302
1410
|
}
|
|
1303
1411
|
/**
|
|
@@ -1848,4 +1956,4 @@ declare function computeBaseline(candleClose: number, candleTimeSec: number, cel
|
|
|
1848
1956
|
baselineTime: number;
|
|
1849
1957
|
};
|
|
1850
1958
|
|
|
1851
|
-
export { type AgencyPairFilter, AgencyPairModule, type AgencyPairStats, type AgencyPairStatus, AuthModule, type BackendHealth, type Bid, BidModule, type BidStatus, CANDLE_EVENT, type CancelBidResult, type Candle, type CandleEventType, type CoefficientInput, type Constraints, type Currency, DEFAULT_CHART_HISTORY_LIMIT, DEFAULT_PROBE_TTL_SECONDS, DEFAULT_REGION, type ErrorMessageCatalog, type ErrorMessageMeta, type ErrorMessagesResponse, GameChannel, type GameConfig, type GridConfig, KNOWN_REGIONS, type KnownRegion, type LeaderboardEntry, LeaderboardModule, type LeaderboardPeriod, type LeaderboardSortBy, LocaleModule, type LocaleRefreshResult, type LocaleResponse, type LocaleTranslations, type LoginResult, type Me, MigrationChannel, type MigrationChannelEvents, type MigrationCompletedEvent, type MqttAcceptedBid, type MqttAgencyPairStatsEvent, type MqttAuthConfig, type MqttBalanceEvent, type MqttBidAcceptedEvent, type MqttBidLostEvent, type MqttBidWonEvent, type MqttCandleEvent, type MqttConfigEvent, type MqttIdealConfigEvent, type MqttWalletBalanceEvent, type MyRank, type NetworkLevel, type NetworkQuality, NetworkQualityMonitor, type Pair, type PairInfo, PairModule, type PlaceBidInput, type ProbeNearestRegionOptions, REGION_PROBE_CACHE_KEY, type RankBoard, type RankEntry, type RankPeriod, type RankSort, RealtimeModule, type RefreshTokenResult, type RegionDomainMap, type Sample, type SampleReason, type SignalSource, type SortDir, TaphubAuthError, TaphubClient, type TaphubClientConfig, TaphubError, TaphubEventBus, type TaphubEventMap, TaphubNetworkError, TaphubServerError, TaphubSlippageError, TaphubStorage, type TaphubStorageAdapter, TaphubValidationError, type User, UserBidsChannel, type UserBidsChannelEvents, UserModule, type UserPnL, type UserPnLPeriod, type Wallet as UserWallet, type Wallet$1 as Wallet, type WalletBalanceReason, WalletChannel, adaptiveSimpson, autoDetectStorage, calculateCoefficientWrapper, calculateProbHit, calculateProbWin, calculateProbWin_v2, computeBaseline, errorFunction, isCancelled, isKnownRegion, isLoss, isPending, isTerminal, isWin, normalCDF, normalPDF, normaliseLang, pairIdFromBidResultTopic, probeNearestRegion, resolveRegionBaseUrl, roundCoefToSignificantDigits };
|
|
1959
|
+
export { type AgencyPairFilter, AgencyPairModule, type AgencyPairStats, type AgencyPairStatus, AuthModule, type BackendHealth, type Bid, type BidCellCandle, BidModule, type BidStatus, CANDLE_EVENT, type CancelBidResult, type Candle, type CandleEventType, type CoefficientInput, type Constraints, type Currency, DEFAULT_CHART_HISTORY_LIMIT, DEFAULT_PROBE_TTL_SECONDS, DEFAULT_REGION, type ErrorMessageCatalog, type ErrorMessageMeta, type ErrorMessagesResponse, GameChannel, type GameConfig, type GridConfig, KNOWN_REGIONS, type KnownRegion, type LeaderboardEntry, LeaderboardModule, type LeaderboardPeriod, type LeaderboardSortBy, LocaleModule, type LocaleRefreshResult, type LocaleResponse, type LocaleTranslations, type LoginResult, type Me, MigrationChannel, type MigrationChannelEvents, type MigrationCompletedEvent, type MqttAcceptedBid, type MqttAgencyPairStatsEvent, type MqttAuthConfig, type MqttBalanceEvent, type MqttBidAcceptedEvent, type MqttBidLostEvent, type MqttBidWonEvent, type MqttCandleEvent, type MqttCellCandleFinalEvent, type MqttConfigEvent, type MqttIdealConfigEvent, type MqttWalletBalanceEvent, type MyRank, type NetworkLevel, type NetworkQuality, NetworkQualityMonitor, type Pair, type PairInfo, PairModule, type PlaceBidInput, type ProbeNearestRegionOptions, REGION_PROBE_CACHE_KEY, type RankBoard, type RankEntry, type RankPeriod, type RankSort, RealtimeModule, type RefreshTokenResult, type RegionDomainMap, type Sample, type SampleReason, type SignalSource, type SortDir, TaphubAuthError, TaphubClient, type TaphubClientConfig, TaphubError, TaphubEventBus, type TaphubEventMap, TaphubNetworkError, TaphubServerError, TaphubSlippageError, TaphubStorage, type TaphubStorageAdapter, TaphubValidationError, type User, UserBidsChannel, type UserBidsChannelEvents, UserModule, type UserPnL, type UserPnLPeriod, type Wallet as UserWallet, type Wallet$1 as Wallet, type WalletBalanceReason, WalletChannel, adaptiveSimpson, autoDetectStorage, calculateCoefficientWrapper, calculateProbHit, calculateProbWin, calculateProbWin_v2, computeBaseline, errorFunction, isCancelled, isKnownRegion, isLoss, isPending, isTerminal, isWin, normalCDF, normalPDF, normaliseLang, pairIdFromBidResultTopic, probeNearestRegion, resolveRegionBaseUrl, roundCoefToSignificantDigits };
|
package/dist/index.js
CHANGED
|
@@ -581,7 +581,22 @@ function normaliseBid(node) {
|
|
|
581
581
|
refundAmount: node.refund_amount ?? null,
|
|
582
582
|
slippage: node.slippage,
|
|
583
583
|
createdAt: node.created_at || null,
|
|
584
|
-
meta: parseMeta(node.meta)
|
|
584
|
+
meta: parseMeta(node.meta),
|
|
585
|
+
// Absent and explicit null both mean "no candle" — an older server, an unselected
|
|
586
|
+
// field, a pending bid and purged ticks must all read the same to a consumer.
|
|
587
|
+
// `final` null (nullable Boolean) collapses to absent = settled, so only a real
|
|
588
|
+
// `false` puts the row in the in-progress presentation.
|
|
589
|
+
cellCandle: node.cellCandle ? {
|
|
590
|
+
o: node.cellCandle.o,
|
|
591
|
+
h: node.cellCandle.h,
|
|
592
|
+
l: node.cellCandle.l,
|
|
593
|
+
c: node.cellCandle.c,
|
|
594
|
+
...typeof node.cellCandle.final === "boolean" ? { final: node.cellCandle.final } : {},
|
|
595
|
+
// Both legs or neither — see BidCellCandle.touchSec. Nulls (a non-win,
|
|
596
|
+
// or an older server) collapse to absent so a consumer only has to
|
|
597
|
+
// check one of them.
|
|
598
|
+
...typeof node.cellCandle.touchSec === "number" && typeof node.cellCandle.touchPrice === "string" ? { touchSec: node.cellCandle.touchSec, touchPrice: node.cellCandle.touchPrice } : {}
|
|
599
|
+
} : null
|
|
585
600
|
};
|
|
586
601
|
}
|
|
587
602
|
function normaliseBids(list) {
|
|
@@ -602,6 +617,7 @@ var PLACE_BID_MUTATION = `mutation PlaceBid($input: PlaceBidInput!) {
|
|
|
602
617
|
var MY_BIDS_QUERY = `query MyBids($statuses: [BidStatus!], $limit: Int, $offset: Int, $pairId: ID) {
|
|
603
618
|
myBids(statuses: $statuses, limit: $limit, offset: $offset, pairId: $pairId) {
|
|
604
619
|
id user_id pair_id currency amount coefficient time1 time2 price1 price2 status payout refund_rate refund_amount slippage created_at meta
|
|
620
|
+
cellCandle { o h l c final touchSec touchPrice }
|
|
605
621
|
}
|
|
606
622
|
}`;
|
|
607
623
|
var CANCEL_BID_MUTATION = `mutation CancelBid($input: CancelBidInput!) {
|
|
@@ -1769,6 +1785,23 @@ function mapWireBidResult(raw, topicPairId) {
|
|
|
1769
1785
|
userId: p.user_id
|
|
1770
1786
|
};
|
|
1771
1787
|
if (typeof p.balance === "string") data.balance = p.balance;
|
|
1788
|
+
const candle = p.cellCandle;
|
|
1789
|
+
if (candle && typeof candle.o === "string" && typeof candle.h === "string" && typeof candle.l === "string" && typeof candle.c === "string") {
|
|
1790
|
+
data.cellCandle = {
|
|
1791
|
+
o: candle.o,
|
|
1792
|
+
h: candle.h,
|
|
1793
|
+
l: candle.l,
|
|
1794
|
+
c: candle.c,
|
|
1795
|
+
final: candle.final !== "false"
|
|
1796
|
+
};
|
|
1797
|
+
if (typeof candle.touchSec === "string" && typeof candle.touchPrice === "string") {
|
|
1798
|
+
const touchSec = Number.parseInt(candle.touchSec, 10);
|
|
1799
|
+
if (Number.isFinite(touchSec)) {
|
|
1800
|
+
data.cellCandle.touchSec = touchSec;
|
|
1801
|
+
data.cellCandle.touchPrice = candle.touchPrice;
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1772
1805
|
if (topicPairId !== void 0) data.pairId = topicPairId;
|
|
1773
1806
|
return { event: "bidWon", data };
|
|
1774
1807
|
}
|
|
@@ -1777,6 +1810,32 @@ function mapWireBidResult(raw, topicPairId) {
|
|
|
1777
1810
|
if (topicPairId !== void 0) data.pairId = topicPairId;
|
|
1778
1811
|
return { event: "bidLost", data };
|
|
1779
1812
|
}
|
|
1813
|
+
case "cell_candle_final": {
|
|
1814
|
+
const candle = p.cellCandle;
|
|
1815
|
+
if (!candle || typeof candle.o !== "string" || typeof candle.h !== "string" || typeof candle.l !== "string" || typeof candle.c !== "string") {
|
|
1816
|
+
return null;
|
|
1817
|
+
}
|
|
1818
|
+
const data = {
|
|
1819
|
+
bidId: p.bidId,
|
|
1820
|
+
userId: p.user_id,
|
|
1821
|
+
cellCandle: {
|
|
1822
|
+
o: candle.o,
|
|
1823
|
+
h: candle.h,
|
|
1824
|
+
l: candle.l,
|
|
1825
|
+
c: candle.c,
|
|
1826
|
+
final: candle.final !== "false"
|
|
1827
|
+
}
|
|
1828
|
+
};
|
|
1829
|
+
if (typeof candle.touchSec === "string" && typeof candle.touchPrice === "string") {
|
|
1830
|
+
const touchSec = Number.parseInt(candle.touchSec, 10);
|
|
1831
|
+
if (Number.isFinite(touchSec)) {
|
|
1832
|
+
data.cellCandle.touchSec = touchSec;
|
|
1833
|
+
data.cellCandle.touchPrice = candle.touchPrice;
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
if (topicPairId !== void 0) data.pairId = topicPairId;
|
|
1837
|
+
return { event: "cellCandleFinal", data };
|
|
1838
|
+
}
|
|
1780
1839
|
default:
|
|
1781
1840
|
console.warn(`Unknown bid_result type "${String(p.type)}"`);
|
|
1782
1841
|
return null;
|
|
@@ -1894,6 +1953,7 @@ var RealtimeModule = class extends EventEmitter5 {
|
|
|
1894
1953
|
else if (mapped.event === "bidAccepted") channel.emit("bidAccepted", mapped.data);
|
|
1895
1954
|
else if (mapped.event === "bidWon") channel.emit("bidWon", mapped.data);
|
|
1896
1955
|
else if (mapped.event === "bidLost") channel.emit("bidLost", mapped.data);
|
|
1956
|
+
else if (mapped.event === "cellCandleFinal") channel.emit("cellCandleFinal", mapped.data);
|
|
1897
1957
|
else if (mapped.event === "balanceUpdate") channel.emit("balanceUpdate", mapped.data);
|
|
1898
1958
|
else if (mapped.event === "configUpdate") channel.emit("configUpdate", mapped.data);
|
|
1899
1959
|
else if (mapped.event === "idealConfigUpdate")
|
|
@@ -2026,6 +2086,7 @@ var RealtimeModule = class extends EventEmitter5 {
|
|
|
2026
2086
|
if (!mapped) return;
|
|
2027
2087
|
if (mapped.event === "bidWon") channel.emit("bidWon", mapped.data);
|
|
2028
2088
|
else if (mapped.event === "bidLost") channel.emit("bidLost", mapped.data);
|
|
2089
|
+
else if (mapped.event === "cellCandleFinal") channel.emit("cellCandleFinal", mapped.data);
|
|
2029
2090
|
};
|
|
2030
2091
|
const onError = (err) => {
|
|
2031
2092
|
channel.emit("error", err);
|