index.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import axios from "axios";
  2. import { randomUUID } from "crypto";
  3. import { HttpsProxyAgent } from "https-proxy-agent";
  4. const PINNACLE_HOST = "https://api.pinnacle888.com";
  5. const axiosDefaultOptions = {
  6. baseURL: "",
  7. url: "",
  8. method: "GET",
  9. headers: {},
  10. params: {},
  11. data: {},
  12. timeout: 10000,
  13. };
  14. const cleanUndefined = (obj) => {
  15. return Object.fromEntries(
  16. Object.entries(obj).filter(([, value]) => value !== undefined)
  17. );
  18. }
  19. export const createPinnacleSdk = (config = {}) => {
  20. const proxyAgent = config.httpProxy ? new HttpsProxyAgent(config.httpProxy) : undefined;
  21. const pinnacleRequest = async (options, channel) => {
  22. const { url, ...optionsRest } = options;
  23. const { username, password } = config;
  24. if (!url || !channel && (!username || !password)) {
  25. throw new Error("url、username、password、channel is required");
  26. }
  27. const authHeader = channel
  28. ? `Basic ${channel}`
  29. : `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
  30. const axiosConfig = {
  31. ...axiosDefaultOptions,
  32. ...optionsRest,
  33. url,
  34. baseURL: PINNACLE_HOST,
  35. proxy: false,
  36. ...(proxyAgent ? { httpsAgent: proxyAgent } : {}),
  37. headers: {
  38. ...axiosDefaultOptions.headers,
  39. ...optionsRest.headers,
  40. Authorization: authHeader,
  41. Accept: "application/json",
  42. },
  43. };
  44. return axios(axiosConfig).then(res => res.data);
  45. }
  46. const pinnacleGet = async (url, params, channel) => {
  47. return pinnacleRequest({ url, params }, channel)
  48. .catch(err => {
  49. if (err.response?.data) {
  50. err.data = err.response.data;
  51. err.cause = err.response.status;
  52. }
  53. return Promise.reject(err);
  54. });
  55. }
  56. const pinnaclePost = async (url, data, channel) => {
  57. return pinnacleRequest({
  58. url,
  59. method: "POST",
  60. headers: {
  61. "Content-Type": "application/json",
  62. },
  63. data,
  64. }, channel);
  65. }
  66. const getLineInfo = async ({ info = {}, channel } = {}) => {
  67. const {
  68. leagueId, eventId, betType, handicap, team, side,
  69. specialId, contestantId,
  70. periodNumber = 0, oddsFormat = "Decimal", sportId = 29,
  71. } = info;
  72. let url = "/v2/line/";
  73. let data = { sportId, leagueId, eventId, betType, handicap, periodNumber, team, side, oddsFormat };
  74. if (specialId) {
  75. url = "/v2/line/special";
  76. data = { specialId, contestantId, oddsFormat };
  77. }
  78. data = cleanUndefined(data);
  79. return pinnacleGet(url, data, channel)
  80. .then(ret => ({ info: ret, line: data }));
  81. }
  82. const getAccountBalance = async (channel) => {
  83. return pinnacleGet("/v1/client/balance", undefined, channel);
  84. }
  85. const placeOrder = async ({ info, line, stakeSize } = {}, channel) => {
  86. const uuid = randomUUID();
  87. if (line.specialId) {
  88. const data = cleanUndefined({
  89. oddsFormat: line.oddsFormat,
  90. uniqueRequestId: uuid,
  91. acceptBetterLine: true,
  92. stake: stakeSize,
  93. winRiskStake: "RISK",
  94. lineId: info.lineId,
  95. specialId: info.specialId,
  96. contestantId: info.contestantId,
  97. });
  98. return pinnaclePost("/v4/bets/special", { bets: [data] }, channel)
  99. .then(ret => ret.bets?.[0] ?? ret);
  100. }
  101. const data = cleanUndefined({
  102. oddsFormat: line.oddsFormat,
  103. uniqueRequestId: uuid,
  104. acceptBetterLine: true,
  105. stake: stakeSize,
  106. winRiskStake: "RISK",
  107. lineId: info.lineId,
  108. altLineId: info.altLineId,
  109. fillType: "NORMAL",
  110. sportId: line.sportId,
  111. eventId: line.eventId,
  112. periodNumber: line.periodNumber,
  113. betType: line.betType,
  114. team: line.team,
  115. side: line.side,
  116. handicap: line.handicap,
  117. });
  118. return pinnaclePost("/v4/bets/place", data, channel);
  119. }
  120. return {
  121. pinnacleRequest,
  122. pinnacleGet,
  123. pinnaclePost,
  124. getLineInfo,
  125. getAccountBalance,
  126. placeOrder,
  127. };
  128. }
  129. export default createPinnacleSdk;