@liberfi.io/react-predict 0.3.70 → 0.3.72

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/dist/index.js CHANGED
@@ -7,6 +7,21 @@ var reactQuery = require('@tanstack/react-query');
7
7
  var clobClientV2 = require('@polymarket/clob-client-v2');
8
8
 
9
9
  // src/client/client.ts
10
+
11
+ // src/client/types.ts
12
+ var MARKET_STRUCTURE_MEDIA_TYPE_V1 = "application/vnd.liberfi.market-structure+json;v=1";
13
+
14
+ // src/client/client.ts
15
+ var MarketDataHttpError = class extends Error {
16
+ constructor(message, status, code, retryAfter, body) {
17
+ super(message);
18
+ this.status = status;
19
+ this.code = code;
20
+ this.retryAfter = retryAfter;
21
+ this.body = body;
22
+ }
23
+ name = "MarketDataHttpError";
24
+ };
10
25
  function buildQuery(params) {
11
26
  const qs = new URLSearchParams();
12
27
  for (const [key, value] of Object.entries(params)) {
@@ -33,6 +48,26 @@ var PredictClient = class {
33
48
  }
34
49
  };
35
50
  }
51
+ async marketDataRequest(path, options) {
52
+ const response = await fetch(
53
+ `${this.endpoint}${path}`,
54
+ this.requestOptions(options)
55
+ );
56
+ if (response.ok) {
57
+ return await response.json();
58
+ }
59
+ const body = await parseMarketDataResponseBody(response);
60
+ const record = isRecord(body) ? body : void 0;
61
+ const code = typeof record?.error === "string" ? record.error : typeof record?.code === "string" ? record.code : void 0;
62
+ const message = typeof record?.message === "string" ? record.message : code ?? response.statusText ?? `HTTP ${response.status}`;
63
+ throw new MarketDataHttpError(
64
+ message,
65
+ response.status,
66
+ code,
67
+ response.headers.get("Retry-After") ?? void 0,
68
+ body
69
+ );
70
+ }
36
71
  // -------------------------------------------------------------------------
37
72
  // Events
38
73
  // -------------------------------------------------------------------------
