UNPKG

@itick/browser-sdk

Version:

Official iTick API SDK for browser. Real-time & historical data for global Stocks, Forex, Crypto, Indices, Futures, Funds, Precious Metals. REST (OHLCV/K-line) + low-latency WebSocket. Promise-based, TypeScript-ready. For quant trading & fintech

197 lines 6.66 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildApiUrl = buildApiUrl; exports.buildWebSocketUrl = buildWebSocketUrl; exports.convertKlinePeriod = convertKlinePeriod; exports.convertSubscribeType = convertSubscribeType; exports.parseeSubscribeType = parseeSubscribeType; exports.parseSymbols = parseSymbols; exports.makeHttpRequest = makeHttpRequest; exports.createWebSocket = createWebSocket; const kline_1 = require("../types/kline"); const socket_1 = require("../types/socket"); const STRICT_SYMBOL_REGEX = /^[A-Za-z0-9]+\$[A-Za-z0-9]+$/; function buildApiUrl(baseURL, path) { return `${baseURL.replace(/\/$/, '')}${path}`; } function buildWebSocketUrl(wssURL, path) { return `${wssURL.replace(/\/$/, '')}${path}`; } /** * Convert K-line period string to number */ function convertKlinePeriod(period) { if (period === kline_1.KlinePeriod.ONE_MIN) return 1; if (period === kline_1.KlinePeriod.FIVE_MIN) return 2; if (period === kline_1.KlinePeriod.FIFTEEN_MIN) return 3; if (period === kline_1.KlinePeriod.THIRTY_MIN) return 4; if (period === kline_1.KlinePeriod.ONE_HOUR) return 5; if (period === kline_1.KlinePeriod.TWO_HOUR) return 6; if (period === kline_1.KlinePeriod.FOUR_HOUR) return 7; if (period === kline_1.KlinePeriod.ONE_DAY) return 8; if (period === kline_1.KlinePeriod.ONE_WEEK) return 9; if (period === kline_1.KlinePeriod.ONE_MONTH) return 10; return period; } /** * Convert websocket subscription type */ function convertSubscribeType(type) { if (type === socket_1.SubscribeType.KLINE_1M) return 'kline@1'; if (type === socket_1.SubscribeType.KLINE_5M) return 'kline@2'; if (type === socket_1.SubscribeType.KLINE_15M) return 'kline@3'; if (type === socket_1.SubscribeType.KLINE_30M) return 'kline@4'; if (type === socket_1.SubscribeType.KLINE_1H) return 'kline@5'; if (type === socket_1.SubscribeType.KLINE_2H) return 'kline@6'; if (type === socket_1.SubscribeType.KLINE_4H) return 'kline@7'; if (type === socket_1.SubscribeType.KLINE_1D) return 'kline@8'; if (type === socket_1.SubscribeType.KLINE_1W) return 'kline@9'; if (type === socket_1.SubscribeType.KLINE_1MTH) return 'kline@10'; return type; } /** * Convert subscription type list */ function parseeSubscribeType(type) { let rawList; if (Array.isArray(type)) rawList = type.map(String); else rawList = type.split(','); const validTypes = Object.values(socket_1.SubscribeType); const processedList = []; const apiToEnumMap = {}; for (const enumValue of validTypes) { // Ensure enumValue is a valid SubscribeType if (typeof enumValue === 'string' || typeof enumValue === 'number') { const apiFormat = convertSubscribeType(enumValue); apiToEnumMap[apiFormat] = enumValue; } } for (const item of rawList) { const trimmed = item.trim(); if (!trimmed) continue; let targetEnum; const isValid = validTypes.some(v => v === trimmed); if (isValid) targetEnum = trimmed; else targetEnum = apiToEnumMap[trimmed]; if (!targetEnum) throw new Error(`Invalid subscribe type: "${trimmed}". Valid types are: ${validTypes.join(', ')}`); processedList.push(convertSubscribeType(trimmed)); } return [...new Set(processedList)].join(','); } /** * Subscription product parameter formatting function * @param input Subscription parameters */ function parseSymbols(input) { const list = Array.isArray(input) ? input : input.split(','); return [...new Set(list .map(item => item.trim()) .filter(Boolean) .map(item => { if (!STRICT_SYMBOL_REGEX.test(item)) throw new Error(`Invalid symbol format: "${item}". Expected format is "SYMBOL$REGION", e.g. "AAPL$US".`); return item.toUpperCase(); }))].join(','); } /** * Build query string */ function buildQueryString(params) { return Object.entries(params) .filter(([_, value]) => value != null) .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) .join('&'); } /** * HTTP request implementation for Browser environment (using fetch API) */ async function makeHttpRequest(url, options = {}) { const { method = 'GET', headers = {}, body, params = {}, } = options; // Build complete URL let finalUrl = url; // For GET requests, append params to URL if (method === 'GET' && Object.keys(params).length > 0) { const queryString = buildQueryString(params); // Handle existing query parameters in the base URL const separator = finalUrl.includes('?') ? '&' : '?'; finalUrl = `${finalUrl}${separator}${queryString}`; } // Prepare fetch options const fetchOptions = { method, headers: { 'Content-Type': 'application/json', ...headers, }, }; // Attach body for non-GET methods if (body && method !== 'GET') { fetchOptions.body = body; } try { const response = await fetch(finalUrl, fetchOptions); // Extract headers as a plain object const responseHeaders = {}; response.headers.forEach((value, key) => { responseHeaders[key] = value; }); // Parse JSON response let data; const contentType = response.headers.get('content-type'); if (contentType && contentType.includes('application/json')) { try { data = await response.json(); } catch (e) { // Fallback to text if JSON parsing fails but content-type suggests JSON data = await response.text(); } } else { // For non-JSON responses, get text data = await response.text(); } return { status: response.status, data, headers: responseHeaders, }; } catch (error) { // Network errors or other fetch failures throw new Error(`Request failed: ${error instanceof Error ? error.message : String(error)}`); } } /** * Create WebSocket instance (Browser environment) */ async function createWebSocket(url, token) { return new WebSocket(`${url}?token=${token}`); } //# sourceMappingURL=index.js.map