@@ -167,6 +202,85 @@ var PredictClient = class {
167
202
  // -------------------------------------------------------------------------
168
203
  // Markets
169
204
  // -------------------------------------------------------------------------
205
+ /** Register or refresh the complete provider-neutral market-data demand set. */
206
+ async watchMarketData(request) {
207
+ return await this.marketDataRequest(
208
+ "/api/v1/market-data/watch",
209
+ {
210
+ method: "POST",
211
+ headers: { "Content-Type": "application/json" },
212
+ body: JSON.stringify(request)
213
+ }
214
+ );
215
+ }
216
+ /** Read cache-only quote snapshots for at most 500 provider-neutral keys. */
217
+ async getMarketDataQuotes(markets) {
218
+ if (markets.length > 500) {
219
+ throw new RangeError(
220
+ "market data quote request accepts at most 500 markets"
221
+ );
222
+ }
223
+ return await this.marketDataRequest(
224
+ "/api/v1/markets/quotes",
225
+ {
226
+ method: "POST",
227
+ cache: "no-store",
228
+ headers: { "Content-Type": "application/json" },
229
+ body: JSON.stringify({ markets })
230
+ }
231
+ );
232
+ }
233
+ /** Read all cached Top20 outcome books for one provider-neutral market. */
234
+ async getMarketDataOrderbooks(slug, source) {
235
+ const path = `/api/v1/markets/${encodeURIComponent(slug)}/orderbooks` + buildQuery({ source });
236
+ return await this.marketDataRequest(path, {
237
+ method: "GET",
238
+ cache: "no-store"
239
+ });
240
+ }
241
+ /**
242
+ * Revalidate a page's allowlist-only structure representation.
243
+ *
244
+ * The path must remain inside the prediction API so callers cannot turn a
245
+ * configured authenticated client into a cross-origin request primitive.
246
+ */
247
+ async getMarketStructure(path, ifNoneMatch) {
248
+ if (!path.startsWith("/api/v1/")) {
249
+ throw new TypeError("market structure path must start with /api/v1/");
250
+ }
251
+ const response = await fetch(
252
+ `${this.endpoint}${path}`,
253
+ this.requestOptions({
254
+ method: "GET",
255
+ cache: "no-store",
256
+ headers: {
257
+ Accept: MARKET_STRUCTURE_MEDIA_TYPE_V1,
258
+ ...ifNoneMatch ? { "If-None-Match": ifNoneMatch } : {}
259
+ }
260
+ })
261
+ );
262
+ const etag = response.headers.get("ETag") ?? "";
263
+ if (response.status === 304) {
264
+ return { status: 304, etag };
265
+ }
266
+ if (response.ok) {
267
+ return {
268
+ status: 200,
269
+ etag,
270
+ body: await response.json()
271
+ };
272
+ }
273
+ const body = await parseMarketDataResponseBody(response);
274
+ const record = isRecord(body) ? body : void 0;
275
+ const code = typeof record?.error === "string" ? record.error : void 0;
276
+ throw new MarketDataHttpError(
277
+ typeof record?.message === "string" ? record.message : code ?? response.statusText,
278
+ response.status,
279
+ code,
280
+ response.headers.get("Retry-After") ?? void 0,
281
+ body
282
+ );
283
+ }
170
284
  /**
171
285
  * Fetch a single prediction market by its slug.
172
286
  *
@@ -636,6 +750,18 @@ var PredictClient = class {
636
750
  function createPredictClient(endpoint, options) {
637
751
  return new PredictClient(endpoint, options);
638
752
  }
753
+ async function parseMarketDataResponseBody(response) {
754
+ const text = await response.text().catch(() => "");
755
+ if (!text) return void 0;
756
+ try {
757
+ return JSON.parse(text);
758
+ } catch {
759
+ return void 0;
760
+ }
761
+ }
762
+ function isRecord(value) {
763
+ return typeof value === "object" && value !== null && !Array.isArray(value);
764
+ }
639
765
 
640
766
  // src/client/ws.ts
641
767
  var DEFAULT_RECONNECT_BASE = 1e3;
@@ -949,19 +1075,19 @@ var PredictWsClient = class {
949
1075
  JSON.stringify({ type, channels, market_slugs: [] })
950
1076
  );
951
1077
  const budget = MAX_SUBSCRIPTION_FRAME_BYTES - envelopeBytes;
952
- let chunk = [];
1078
+ let chunk2 = [];
953
1079
  let chunkBytes = 0;
954
1080
  const flush = () => {
955
- if (chunk.length > 0) {
956
- this.send({ type, channels, market_slugs: chunk });
957
- chunk = [];
1081
+ if (chunk2.length > 0) {
1082
+ this.send({ type, channels, market_slugs: chunk2 });
1083
+ chunk2 = [];
958
1084
  chunkBytes = 0;
959
1085
  }
960
1086
  };
961
1087
  for (const slug of marketSlugs) {
962
1088
  const slugBytes = byteLength(JSON.stringify(slug)) + 1;
963
- if (chunk.length > 0 && chunkBytes + slugBytes > budget) flush();
964
- chunk.push(slug);
1089
+ if (chunk2.length > 0 && chunkBytes + slugBytes > budget) flush();
1090
+ chunk2.push(slug);
965
1091
  chunkBytes += slugBytes;
966
1092
  }
967
1093
  flush();
@@ -1004,6 +1130,1258 @@ var PredictWsClient = class {
1004
1130
  function createPredictWsClient(config) {
1005
1131
  return new PredictWsClient(config);
1006
1132
  }
1133
+
1134
+ // src/market-data/contract.ts
1135
+ var MARKET_DATA_BACKEND_CONTRACT_COMMIT = "0d0bab5c38dda76658890395bd992de84477267a";
1136
+ var MARKET_DATA_CONTRACT_MANIFEST_SHA256 = "81c503ed6f1bb5b6f8f20ff9f448549d0b89553b36dbc422d09c3e4a898e4aaf";
1137
+
1138
+ // src/market-data/initialQuote.ts
1139
+ function parseInitialQuotes(input, structure) {
1140
+ if (input === void 0) return { kind: "missing" };
1141
+ try {
1142
+ validateInitialQuotes(input, structure);
1143
+ return { kind: "valid", value: input };
1144
+ } catch (error) {
1145
+ return {
1146
+ kind: "malformed",
1147
+ reason: error instanceof Error ? error.message : "invalid initial_quotes"
1148
+ };
1149
+ }
1150
+ }
1151
+ function validateInitialQuotes(input, structure) {
1152
+ const root = requireRecord(input, "initial_quotes");
1153
+ if (root.schema_version !== 1) {
1154
+ throw new Error("initial_quotes schema_version must be 1");
1155
+ }
1156
+ const markets = requireArray(root.markets, "initial_quotes markets");
1157
+ if (markets.length !== structure.length) {
1158
+ throw new Error("initial_quotes markets must match structural markets");
1159
+ }
1160
+ const structuralMarkets = new Map(
1161
+ structure.map((market) => [
1162
+ marketIdentity(market.source, market.market_slug),
1163
+ market
1164
+ ])
1165
+ );
1166
+ if (structuralMarkets.size !== structure.length) {
1167
+ throw new Error("structural markets must have unique identities");
1168
+ }
1169
+ const seenMarkets = /* @__PURE__ */ new Set();
1170
+ markets.forEach((marketValue, marketIndex) => {
1171
+ const market = requireRecord(
1172
+ marketValue,
1173
+ `initial_quotes market ${marketIndex}`
1174
+ );
1175
+ if (typeof market.source !== "string" || typeof market.market_slug !== "string") {
1176
+ throw new Error(
1177
+ `initial_quotes market ${marketIndex} requires source and market_slug`
1178
+ );
1179
+ }
1180
+ const identity = marketIdentity(market.source, market.market_slug);
1181
+ const structuralMarket = structuralMarkets.get(identity);
1182
+ if (!structuralMarket || seenMarkets.has(identity)) {
1183
+ throw new Error(
1184
+ `initial_quotes market ${marketIndex} must match structural market`
1185
+ );
1186
+ }
1187
+ seenMarkets.add(identity);
1188
+ if (typeof market.realtime_supported !== "boolean") {
1189
+ throw new Error(
1190
+ `initial_quotes market ${marketIndex} requires realtime_supported`
1191
+ );
1192
+ }
1193
+ const outcomes = requireArray(
1194
+ market.outcomes,
1195
+ `initial_quotes market ${marketIndex} outcomes`
1196
+ );
1197
+ if (outcomes.length !== structuralMarket.outcomes.length) {
1198
+ throw new Error(
1199
+ `initial_quotes market ${marketIndex} outcomes must match structure`
1200
+ );
1201
+ }
1202
+ const structuralOutcomes = new Set(structuralMarket.outcomes);
1203
+ if (structuralOutcomes.size !== structuralMarket.outcomes.length) {
1204
+ throw new Error(
1205
+ `structural market ${marketIndex} outcomes must have unique identities`
1206
+ );
1207
+ }
1208
+ const seenOutcomes = /* @__PURE__ */ new Set();
1209
+ outcomes.forEach((outcomeValue, outcomeIndex) => {
1210
+ const outcome = requireRecord(
1211
+ outcomeValue,
1212
+ `initial_quotes market ${marketIndex} outcome ${outcomeIndex}`
1213
+ );
1214
+ if (outcome.source !== structuralMarket.source || outcome.market_slug !== structuralMarket.market_slug || typeof outcome.outcome !== "string" || !structuralOutcomes.has(outcome.outcome) || seenOutcomes.has(outcome.outcome)) {
1215
+ throw new Error(
1216
+ `initial_quotes market ${marketIndex} outcome ${outcomeIndex} must match structure`
1217
+ );
1218
+ }
1219
+ seenOutcomes.add(outcome.outcome);
1220
+ assertMarketDataBBAComponent(
1221
+ outcome.bba,
1222
+ `initial_quotes market ${marketIndex} outcome ${outcomeIndex} bba`
1223
+ );
1224
+ assertMarketDataValueComponent(
1225
+ outcome.last_trade,
1226
+ `initial_quotes market ${marketIndex} outcome ${outcomeIndex} last_trade`,
1227
+ false
1228
+ );
1229
+ assertMarketDataValueComponent(
1230
+ outcome.tick_size,
1231
+ `initial_quotes market ${marketIndex} outcome ${outcomeIndex} tick_size`,
1232
+ true
1233
+ );
1234
+ if (!market.realtime_supported && (outcome.bba.available || outcome.last_trade.available || outcome.tick_size.available)) {
1235
+ throw new Error(
1236
+ `unsupported initial_quotes market ${marketIndex} must be unavailable`
1237
+ );
1238
+ }
1239
+ });
1240
+ });
1241
+ }
1242
+ function marketIdentity(source, marketSlug) {
1243
+ return `${source}\0${marketSlug}`;
1244
+ }
1245
+ function assertMarketDataBBAComponent(input, name) {
1246
+ const component = requireRecord(input, name);
1247
+ if (typeof component.available !== "boolean" || typeof component.empty !== "boolean") {
1248
+ throw new Error(`${name} requires available and empty`);
1249
+ }
1250
+ validateTimestampFields(component, name);
1251
+ if (!component.available) {
1252
+ if (component.empty || component.best_bid !== void 0 || component.best_ask !== void 0 || component.midpoint !== void 0) {
1253
+ throw new Error(`${name} unavailable component must omit quote values`);
1254
+ }
1255
+ return;
1256
+ }
1257
+ requireObservedAt(component, name);
1258
+ if (component.empty) {
1259
+ if (component.best_bid !== void 0 || component.best_ask !== void 0 || component.midpoint !== void 0) {
1260
+ throw new Error(`${name} empty component must omit quote values`);
1261
+ }
1262
+ return;
1263
+ }
1264
+ const bid = optionalProbability(component.best_bid, `${name} best_bid`);
1265
+ const ask = optionalProbability(component.best_ask, `${name} best_ask`);
1266
+ const midpoint = optionalProbability(component.midpoint, `${name} midpoint`);
1267
+ if (bid === void 0 && ask === void 0) {
1268
+ throw new Error(`${name} non-empty component requires a bid or ask`);
1269
+ }
1270
+ if (bid !== void 0 && ask !== void 0) {
1271
+ if (bid >= ask) throw new Error(`${name} best bid must be lower than ask`);
1272
+ if (midpoint === void 0 || Math.abs(midpoint - (bid + ask) / 2) > 1e-12) {
1273
+ throw new Error(`${name} midpoint must match bid and ask`);
1274
+ }
1275
+ } else if (midpoint !== void 0) {
1276
+ throw new Error(`${name} midpoint requires bid and ask`);
1277
+ }
1278
+ }
1279
+ function assertMarketDataValueComponent(input, name, positive) {
1280
+ const component = requireRecord(input, name);
1281
+ if (typeof component.available !== "boolean") {
1282
+ throw new Error(`${name} requires available`);
1283
+ }
1284
+ validateTimestampFields(component, name);
1285
+ if (!component.available) {
1286
+ if (component.value !== void 0) {
1287
+ throw new Error(`${name} unavailable component must omit value`);
1288
+ }
1289
+ return;
1290
+ }
1291
+ const value = optionalProbability(component.value, `${name} value`);
1292
+ if (value === void 0) throw new Error(`${name} requires value`);
1293
+ if (positive && value === 0) throw new Error(`${name} must be positive`);
1294
+ requireObservedAt(component, name);
1295
+ }
1296
+ function validateTimestampFields(component, name) {
1297
+ if (component.provider_timestamp !== void 0 && !isRFC3339(component.provider_timestamp)) {
1298
+ throw new Error(`${name} provider_timestamp must be RFC3339`);
1299
+ }
1300
+ if (component.observed_at !== void 0 && !isRFC3339(component.observed_at)) {
1301
+ throw new Error(`${name} observed_at must be RFC3339`);
1302
+ }
1303
+ if (component.provider_timestamp !== void 0 && component.observed_at === void 0) {
1304
+ throw new Error(`${name} provider_timestamp requires observed_at`);
1305
+ }
1306
+ }
1307
+ function requireObservedAt(component, name) {
1308
+ if (!isRFC3339(component.observed_at)) {
1309
+ throw new Error(`${name} available component requires observed_at`);
1310
+ }
1311
+ }
1312
+ function optionalProbability(value, name) {
1313
+ if (value === void 0) return void 0;
1314
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
1315
+ throw new Error(`${name} must be a finite probability`);
1316
+ }
1317
+ return value;
1318
+ }
1319
+ function isRFC3339(value) {
1320
+ return typeof value === "string" && value.length > 0 && Number.isFinite(Date.parse(value));
1321
+ }
1322
+ function requireRecord(value, name) {
1323
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
1324
+ throw new Error(`${name} must be an object`);
1325
+ }
1326
+ return value;
1327
+ }
1328
+ function requireArray(value, name) {
1329
+ if (!Array.isArray(value)) throw new Error(`${name} must be an array`);
1330
+ return value;
1331
+ }
1332
+
1333
+ // src/market-data/protocol.ts
1334
+ function comparePublicationCursor(candidate, current) {
1335
+ if (candidate.generation < current.generation) return "older";
1336
+ if (candidate.generation > current.generation) return "newer_generation";
1337
+ if (candidate.epoch !== current.epoch) return "epoch_changed";
1338
+ if (candidate.offset < current.offset) return "older";
1339
+ if (candidate.offset > current.offset) return "newer";
1340
+ return "same";
1341
+ }
1342
+ function decodeItemEnvelope(input) {
1343
+ const root = asRecord(input);
1344
+ if (root?.schema_version !== 1) {
1345
+ return failure("incompatible_schema", "item schema_version must be 1");
1346
+ }
1347
+ try {
1348
+ const changes = root.changes === void 0 ? void 0 : requireArray2(root.changes, "changes").map(decodeItemChange);
1349
+ const invalidation = root.resource_invalidated === void 0 ? void 0 : decodeInvalidation(root.resource_invalidated);
1350
+ if ((!changes || changes.length === 0) && !invalidation) {
1351
+ throw new Error("item envelope requires changes or invalidation");
1352
+ }
1353
+ return {
1354
+ ok: true,
1355
+ value: {
1356
+ schema_version: 1,
1357
+ ...changes ? { changes } : {},
1358
+ ...invalidation ? { resource_invalidated: invalidation } : {}
1359
+ }
1360
+ };
1361
+ } catch (error) {
1362
+ return failure(
1363
+ "malformed",
1364
+ error instanceof Error ? error.message : "malformed item envelope"
1365
+ );
1366
+ }
1367
+ }
1368
+ function decodeBookEnvelope(input) {
1369
+ const root = asRecord(input);
1370
+ if (root?.schema_version !== 1) {
1371
+ return failure("incompatible_schema", "book schema_version must be 1");
1372
+ }
1373
+ try {
1374
+ const source = requireSource(root.source);
1375
+ const marketSlug = requireIdentity(root.market_slug, "market_slug");
1376
+ const outcome = requireIdentity(root.outcome, "outcome");
1377
+ const observedAt = requireTimestamp(root.observed_at, "observed_at");
1378
+ if (typeof root.available !== "boolean") {
1379
+ throw new Error("book available must be boolean");
1380
+ }
1381
+ const providerTimestamp = root.provider_timestamp === void 0 ? void 0 : requireTimestamp(root.provider_timestamp, "provider_timestamp");
1382
+ if (!root.available) {
1383
+ if (root.bids !== void 0 || root.asks !== void 0) {
1384
+ throw new Error("unavailable book must omit levels");
1385
+ }
1386
+ return {
1387
+ ok: true,
1388
+ value: {
1389
+ schema_version: 1,
1390
+ available: false,
1391
+ source,
1392
+ market_slug: marketSlug,
1393
+ outcome,
1394
+ observed_at: observedAt,
1395
+ ...providerTimestamp ? { provider_timestamp: providerTimestamp } : {}
1396
+ }
1397
+ };
1398
+ }
1399
+ const bids = decodeBookLevels(root.bids, "bids");
1400
+ const asks = decodeBookLevels(root.asks, "asks");
1401
+ return {
1402
+ ok: true,
1403
+ value: {
1404
+ schema_version: 1,
1405
+ available: true,
1406
+ source,
1407
+ market_slug: marketSlug,
1408
+ outcome,
1409
+ observed_at: observedAt,
1410
+ bids,
1411
+ asks,
1412
+ ...providerTimestamp ? { provider_timestamp: providerTimestamp } : {}
1413
+ }
1414
+ };
1415
+ } catch (error) {
1416
+ return failure(
1417
+ "malformed",
1418
+ error instanceof Error ? error.message : "malformed book envelope"
1419
+ );
1420
+ }
1421
+ }
1422
+ function decodeItemChange(value) {
1423
+ const change = requireRecord2(value, "change");
1424
+ const source = requireSource(change.source);
1425
+ const marketSlug = requireIdentity(change.market_slug, "market_slug");
1426
+ const outcome = requireIdentity(change.outcome, "outcome");
1427
+ const decoded = {
1428
+ source,
1429
+ market_slug: marketSlug,
1430
+ outcome
1431
+ };
1432
+ if (change.bba !== void 0) {
1433
+ assertMarketDataBBAComponent(change.bba, "bba");
1434
+ decoded.bba = change.bba;
1435
+ }
1436
+ if (change.last_trade !== void 0) {
1437
+ assertMarketDataValueComponent(change.last_trade, "last_trade", false);
1438
+ decoded.last_trade = change.last_trade;
1439
+ }
1440
+ if (change.tick_size !== void 0) {
1441
+ assertMarketDataValueComponent(change.tick_size, "tick_size", true);
1442
+ decoded.tick_size = change.tick_size;
1443
+ }
1444
+ if (change.market_status !== void 0) {
1445
+ decoded.market_status = decodeStatus(change.market_status);
1446
+ }
1447
+ if (decoded.bba === void 0 && decoded.last_trade === void 0 && decoded.tick_size === void 0 && decoded.market_status === void 0) {
1448
+ throw new Error("item change requires a component replacement");
1449
+ }
1450
+ return decoded;
1451
+ }
1452
+ function decodeStatus(value) {
1453
+ const status = requireRecord2(value, "market_status");
1454
+ if (status.value !== "pending" && status.value !== "open" && status.value !== "closed" && status.value !== "voided") {
1455
+ throw new Error("unsupported market_status");
1456
+ }
1457
+ return {
1458
+ value: status.value,
1459
+ observed_at: requireTimestamp(
1460
+ status.observed_at,
1461
+ "market_status observed_at"
1462
+ )
1463
+ };
1464
+ }
1465
+ function decodeInvalidation(value) {
1466
+ const invalidation = requireRecord2(value, "resource_invalidated");
1467
+ if (invalidation.reason !== "market_membership_changed") {
1468
+ throw new Error("unsupported invalidation reason");
1469
+ }
1470
+ return {
1471
+ reason: invalidation.reason,
1472
+ observed_at: requireTimestamp(
1473
+ invalidation.observed_at,
1474
+ "resource_invalidated observed_at"
1475
+ )
1476
+ };
1477
+ }
1478
+ function decodeBookLevels(value, name) {
1479
+ return requireArray2(value, name).map((levelValue, index) => {
1480
+ const level = requireRecord2(levelValue, `${name} ${index}`);
1481
+ if (typeof level.price !== "string" || !isDecimal(level.price) || typeof level.size !== "string" || !isDecimal(level.size)) {
1482
+ throw new Error(
1483
+ `${name} ${index} requires decimal string price and size`
1484
+ );
1485
+ }
1486
+ return { price: level.price, size: level.size };
1487
+ });
1488
+ }
1489
+ function requireSource(value) {
1490
+ if (value !== "polymarket" && value !== "kalshi") {
1491
+ throw new Error("unsupported source");
1492
+ }
1493
+ return value;
1494
+ }
1495
+ function requireIdentity(value, name) {
1496
+ if (typeof value !== "string" || value.trim() === "" || /[\u0000-\u001f]/.test(value)) {
1497
+ throw new Error(`${name} must be a non-empty identity`);
1498
+ }
1499
+ return value;
1500
+ }
1501
+ function requireTimestamp(value, name) {
1502
+ if (typeof value !== "string" || value.length === 0 || !Number.isFinite(Date.parse(value))) {
1503
+ throw new Error(`${name} must be RFC3339`);
1504
+ }
1505
+ return value;
1506
+ }
1507
+ function isDecimal(value) {
1508
+ return /^(?:0|[1-9]\d*)(?:\.\d+)?$/.test(value);
1509
+ }
1510
+ function requireRecord2(value, name) {
1511
+ const record = asRecord(value);
1512
+ if (!record) throw new Error(`${name} must be an object`);
1513
+ return record;
1514
+ }
1515
+ function asRecord(value) {
1516
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
1517
+ }
1518
+ function requireArray2(value, name) {
1519
+ if (!Array.isArray(value)) throw new Error(`${name} must be an array`);
1520
+ return value;
1521
+ }
1522
+ function failure(reason, message) {
1523
+ return { ok: false, reason, message };
1524
+ }
1525
+
1526
+ // src/market-data/recoveryBarrier.ts
1527
+ var RecoveryBarrier = class {
1528
+ generation;
1529
+ maxBufferedPublications;
1530
+ commitValue;
1531
+ buffered = [];
1532
+ currentCursor;
1533
+ currentEpoch;
1534
+ state = "buffering";
1535
+ constructor(options) {
1536
+ if (options.maxBufferedPublications < 1) {
1537
+ throw new RangeError("maxBufferedPublications must be positive");
1538
+ }
1539
+ this.generation = options.generation;
1540
+ this.maxBufferedPublications = options.maxBufferedPublications;
1541
+ this.commitValue = options.commit;
1542
+ }
1543
+ acknowledge(input) {
1544
+ if (this.state === "invalidated") return this.state;
1545
+ if (input.epoch.length === 0) {
1546
+ return this.requireRecovery();
1547
+ }
1548
+ this.currentEpoch = input.epoch;
1549
+ this.currentCursor = void 0;
1550
+ this.state = "catching_up";
1551
+ return this.state;
1552
+ }
1553
+ completeCatchUp(cursor) {
1554
+ if (this.state !== "catching_up" || cursor.generation !== this.generation || cursor.epoch !== this.currentEpoch) {
1555
+ return this.requireRecovery();
1556
+ }
1557
+ this.currentCursor = cursor;
1558
+ const pending = this.buffered;
1559
+ this.buffered = [];
1560
+ let recoveryRequired = false;
1561
+ for (const publication of pending) {
1562
+ if (this.commitIfNewer(publication) === "recovery_required") {
1563
+ recoveryRequired = true;
1564
+ break;
1565
+ }
1566
+ }
1567
+ if (!recoveryRequired) this.state = "live";
1568
+ return this.state;
1569
+ }
1570
+ push(value, cursor) {
1571
+ if (this.state === "invalidated" || cursor.generation < this.generation) {
1572
+ return "ignored";
1573
+ }
1574
+ if (cursor.generation > this.generation) {
1575
+ this.requireRecovery();
1576
+ return "recovery_required";
1577
+ }
1578
+ if (this.state === "live") {
1579
+ return this.commitIfNewer({ value, cursor });
1580
+ }
1581
+ if (this.state === "recovery_required") return "recovery_required";
1582
+ if (this.buffered.length >= this.maxBufferedPublications) {
1583
+ this.requireRecovery();
1584
+ return "recovery_required";
1585
+ }
1586
+ this.buffered.push({ value, cursor });
1587
+ return "buffered";
1588
+ }
1589
+ invalidate() {
1590
+ this.buffered = [];
1591
+ this.currentCursor = void 0;
1592
+ this.state = "invalidated";
1593
+ }
1594
+ commitIfNewer(publication) {
1595
+ if (!this.currentCursor) {
1596
+ this.requireRecovery();
1597
+ return "recovery_required";
1598
+ }
1599
+ const order = comparePublicationCursor(
1600
+ publication.cursor,
1601
+ this.currentCursor
1602
+ );
1603
+ if (order === "older" || order === "same") return "ignored";
1604
+ if (order === "epoch_changed" || order === "newer_generation") {
1605
+ this.requireRecovery();
1606
+ return "recovery_required";
1607
+ }
1608
+ this.commitValue(publication.value, publication.cursor);
1609
+ this.currentCursor = publication.cursor;
1610
+ return "committed";
1611
+ }
1612
+ requireRecovery() {
1613
+ this.buffered = [];
1614
+ this.currentCursor = void 0;
1615
+ this.state = "recovery_required";
1616
+ return this.state;
1617
+ }
1618
+ };
1619
+
1620
+ // src/market-data/watchScheduler.ts
1621
+ function chunkWatchRequest(request, maxRawQuoteSelectors) {
1622
+ if (maxRawQuoteSelectors < 1) {
1623
+ throw new RangeError("maxRawQuoteSelectors must be positive");
1624
+ }
1625
+ const selectors = [
1626
+ ...(request.quote_events ?? []).map((value) => ({
1627
+ kind: "event",
1628
+ value
1629
+ })),
1630
+ ...(request.quote_markets ?? []).map((value) => ({
1631
+ kind: "market",
1632
+ value
1633
+ }))
1634
+ ];
1635
+ if (selectors.length === 0) {
1636
+ return request.orderbook_market ? [{ ...request }] : [];
1637
+ }
1638
+ const chunks = [];
1639
+ for (let index = 0; index < selectors.length; index += maxRawQuoteSelectors) {
1640
+ const chunk2 = selectors.slice(index, index + maxRawQuoteSelectors);
1641
+ const quoteEvents = chunk2.filter(
1642
+ (selector) => selector.kind === "event"
1643
+ ).map((selector) => selector.value);
1644
+ const quoteMarkets = chunk2.filter(
1645
+ (selector) => selector.kind === "market"
1646
+ ).map((selector) => selector.value);
1647
+ chunks.push({
1648
+ ...quoteEvents.length ? { quote_events: quoteEvents } : {},
1649
+ ...quoteMarkets.length ? { quote_markets: quoteMarkets } : {},
1650
+ ...request.orderbook_market ? { orderbook_market: request.orderbook_market } : {}
1651
+ });
1652
+ }
1653
+ return chunks;
1654
+ }
1655
+ var MarketDataWatchScheduler = class {
1656
+ touch;
1657
+ maxRawQuoteSelectors;
1658
+ onTouchSuccess;
1659
+ onTouchError;
1660
+ timer;
1661
+ revision = 0;
1662
+ retryAttempt = 0;
1663
+ current;
1664
+ disposed = false;
1665
+ constructor(options) {
1666
+ this.touch = options.touch;
1667
+ this.maxRawQuoteSelectors = options.maxRawQuoteSelectors;
1668
+ this.onTouchSuccess = options.onTouchSuccess;
1669
+ this.onTouchError = options.onTouchError;
1670
+ }
1671
+ async replace(request) {
1672
+ if (this.disposed) throw new Error("watch scheduler is disposed");
1673
+ if (chunkWatchRequest(request, this.maxRawQuoteSelectors).length === 0) {
1674
+ this.clear();
1675
+ return;
1676
+ }
1677
+ this.current = request;
1678
+ const revision = ++this.revision;
1679
+ this.retryAttempt = 0;
1680
+ this.clearTimer();
1681
+ try {
1682
+ await this.touchCurrent(revision);
1683
+ } catch (error) {
1684
+ if (isRetryableWatchError(error)) {
1685
+ this.scheduleRetry(revision, error);
1686
+ }
1687
+ throw error;
1688
+ }
1689
+ }
1690
+ dispose() {
1691
+ this.disposed = true;
1692
+ this.clear();
1693
+ }
1694
+ clear() {
1695
+ this.current = void 0;
1696
+ this.revision++;
1697
+ this.retryAttempt = 0;
1698
+ this.clearTimer();
1699
+ }
1700
+ async touchCurrent(revision) {
1701
+ if (!this.current || revision !== this.revision || this.disposed) return;
1702
+ const chunks = chunkWatchRequest(this.current, this.maxRawQuoteSelectors);
1703
+ if (chunks.length === 0) throw new Error("watch request must not be empty");
1704
+ const responses = [];
1705
+ try {
1706
+ for (const chunk2 of chunks) {
1707
+ responses.push(await this.touch(chunk2));
1708
+ }
1709
+ } catch (error) {
1710
+ if (this.current && revision === this.revision && !this.disposed) {
1711
+ this.onTouchError?.(error);
1712
+ }
1713
+ throw error;
1714
+ }
1715
+ if (!this.current || revision !== this.revision || this.disposed) return;
1716
+ const refreshAfterMS = Math.min(
1717
+ ...responses.map((response) => response.refresh_after_ms)
1718
+ );
1719
+ if (!Number.isFinite(refreshAfterMS) || refreshAfterMS <= 0) {
1720
+ throw new Error("refresh_after_ms must be positive");
1721
+ }
1722
+ this.retryAttempt = 0;
1723
+ this.onTouchSuccess?.();
1724
+ this.timer = setTimeout(() => {
1725
+ void this.touchCurrent(revision).catch((error) => {
1726
+ if (isRetryableWatchError(error)) {
1727
+ this.scheduleRetry(revision, error);
1728
+ }
1729
+ });
1730
+ }, refreshAfterMS);
1731
+ }
1732
+ scheduleRetry(revision, error) {
1733
+ if (!this.current || revision !== this.revision || this.disposed) return;
1734
+ this.clearTimer();
1735
+ const retryAfterMS = retryAfterMilliseconds(error);
1736
+ const delay = retryAfterMS ?? Math.min(3e4, 1e3 * 2 ** Math.min(this.retryAttempt, 5));
1737
+ this.retryAttempt++;
1738
+ this.timer = setTimeout(() => {
1739
+ void this.touchCurrent(revision).catch((nextError) => {
1740
+ if (isRetryableWatchError(nextError)) {
1741
+ this.scheduleRetry(revision, nextError);
1742
+ }
1743
+ });
1744
+ }, delay);
1745
+ }
1746
+ clearTimer() {
1747
+ if (this.timer !== void 0) clearTimeout(this.timer);
1748
+ this.timer = void 0;
1749
+ }
1750
+ };
1751
+ function isRetryableWatchError(error) {
1752
+ if (typeof error !== "object" || error === null || !("status" in error) || typeof error.status !== "number") {
1753
+ return true;
1754
+ }
1755
+ return error.status === 408 || error.status === 429 || error.status >= 500;
1756
+ }
1757
+ function retryAfterMilliseconds(error) {
1758
+ if (typeof error !== "object" || error === null || !("retryAfter" in error) || typeof error.retryAfter !== "string") {
1759
+ return void 0;
1760
+ }
1761
+ const seconds = Number(error.retryAfter);
1762
+ return Number.isFinite(seconds) && seconds >= 0 ? seconds * 1e3 : void 0;
1763
+ }
1764
+
1765
+ // src/market-data/marketDataRuntime.ts
1766
+ var MarketDataRuntime = class {
1767
+ enabled;
1768
+ client;
1769
+ store;
1770
+ transportFactory;
1771
+ resources = /* @__PURE__ */ new Map();
1772
+ transport;
1773
+ watchScheduler;
1774
+ disposing = false;
1775
+ constructor(options) {
1776
+ this.enabled = options.enabled;
1777
+ this.client = options.client;
1778
+ this.store = options.store;
1779
+ this.transportFactory = options.transportFactory;
1780
+ }
1781
+ mount(input) {
1782
+ if (!this.enabled) return () => void 0;
1783
+ if (!this.transportFactory) {
1784
+ throw new Error(
1785
+ "market data transportFactory is required when capability is enabled"
1786
+ );
1787
+ }
1788
+ this.release(input.key);
1789
+ const started = this.store.begin(input.key, input.structureETag);
1790
+ this.store.update(input.key, started.generation, {
1791
+ phase: "buffering",
1792
+ initialQuotes: input.initialQuotes
1793
+ });
1794
+ const resource = {
1795
+ generation: started.generation,
1796
+ input,
1797
+ subscriptions: [],
1798
+ barriers: /* @__PURE__ */ new Map(),
1799
+ acknowledgements: /* @__PURE__ */ new Map(),
1800
+ initialQuotes: input.initialQuotes,
1801
+ bootstrapStarted: false,
1802
+ catchUpInFlight: false,
1803
+ bookRetryAttempt: 0,
1804
+ released: false
1805
+ };
1806
+ this.resources.set(input.key, resource);
1807
+ if (Boolean(input.bookChannel) !== Boolean(input.watch.orderbook_market)) {
1808
+ this.fail(
1809
+ resource,
1810
+ "incomplete_book_target",
1811
+ "book channel and orderbook watch selector must be provided together"
1812
+ );
1813
+ return () => this.releaseGeneration(input.key, resource.generation);
1814
+ }
1815
+ const channels = new Set(
1816
+ input.structure.items.map((item) => item.item_channel).filter((channel) => Boolean(channel))
1817
+ );
1818
+ if (input.bookChannel) {
1819
+ const declared = input.structure.items.some(
1820
+ (item) => item.markets.some(
1821
+ (market) => market.outcomes.some(
1822
+ (outcome) => outcome.book_channel === input.bookChannel
1823
+ )
1824
+ )
1825
+ );
1826
+ if (!declared) {
1827
+ this.fail(
1828
+ resource,
1829
+ "unknown_book_channel",
1830
+ "book channel is absent from structure"
1831
+ );
1832
+ return () => this.releaseGeneration(input.key, resource.generation);
1833
+ }
1834
+ channels.add(input.bookChannel);
1835
+ }
1836
+ if (channels.size === 0) {
1837
+ this.fail(resource, "missing_channel", "structure has no channel target");
1838
+ return () => this.releaseGeneration(input.key, resource.generation);
1839
+ }
1840
+ for (const channel of channels) this.subscribe(resource, channel);
1841
+ return () => this.releaseGeneration(input.key, resource.generation);
1842
+ }
1843
+ dispose() {
1844
+ this.disposing = true;
1845
+ for (const key of [...this.resources.keys()]) this.release(key);
1846
+ this.watchScheduler?.dispose();
1847
+ this.watchScheduler = void 0;
1848
+ this.transport?.close?.();
1849
+ this.transport = void 0;
1850
+ }
1851
+ subscribe(resource, channel) {
1852
+ const barrier = new RecoveryBarrier({
1853
+ generation: resource.generation,
1854
+ maxBufferedPublications: 1e3,
1855
+ commit: (value) => this.commitPublication(resource, channel, value)
1856
+ });
1857
+ resource.barriers.set(channel, barrier);
1858
+ const subscription = this.getTransport().subscribe(channel, {
1859
+ onPublication: (publication) => this.onPublication(resource, channel, publication),
1860
+ onSubscribed: (ack) => this.onSubscribed(resource, channel, ack),
1861
+ onError: (error) => this.store.update(resource.input.key, resource.generation, {
1862
+ phase: channel === resource.input.bookChannel ? "degraded_book" : "degraded_quote",
1863
+ ...channel === resource.input.bookChannel ? { bookError: error } : { quoteError: error }
1864
+ })
1865
+ });
1866
+ resource.subscriptions.push(subscription);
1867
+ }
1868
+ onPublication(resource, channel, publication) {
1869
+ if (resource.released) return;
1870
+ const result = resource.barriers.get(channel)?.push(publication.data, {
1871
+ generation: resource.generation,
1872
+ epoch: publication.epoch,
1873
+ offset: publication.offset
1874
+ });
1875
+ const acknowledged = resource.acknowledgements.get(channel);
1876
+ if (result === "recovery_required" && acknowledged?.epoch === publication.epoch) {
1877
+ this.restartCatchUp(resource);
1878
+ }
1879
+ }
1880
+ onSubscribed(resource, channel, ack) {
1881
+ if (resource.released) return;
1882
+ const barrier = resource.barriers.get(channel);
1883
+ const previousState = barrier?.state;
1884
+ if (resource.bootstrapStarted && (previousState === "live" || previousState === "recovery_required")) {
1885
+ resource.bootstrapStarted = false;
1886
+ resource.acknowledgements.clear();
1887
+ this.store.update(resource.input.key, resource.generation, {
1888
+ phase: "buffering"
1889
+ });
1890
+ }
1891
+ const state = barrier?.acknowledge(ack);
1892
+ if (state === "recovery_required") {
1893
+ this.fail(
1894
+ resource,
1895
+ "recovery_required",
1896
+ "subscription was not recovered"
1897
+ );
1898
+ return;
1899
+ }
1900
+ resource.acknowledgements.set(channel, ack);
1901
+ if (resource.acknowledgements.size === resource.barriers.size && !resource.bootstrapStarted) {
1902
+ resource.bootstrapStarted = true;
1903
+ void this.bootstrap(resource);
1904
+ }
1905
+ }
1906
+ async bootstrap(resource) {
1907
+ if (resource.catchUpInFlight || resource.released) return;
1908
+ resource.catchUpInFlight = true;
1909
+ this.store.update(resource.input.key, resource.generation, {
1910
+ phase: "catching_up"
1911
+ });
1912
+ try {
1913
+ const structure = await this.client.getMarketStructure(
1914
+ resource.input.structurePath,
1915
+ resource.input.structureETag
1916
+ );
1917
+ if (resource.released) return;
1918
+ if (structure.status === 200 || structure.etag !== resource.input.structureETag) {
1919
+ this.fail(
1920
+ resource,
1921
+ "structure_changed",
1922
+ "resource structure changed during recovery"
1923
+ );
1924
+ return;
1925
+ }
1926
+ const keys = realtimeMarketKeys(resource.input);
1927
+ const quoteChunks = chunk(keys, 500);
1928
+ let initialQuotes = resource.initialQuotes;
1929
+ for (const quoteChunk of quoteChunks) {
1930
+ const response = await this.client.getMarketDataQuotes(quoteChunk);
1931
+ if (resource.released) return;
1932
+ const parsed = parseInitialQuotes(
1933
+ response,
1934
+ structuralMarketsForKeys(resource.input, quoteChunk)
1935
+ );
1936
+ if (parsed.kind !== "valid") {
1937
+ throw new Error(
1938
+ parsed.kind === "malformed" ? parsed.reason : "quote catch-up response is missing"
1939
+ );
1940
+ }
1941
+ initialQuotes = mergeQuoteCatchUp(initialQuotes, parsed.value);
1942
+ }
1943
+ resource.initialQuotes = initialQuotes;
1944
+ let bookError;
1945
+ if (resource.input.watch.orderbook_market) {
1946
+ const key = resource.input.watch.orderbook_market;
1947
+ try {
1948
+ const orderbooks = await this.client.getMarketDataOrderbooks(
1949
+ key.market_slug,
1950
+ key.source
1951
+ );
1952
+ if (resource.released) return;
1953
+ this.store.update(resource.input.key, resource.generation, {
1954
+ orderbooks,
1955
+ bookError: void 0
1956
+ });
1957
+ } catch (error) {
1958
+ bookError = error;
1959
+ if (this.handleBookError(resource, error)) return;
1960
+ }
1961
+ }
1962
+ if (resource.released) return;
1963
+ await this.getWatchScheduler().replace(this.combinedWatchRequest());
1964
+ if (resource.released) return;
1965
+ for (const [channel, barrier] of resource.barriers) {
1966
+ const ack = resource.acknowledgements.get(channel);
1967
+ if (!ack) throw new Error(`missing subscription ack for ${channel}`);
1968
+ if (barrier.completeCatchUp({
1969
+ generation: resource.generation,
1970
+ epoch: ack.epoch,
1971
+ offset: ack.offset
1972
+ }) === "recovery_required") {
1973
+ throw new Error(`recovery fence failed for ${channel}`);
1974
+ }
1975
+ }
1976
+ this.store.update(resource.input.key, resource.generation, {
1977
+ phase: bookError ? "degraded_book" : "live",
1978
+ initialQuotes: resource.initialQuotes,
1979
+ quoteError: void 0
1980
+ });
1981
+ } catch (error) {
1982
+ const state = this.store.get(resource.input.key);
1983
+ if (state.generation === resource.generation && (state.phase === "terminal" || state.phase === "degraded_book" && resource.watchFailure === "book" || resource.watchFailure === "rate_limit")) {
1984
+ return;
1985
+ }
1986
+ this.store.update(resource.input.key, resource.generation, {
1987
+ phase: "degraded_quote",
1988
+ initialQuotes: resource.initialQuotes,
1989
+ quoteError: error
1990
+ });
1991
+ } finally {
1992
+ resource.catchUpInFlight = false;
1993
+ }
1994
+ }
1995
+ restartCatchUp(resource) {
1996
+ if (resource.released || resource.catchUpInFlight) return;
1997
+ resource.bootstrapStarted = true;
1998
+ for (const [channel, barrier] of resource.barriers) {
1999
+ const ack = resource.acknowledgements.get(channel);
2000
+ if (!ack) {
2001
+ resource.bootstrapStarted = false;
2002
+ return;
2003
+ }
2004
+ barrier.acknowledge({ ...ack, recovered: false });
2005
+ }
2006
+ void this.bootstrap(resource);
2007
+ }
2008
+ commitPublication(resource, channel, value) {
2009
+ if (channel === resource.input.bookChannel) {
2010
+ const decoded2 = decodeBookEnvelope(value);
2011
+ if (!decoded2.ok) {
2012
+ this.store.update(resource.input.key, resource.generation, {
2013
+ phase: "degraded_book",
2014
+ bookError: decoded2
2015
+ });
2016
+ } else {
2017
+ this.store.update(resource.input.key, resource.generation, {
2018
+ phase: "live",
2019
+ liveBook: decoded2.value,
2020
+ bookError: void 0
2021
+ });
2022
+ }
2023
+ return;
2024
+ }
2025
+ const decoded = decodeItemEnvelope(value);
2026
+ if (!decoded.ok) {
2027
+ this.store.update(resource.input.key, resource.generation, {
2028
+ phase: "degraded_quote",
2029
+ quoteError: decoded
2030
+ });
2031
+ return;
2032
+ }
2033
+ if (decoded.value.resource_invalidated) {
2034
+ this.fail(
2035
+ resource,
2036
+ "structure_invalidated",
2037
+ "resource membership was invalidated"
2038
+ );
2039
+ return;
2040
+ }
2041
+ if (decoded.value.changes && resource.initialQuotes) {
2042
+ resource.initialQuotes = mergeItemChanges(
2043
+ resource.initialQuotes,
2044
+ decoded.value.changes
2045
+ );
2046
+ this.store.update(resource.input.key, resource.generation, {
2047
+ initialQuotes: resource.initialQuotes
2048
+ });
2049
+ }
2050
+ }
2051
+ getTransport() {
2052
+ if (!this.transport) this.transport = this.transportFactory();
2053
+ return this.transport;
2054
+ }
2055
+ getWatchScheduler() {
2056
+ if (!this.watchScheduler) {
2057
+ this.watchScheduler = new MarketDataWatchScheduler({
2058
+ touch: (request) => this.client.watchMarketData(request),
2059
+ maxRawQuoteSelectors: 500,
2060
+ onTouchSuccess: () => this.onWatchTouchSuccess(),
2061
+ onTouchError: (error) => this.onWatchTouchError(error)
2062
+ });
2063
+ }
2064
+ return this.watchScheduler;
2065
+ }
2066
+ onWatchTouchSuccess() {
2067
+ for (const resource of this.resources.values()) {
2068
+ if (resource.released || !resource.watchFailure) continue;
2069
+ const state = this.store.get(resource.input.key);
2070
+ if (state.generation !== resource.generation) continue;
2071
+ const watchError = resource.watchError;
2072
+ const quoteError = state.quoteError === watchError ? void 0 : state.quoteError;
2073
+ const bookError = state.bookError === watchError ? void 0 : state.bookError;
2074
+ resource.watchFailure = void 0;
2075
+ resource.watchError = void 0;
2076
+ this.store.update(resource.input.key, resource.generation, {
2077
+ phase: quoteError ? "degraded_quote" : bookError ? "degraded_book" : "live",
2078
+ quoteError,
2079
+ bookError
2080
+ });
2081
+ }
2082
+ }
2083
+ onWatchTouchError(error) {
2084
+ const status = httpStatus(error);
2085
+ for (const resource of this.resources.values()) {
2086
+ if (resource.released) continue;
2087
+ if (status === 401 || status === 403 || status === 404 || status === 422) {
2088
+ this.fail(
2089
+ resource,
2090
+ status === 404 ? "structure_invalidated" : "watch_terminal",
2091
+ error instanceof Error ? error.message : "Watch request failed"
2092
+ );
2093
+ this.store.update(resource.input.key, resource.generation, {
2094
+ quoteError: error
2095
+ });
2096
+ continue;
2097
+ }
2098
+ if (status === 429) {
2099
+ resource.watchFailure = resource.input.watch.orderbook_market ? "book" : "rate_limit";
2100
+ resource.watchError = error;
2101
+ this.store.update(resource.input.key, resource.generation, {
2102
+ phase: resource.input.watch.orderbook_market ? "degraded_book" : "live",
2103
+ initialQuotes: resource.initialQuotes,
2104
+ quoteError: void 0,
2105
+ ...resource.input.watch.orderbook_market ? { bookError: error } : {}
2106
+ });
2107
+ continue;
2108
+ }
2109
+ resource.watchFailure = "quote";
2110
+ resource.watchError = error;
2111
+ this.store.update(resource.input.key, resource.generation, {
2112
+ phase: "degraded_quote",
2113
+ initialQuotes: resource.initialQuotes,
2114
+ quoteError: error
2115
+ });
2116
+ }
2117
+ }
2118
+ handleBookError(resource, error) {
2119
+ if (resource.released) return false;
2120
+ const status = httpStatus(error);
2121
+ if (status === 401 || status === 403 || status === 404 || status === 422) {
2122
+ this.fail(
2123
+ resource,
2124
+ status === 404 ? "structure_invalidated" : "book_terminal",
2125
+ error instanceof Error ? error.message : "Book request failed"
2126
+ );
2127
+ this.store.update(resource.input.key, resource.generation, {
2128
+ bookError: error
2129
+ });
2130
+ return true;
2131
+ }
2132
+ this.store.update(resource.input.key, resource.generation, {
2133
+ phase: "degraded_book",
2134
+ bookError: error
2135
+ });
2136
+ if (!isRetryableBookError(error)) return false;
2137
+ if (resource.bookRetryTimer !== void 0) {
2138
+ clearTimeout(resource.bookRetryTimer);
2139
+ }
2140
+ const delay = retryAfterMilliseconds2(error) ?? Math.min(3e4, 1e3 * 2 ** Math.min(resource.bookRetryAttempt, 5));
2141
+ resource.bookRetryAttempt++;
2142
+ resource.bookRetryTimer = setTimeout(() => {
2143
+ resource.bookRetryTimer = void 0;
2144
+ void this.retryBookCatchUp(resource);
2145
+ }, delay);
2146
+ return false;
2147
+ }
2148
+ async retryBookCatchUp(resource) {
2149
+ const key = resource.input.watch.orderbook_market;
2150
+ if (resource.released || !key) return;
2151
+ try {
2152
+ const orderbooks = await this.client.getMarketDataOrderbooks(
2153
+ key.market_slug,
2154
+ key.source
2155
+ );
2156
+ resource.bookRetryAttempt = 0;
2157
+ const state = this.store.get(resource.input.key);
2158
+ this.store.update(resource.input.key, resource.generation, {
2159
+ phase: state.quoteError ? "degraded_quote" : "live",
2160
+ orderbooks,
2161
+ bookError: void 0
2162
+ });
2163
+ } catch (error) {
2164
+ this.handleBookError(resource, error);
2165
+ }
2166
+ }
2167
+ combinedWatchRequest() {
2168
+ const quoteEvents = /* @__PURE__ */ new Map();
2169
+ const quoteMarkets = /* @__PURE__ */ new Map();
2170
+ const orderbookMarkets = /* @__PURE__ */ new Map();
2171
+ for (const resource of this.resources.values()) {
2172
+ if (resource.released) continue;
2173
+ for (const event of resource.input.watch.quote_events ?? []) {
2174
+ quoteEvents.set(
2175
+ `${event.source}\0${event.event_slug}\0${event.market_view}`,
2176
+ event
2177
+ );
2178
+ }
2179
+ for (const market of resource.input.watch.quote_markets ?? []) {
2180
+ quoteMarkets.set(`${market.source}\0${market.market_slug}`, market);
2181
+ }
2182
+ const book = resource.input.watch.orderbook_market;
2183
+ if (book) {
2184
+ orderbookMarkets.set(`${book.source}\0${book.market_slug}`, book);
2185
+ }
2186
+ }
2187
+ if (orderbookMarkets.size > 1) {
2188
+ throw new Error("only one active orderbook market is supported");
2189
+ }
2190
+ return {
2191
+ ...quoteEvents.size ? { quote_events: [...quoteEvents.values()] } : {},
2192
+ ...quoteMarkets.size ? { quote_markets: [...quoteMarkets.values()] } : {},
2193
+ ...orderbookMarkets.size ? { orderbook_market: [...orderbookMarkets.values()][0] } : {}
2194
+ };
2195
+ }
2196
+ fail(resource, code, message) {
2197
+ for (const barrier of resource.barriers.values()) barrier.invalidate();
2198
+ this.store.update(resource.input.key, resource.generation, {
2199
+ phase: "terminal",
2200
+ structureInvalidated: code === "structure_invalidated" || code === "structure_changed",
2201
+ quoteError: { code, message }
2202
+ });
2203
+ }
2204
+ release(key) {
2205
+ const resource = this.resources.get(key);
2206
+ if (resource) this.releaseGeneration(key, resource.generation);
2207
+ }
2208
+ releaseGeneration(key, generation) {
2209
+ const resource = this.resources.get(key);
2210
+ if (!resource || resource.generation !== generation) return;
2211
+ resource.released = true;
2212
+ if (resource.bookRetryTimer !== void 0) {
2213
+ clearTimeout(resource.bookRetryTimer);
2214
+ resource.bookRetryTimer = void 0;
2215
+ }
2216
+ for (const subscription of resource.subscriptions) {
2217
+ subscription.unsubscribe();
2218
+ }
2219
+ for (const barrier of resource.barriers.values()) barrier.invalidate();
2220
+ this.resources.delete(key);
2221
+ this.store.remove(key, generation);
2222
+ if (!this.disposing) this.refreshWatchDemand();
2223
+ }
2224
+ refreshWatchDemand() {
2225
+ if (!this.watchScheduler) return;
2226
+ const request = this.combinedWatchRequest();
2227
+ if (!(request.quote_events?.length ?? 0) && !(request.quote_markets?.length ?? 0) && !request.orderbook_market) {
2228
+ this.watchScheduler.clear();
2229
+ return;
2230
+ }
2231
+ void this.watchScheduler.replace(request).catch(() => void 0);
2232
+ }
2233
+ };
2234
+ function realtimeMarketKeys(input) {
2235
+ return input.structure.items.flatMap(
2236
+ (item) => item.markets.filter((market) => market.realtime_supported).map((market) => ({
2237
+ source: market.source,
2238
+ market_slug: market.market_slug
2239
+ }))
2240
+ );
2241
+ }
2242
+ function structuralMarketsForKeys(input, keys) {
2243
+ return keys.map((key) => {
2244
+ const market = input.structure.items.flatMap((item) => item.markets).find(
2245
+ (candidate) => candidate.source === key.source && candidate.market_slug === key.market_slug
2246
+ );
2247
+ if (!market) throw new Error("quote catch-up key is absent from structure");
2248
+ return {
2249
+ source: market.source,
2250
+ market_slug: market.market_slug,
2251
+ outcomes: market.outcomes.map((outcome) => outcome.key)
2252
+ };
2253
+ });
2254
+ }
2255
+ function chunk(values, size) {
2256
+ const chunks = [];
2257
+ for (let index = 0; index < values.length; index += size) {
2258
+ chunks.push(values.slice(index, index + size));
2259
+ }
2260
+ return chunks;
2261
+ }
2262
+ function httpStatus(error) {
2263
+ return typeof error === "object" && error !== null && "status" in error && typeof error.status === "number" ? error.status : void 0;
2264
+ }
2265
+ function isRetryableBookError(error) {
2266
+ const status = httpStatus(error);
2267
+ return status === void 0 || status === 408 || status === 409 || status === 429 || status >= 500;
2268
+ }
2269
+ function retryAfterMilliseconds2(error) {
2270
+ if (typeof error !== "object" || error === null || !("retryAfter" in error) || typeof error.retryAfter !== "string") {
2271
+ return void 0;
2272
+ }
2273
+ const seconds = Number(error.retryAfter);
2274
+ return Number.isFinite(seconds) && seconds >= 0 ? seconds * 1e3 : void 0;
2275
+ }
2276
+ function mergeItemChanges(current, changes) {
2277
+ return {
2278
+ ...current,
2279
+ markets: current.markets.map((market) => ({
2280
+ ...market,
2281
+ outcomes: market.outcomes.map((outcome) => {
2282
+ const change = changes.find(
2283
+ (candidate) => candidate.source === outcome.source && candidate.market_slug === outcome.market_slug && candidate.outcome === outcome.outcome
2284
+ );
2285
+ if (!change) return outcome;
2286
+ return {
2287
+ ...outcome,
2288
+ ...change.bba ? { bba: change.bba } : {},
2289
+ ...change.last_trade ? { last_trade: change.last_trade } : {},
2290
+ ...change.tick_size ? { tick_size: change.tick_size } : {}
2291
+ };
2292
+ })
2293
+ }))
2294
+ };
2295
+ }
2296
+ function mergeQuoteCatchUp(current, catchUp) {
2297
+ if (!current) return catchUp;
2298
+ const identity = (source, slug) => `${source}\0${slug}`;
2299
+ const catchUpByMarket = new Map(
2300
+ catchUp.markets.map((market) => [
2301
+ identity(market.source, market.market_slug),
2302
+ market
2303
+ ])
2304
+ );
2305
+ const merged = current.markets.map(
2306
+ (market) => catchUpByMarket.get(identity(market.source, market.market_slug)) ?? market
2307
+ );
2308
+ const existing = new Set(
2309
+ current.markets.map(
2310
+ (market) => identity(market.source, market.market_slug)
2311
+ )
2312
+ );
2313
+ for (const market of catchUp.markets) {
2314
+ if (!existing.has(identity(market.source, market.market_slug))) {
2315
+ merged.push(market);
2316
+ }
2317
+ }
2318
+ return { schema_version: 1, markets: merged };
2319
+ }
2320
+
2321
+ // src/market-data/marketDataStore.ts
2322
+ var legacyState = (key) => ({
2323
+ key,
2324
+ generation: 0,
2325
+ phase: "legacy"
2326
+ });
2327
+ var MarketDataStore = class {
2328
+ resources = /* @__PURE__ */ new Map();
2329
+ generations = /* @__PURE__ */ new Map();
2330
+ legacyStates = /* @__PURE__ */ new Map();
2331
+ listeners = /* @__PURE__ */ new Map();
2332
+ get(key) {
2333
+ const existing = this.resources.get(key);
2334
+ if (existing) return existing;
2335
+ let fallback = this.legacyStates.get(key);
2336
+ if (!fallback) {
2337
+ fallback = legacyState(key);
2338
+ this.legacyStates.set(key, fallback);
2339
+ }
2340
+ return fallback;
2341
+ }
2342
+ begin(key, structureETag) {
2343
+ const generation = (this.generations.get(key) ?? 0) + 1;
2344
+ this.generations.set(key, generation);
2345
+ const state = {
2346
+ key,
2347
+ generation,
2348
+ phase: "initializing",
2349
+ structureETag
2350
+ };
2351
+ this.resources.set(key, state);
2352
+ this.emit(key);
2353
+ return state;
2354
+ }
2355
+ update(key, generation, patch) {
2356
+ const current = this.resources.get(key);
2357
+ if (!current || current.generation !== generation) return false;
2358
+ this.resources.set(key, { ...current, ...patch });
2359
+ this.emit(key);
2360
+ return true;
2361
+ }
2362
+ remove(key, generation) {
2363
+ const current = this.resources.get(key);
2364
+ if (!current || current.generation !== generation) return false;
2365
+ this.resources.delete(key);
2366
+ this.emit(key);
2367
+ return true;
2368
+ }
2369
+ subscribe(key, listener) {
2370
+ let listeners = this.listeners.get(key);
2371
+ if (!listeners) {
2372
+ listeners = /* @__PURE__ */ new Set();
2373
+ this.listeners.set(key, listeners);
2374
+ }
2375
+ listeners.add(listener);
2376
+ return () => {
2377
+ listeners?.delete(listener);
2378
+ if (listeners?.size === 0) this.listeners.delete(key);
2379
+ };
2380
+ }
2381
+ emit(key) {
2382
+ for (const listener of this.listeners.get(key) ?? []) listener();
2383
+ }
2384
+ };
1007
2385
  var PredictContext = react.createContext(null);
1008
2386
  function PredictProvider({
1009
2387
  client,
@@ -1015,6 +2393,43 @@ function PredictProvider({
1015
2393
  return /* @__PURE__ */ jsxRuntime.jsx(PredictContext.Provider, { value, children });
1016
2394
  }
1017
2395
 
2396
+ // src/market-data/adapters/create-client-market-venue-adapter.ts
2397
+ function createClientMarketVenueAdapter(client) {
2398
+ return {
2399
+ watchMarketData: (request) => client.watchMarketData(request),
2400
+ getMarketDataQuotes: (markets) => client.getMarketDataQuotes(markets),
2401
+ getMarketDataOrderbooks: (slug, source) => client.getMarketDataOrderbooks(slug, source),
2402
+ getMarketStructure: (path, ifNoneMatch) => client.getMarketStructure(path, ifNoneMatch)
2403
+ };
2404
+ }
2405
+ var MarketDataContext = react.createContext(
2406
+ null
2407
+ );
2408
+ function MarketDataProvider({
2409
+ capability,
2410
+ client,
2411
+ transportFactory,
2412
+ children
2413
+ }) {
2414
+ const store = react.useMemo(() => new MarketDataStore(), []);
2415
+ const venue = react.useMemo(() => createClientMarketVenueAdapter(client), [client]);
2416
+ const runtime = react.useMemo(
2417
+ () => new MarketDataRuntime({
2418
+ enabled: capability.enabled,
2419
+ client: venue,
2420
+ store,
2421
+ transportFactory
2422
+ }),
2423
+ [capability.enabled, venue, store, transportFactory]
2424
+ );
2425
+ react.useEffect(() => () => runtime.dispose(), [runtime]);
2426
+ const value = react.useMemo(
2427
+ () => ({ capability, client, store, runtime }),
2428
+ [capability, client, store, runtime]
2429
+ );
2430
+ return /* @__PURE__ */ jsxRuntime.jsx(MarketDataContext.Provider, { value, children });
2431
+ }
2432
+
1018
2433
  // src/utils/polymarket-hmac.ts
1019
2434
  function encode(str) {
1020
2435
  return new TextEncoder().encode(str);
@@ -1200,6 +2615,47 @@ function usePredictClient() {
1200
2615
  }
1201
2616
  return context.client;
1202
2617
  }
2618
+ function useMarketDataCapability() {
2619
+ const context = react.useContext(MarketDataContext);
2620
+ if (!context) {
2621
+ throw new Error(
2622
+ "useMarketDataCapability must be used within a MarketDataProvider"
2623
+ );
2624
+ }
2625
+ return context.capability;
2626
+ }
2627
+ function useMarketDataResource(input) {
2628
+ const context = react.useContext(MarketDataContext);
2629
+ if (!context) {
2630
+ throw new Error(
2631
+ "useMarketDataResource must be used within a MarketDataProvider"
2632
+ );
2633
+ }
2634
+ const key = typeof input === "string" ? input : input.key;
2635
+ react.useEffect(() => {
2636
+ if (typeof input === "string" || !context.capability.enabled) return;
2637
+ return context.runtime.mount(input);
2638
+ }, [context.capability.enabled, context.runtime, input]);
2639
+ const subscribe = react.useCallback(
2640
+ (listener) => context.store.subscribe(key, listener),
2641
+ [context.store, key]
2642
+ );
2643
+ const getSnapshot = react.useCallback(
2644
+ () => context.store.get(key),
2645
+ [context.store, key]
2646
+ );
2647
+ return react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
2648
+ }
2649
+
2650
+ // src/hooks/predict/useMarketDataOrderbooks.ts
2651
+ function useMarketDataOrderbooks(resourceKey) {
2652
+ const resource = useMarketDataResource(resourceKey);
2653
+ return {
2654
+ snapshot: resource.orderbooks,
2655
+ live: resource.liveBook,
2656
+ error: resource.bookError
2657
+ };
2658
+ }
1203
2659
  function eventsQueryKey(params) {
1204
2660
  return ["predict", "events", params ?? {}];
1205
2661
  }
@@ -1592,6 +3048,7 @@ function useRealtimeOrderbook(params, queryOptions = {}) {
1592
3048
  const { wsClient } = usePredictWsClient();
1593
3049
  const queryClient = reactQuery.useQueryClient();
1594
3050
  const outcome = params.outcome ?? "yes";
3051
+ const enabled = queryOptions.enabled !== false && Boolean(params.slug);
1595
3052
  const handleUpdate = react.useCallback(
1596
3053
  (msg) => {
1597
3054
  if (msg.data.market_slug !== params.slug) return;
@@ -1613,7 +3070,7 @@ function useRealtimeOrderbook(params, queryOptions = {}) {
1613
3070
  const subParams = {
1614
3071
  wsClient,
1615
3072
  slug: params.slug,
1616
- enabled: Boolean(params.slug),
3073
+ enabled,
1617
3074
  outcome,
1618
3075
  onUpdate: handleUpdate
1619
3076
  };
@@ -2797,7 +4254,7 @@ function useRunPolymarketSetup(walletAddress) {
2797
4254
  mutationFn: (address) => client.runPolymarketSetup(address),
2798
4255
  onSuccess: () => {
2799
4256
  if (walletAddress) {
2800
- queryClient.invalidateQueries({
4257
+ void queryClient.invalidateQueries({
2801
4258
  queryKey: polymarketSetupQueryKey(walletAddress)
2802
4259
  });
2803
4260
  }
@@ -2811,7 +4268,7 @@ function useDeployPolymarketDepositWallet(walletAddress) {
2811
4268
  mutationFn: (address) => client.deployPolymarketDepositWallet(address),
2812
4269
  onSuccess: () => {
2813
4270
  if (walletAddress) {
2814
- queryClient.invalidateQueries({
4271
+ void queryClient.invalidateQueries({
2815
4272
  queryKey: polymarketSetupQueryKey(walletAddress)
2816
4273
  });
2817
4274
  }
@@ -2831,8 +4288,8 @@ function useWithdrawSubmitMutation(mutationOptions = {}) {
2831
4288
  return reactQuery.useMutation({
2832
4289
  mutationFn: (body) => client.withdrawSubmit(body),
2833
4290
  onSuccess: () => {
2834
- queryClient.invalidateQueries({ queryKey: ["predict", "balance"] });
2835
- queryClient.invalidateQueries({ queryKey: ["predict", "positions"] });
4291
+ void queryClient.invalidateQueries({ queryKey: ["predict", "balance"] });
4292
+ void queryClient.invalidateQueries({ queryKey: ["predict", "positions"] });
2836
4293
  },
2837
4294
  ...mutationOptions
2838
4295
  });
@@ -2897,7 +4354,7 @@ function usePolymarketDeposit(mutationOptions = {}) {
2897
4354
  };
2898
4355
  },
2899
4356
  onSuccess: () => {
2900
- queryClient.invalidateQueries({ queryKey: ["predict", "balance"] });
4357
+ void queryClient.invalidateQueries({ queryKey: ["predict", "balance"] });
2901
4358
  },
2902
4359
  ...mutationOptions
2903
4360
  });
@@ -3102,11 +4559,12 @@ function usePricesSubscription({
3102
4559
  onUpdateRef.current?.(msg);
3103
4560
  }, []);
3104
4561
  react.useEffect(() => {
3105
- if (!wsClient || !enabled || slugs.length === 0) {
4562
+ const slugList = slugsKey.length === 0 ? [] : slugsKey.split(",");
4563
+ if (!wsClient || !enabled || slugList.length === 0) {
3106
4564
  setIsSubscribed(false);
3107
4565
  return;
3108
4566
  }
3109
- const unsub = wsClient.subscribePrices(slugs, handleUpdate);
4567
+ const unsub = wsClient.subscribePrices(slugList, handleUpdate);
3110
4568
  setIsSubscribed(true);
3111
4569
  return () => {
3112
4570
  unsub();
@@ -3676,11 +5134,146 @@ function walkOrderbook({
3676
5134
  };
3677
5135
  }
3678
5136
 
5137
+ // src/utils/order-intent-runtime.ts
5138
+ var PredictionOrderRejectedError = class extends Error {
5139
+ constructor(message = "prediction order rejected") {
5140
+ super(message);
5141
+ this.name = "PredictionOrderRejectedError";
5142
+ }
5143
+ };
5144
+ function createPredictionOrderRuntime(options) {
5145
+ let current = { status: "idle" };
5146
+ const accepted = /* @__PURE__ */ new Set();
5147
+ const confirmTimeoutMs = options.confirmTimeoutMs ?? 3e4;
5148
+ const clock = options.clock ?? { now: () => Date.now() };
5149
+ const set = (next) => {
5150
+ current = next;
5151
+ options.onChange?.(next);
5152
+ return next;
5153
+ };
5154
+ return {
5155
+ snapshot() {
5156
+ return current;
5157
+ },
5158
+ cancel() {
5159
+ if (current.status === "succeeded" || current.status === "confirming" || current.status === "submitting") {
5160
+ return current;
5161
+ }
5162
+ return set({ status: "cancelled", intent: current.intent });
5163
+ },
5164
+ async submit(intent) {
5165
+ if (accepted.has(intent.id)) {
5166
+ return current.status === "idle" ? set({ status: "succeeded", intent, acceptedId: intent.id }) : current;
5167
+ }
5168
+ if (current.intent?.id === intent.id && (current.status === "submitting" || current.status === "confirming" || current.status === "succeeded")) {
5169
+ return current;
5170
+ }
5171
+ set({ status: "validating", intent });
5172
+ if (intent.venue === "kalshi") {
5173
+ const verified = options.kyc ? await options.kyc.verified() : false;
5174
+ if (!verified) {
5175
+ return set({ status: "needs-kyc", intent });
5176
+ }
5177
+ }
5178
+ if (intent.venue === "polymarket") {
5179
+ const verified = options.setup ? await options.setup.verified() : false;
5180
+ if (!verified) {
5181
+ return set({ status: "needs-setup", intent });
5182
+ }
5183
+ }
5184
+ if (!options.signer) {
5185
+ return set({
5186
+ status: "failed",
5187
+ intent,
5188
+ error: new PredictionOrderRejectedError("missing signer")
5189
+ });
5190
+ }
5191
+ set({ status: "signing", intent });
5192
+ let signed;
5193
+ try {
5194
+ signed = await options.signer.sign(intent);
5195
+ } catch (error) {
5196
+ const err = error instanceof Error ? error : new Error(String(error));
5197
+ return set({ status: "failed", intent, error: err });
5198
+ }
5199
+ set({ status: "submitting", intent });
5200
+ let acceptedId;
5201
+ try {
5202
+ const result = await options.execution.submit(intent, signed);
5203
+ if (!result.accepted) {
5204
+ return set({
5205
+ status: "failed",
5206
+ intent,
5207
+ error: new PredictionOrderRejectedError()
5208
+ });
5209
+ }
5210
+ acceptedId = result.id ?? intent.id;
5211
+ accepted.add(intent.id);
5212
+ accepted.add(acceptedId);
5213
+ } catch (error) {
5214
+ const err = error instanceof Error ? error : new Error(String(error));
5215
+ return set({ status: "failed", intent, error: err });
5216
+ }
5217
+ set({ status: "confirming", intent, acceptedId });
5218
+ if (!options.confirmation) {
5219
+ return set({ status: "succeeded", intent, acceptedId });
5220
+ }
5221
+ const deadline = clock.now() + confirmTimeoutMs;
5222
+ const outcome = await options.confirmation.wait(acceptedId, {
5223
+ timedOut: () => clock.now() >= deadline
5224
+ });
5225
+ if (outcome === "timed-out") {
5226
+ return set({ status: "timed-out", intent, acceptedId });
5227
+ }
5228
+ return set({ status: "succeeded", intent, acceptedId });
5229
+ }
5230
+ };
5231
+ }
5232
+
5233
+ // src/utils/in-memory-order-ports.ts
5234
+ function createInMemoryOrderPorts(options = {}) {
5235
+ let submits = 0;
5236
+ return {
5237
+ signer: {
5238
+ async sign(intent) {
5239
+ if (options.signError) throw options.signError;
5240
+ return { signed: intent.id };
5241
+ }
5242
+ },
5243
+ execution: {
5244
+ async submit(intent) {
5245
+ submits += 1;
5246
+ return {
5247
+ accepted: options.accept !== false,
5248
+ id: intent.id
5249
+ };
5250
+ }
5251
+ },
5252
+ confirmation: {
5253
+ async wait(_acceptedId, signal) {
5254
+ if (signal.timedOut() || options.confirm === "timed-out") {
5255
+ return "timed-out";
5256
+ }
5257
+ return "confirmed";
5258
+ }
5259
+ },
5260
+ submitCount: () => submits
5261
+ };
5262
+ }
5263
+
3679
5264
  exports.CLOB_AUTH_DOMAIN = CLOB_AUTH_DOMAIN;
3680
5265
  exports.CLOB_AUTH_TYPES = CLOB_AUTH_TYPES;
3681
5266
  exports.CTF_EXCHANGE_ADDRESS = CTF_EXCHANGE_ADDRESS;
3682
5267
  exports.CTF_ORDER_TYPES = CTF_ORDER_TYPES;
3683
5268
  exports.ChartRange = ChartRange;
5269
+ exports.MARKET_DATA_BACKEND_CONTRACT_COMMIT = MARKET_DATA_BACKEND_CONTRACT_COMMIT;
5270
+ exports.MARKET_DATA_CONTRACT_MANIFEST_SHA256 = MARKET_DATA_CONTRACT_MANIFEST_SHA256;
5271
+ exports.MARKET_STRUCTURE_MEDIA_TYPE_V1 = MARKET_STRUCTURE_MEDIA_TYPE_V1;
5272
+ exports.MarketDataHttpError = MarketDataHttpError;
5273
+ exports.MarketDataProvider = MarketDataProvider;
5274
+ exports.MarketDataRuntime = MarketDataRuntime;
5275
+ exports.MarketDataStore = MarketDataStore;
5276
+ exports.MarketDataWatchScheduler = MarketDataWatchScheduler;
3684
5277
  exports.NEG_RISK_CTF_EXCHANGE_ADDRESS = NEG_RISK_CTF_EXCHANGE_ADDRESS;
3685
5278
  exports.ORDER_TYPE = ORDER_TYPE;
3686
5279
  exports.POLYGON_CHAIN_ID = POLYGON_CHAIN_ID;
@@ -3690,8 +5283,12 @@ exports.PredictClient = PredictClient;
3690
5283
  exports.PredictContext = PredictContext;
3691
5284
  exports.PredictProvider = PredictProvider;
3692
5285
  exports.PredictWsClient = PredictWsClient;
5286
+ exports.PredictionOrderRejectedError = PredictionOrderRejectedError;
5287
+ exports.RecoveryBarrier = RecoveryBarrier;
3693
5288
  exports.SIDE = SIDE;
3694
5289
  exports.USDC_ADDRESS = USDC_ADDRESS;
5290
+ exports.assertMarketDataBBAComponent = assertMarketDataBBAComponent;
5291
+ exports.assertMarketDataValueComponent = assertMarketDataValueComponent;
3695
5292
  exports.availableSharesQueryKey = availableSharesQueryKey;
3696
5293
  exports.balanceQueryKey = balanceQueryKey;
3697
5294
  exports.buildClobAuthMessage = buildClobAuthMessage;
@@ -3702,8 +5299,14 @@ exports.buildPolymarketL2Headers = buildPolymarketL2Headers;
3702
5299
  exports.buildSignedOrder = buildSignedOrder;
3703
5300
  exports.buildSignedV2OrderPayload = buildSignedV2OrderPayload;
3704
5301
  exports.candlesticksQueryKey = candlesticksQueryKey;
5302
+ exports.chunkWatchRequest = chunkWatchRequest;
5303
+ exports.comparePublicationCursor = comparePublicationCursor;
5304
+ exports.createInMemoryOrderPorts = createInMemoryOrderPorts;
3705
5305
  exports.createPredictClient = createPredictClient;
3706
5306
  exports.createPredictWsClient = createPredictWsClient;
5307
+ exports.createPredictionOrderRuntime = createPredictionOrderRuntime;
5308
+ exports.decodeBookEnvelope = decodeBookEnvelope;
5309
+ exports.decodeItemEnvelope = decodeItemEnvelope;
3707
5310
  exports.derivePolymarketApiKey = derivePolymarketApiKey;
3708
5311
  exports.dflowKYCQueryKey = dflowKYCQueryKey;
3709
5312
  exports.dflowQuoteQueryKey = dflowQuoteQueryKey;
@@ -3746,6 +5349,7 @@ exports.orderQueryKey = orderQueryKey;
3746
5349
  exports.orderbookQueryKey = orderbookQueryKey;
3747
5350
  exports.ordersMultiQueryKey = ordersMultiQueryKey;
3748
5351
  exports.ordersQueryKey = ordersQueryKey;
5352
+ exports.parseInitialQuotes = parseInitialQuotes;
3749
5353
  exports.pickBestAsk = pickBestAsk;
3750
5354
  exports.pickBestBid = pickBestBid;
3751
5355
  exports.polymarketDepositAddressesQueryKey = polymarketDepositAddressesQueryKey;
@@ -3795,6 +5399,9 @@ exports.useInfinitePredictSearch = useInfinitePredictSearch;
3795
5399
  exports.useInfiniteTrades = useInfiniteTrades;
3796
5400
  exports.useInfiniteTradesMulti = useInfiniteTradesMulti;
3797
5401
  exports.useMarket = useMarket;
5402
+ exports.useMarketDataCapability = useMarketDataCapability;
5403
+ exports.useMarketDataOrderbooks = useMarketDataOrderbooks;
5404
+ exports.useMarketDataResource = useMarketDataResource;
3798
5405
  exports.useMarketHistory = useMarketHistory;
3799
5406
  exports.useMarketTrades = useMarketTrades;
3800
5407
  exports.useMatch = useMatch;