@tickerall/sdk 0.1.2 → 0.1.3
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 +7 -7
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,10 +20,10 @@ import { Tickerall } from '@tickerall/sdk'
|
|
|
20
20
|
const ticker = new Tickerall({ apiKey: process.env.TICKERALL_API_KEY! })
|
|
21
21
|
|
|
22
22
|
const { accountId } = await ticker.sessions.start({
|
|
23
|
-
broker: '
|
|
24
|
-
server: 'Exness-
|
|
25
|
-
account:
|
|
26
|
-
password: process.env.
|
|
23
|
+
broker: 'mt5',
|
|
24
|
+
server: 'Exness-MT5Trial7',
|
|
25
|
+
account: 12345678,
|
|
26
|
+
password: process.env.MT5_PASSWORD!,
|
|
27
27
|
})
|
|
28
28
|
|
|
29
29
|
const order = await ticker.orders.place(accountId, {
|
|
@@ -57,9 +57,9 @@ Multiple `Tickerall` instances are independent — useful for multi-tenant code.
|
|
|
57
57
|
|
|
58
58
|
```ts
|
|
59
59
|
const session = await ticker.sessions.start({
|
|
60
|
-
broker: '
|
|
61
|
-
server: 'Exness-
|
|
62
|
-
account:
|
|
60
|
+
broker: 'mt5',
|
|
61
|
+
server: 'Exness-MT5Trial7',
|
|
62
|
+
account: 12345678,
|
|
63
63
|
password: '...',
|
|
64
64
|
})
|
|
65
65
|
// { accountId, isDemo, status: 'connected', expiresAt }
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var events=require('events'),p=require('ws');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var p__default=/*#__PURE__*/_interopDefault(p);var a=class extends Error{constructor(e){super(e.message),this.name="TickerallApiError",this.status=e.status,this.code=e.code,this.requestId=e.requestId,this.details=e.details,this.transient=e.transient??false;}},h=class extends a{constructor(e){super(e),this.name="TickerallAuthError";}},y=class extends a{constructor(e){super(e),this.name="TickerallForbiddenError";}},g=class extends a{constructor(e){super(e),this.name="TickerallValidationError";}},f=class extends a{constructor(e){super(e),this.name="TickerallNotFoundError";}},T=class extends a{constructor(e){super(e),this.name="TickerallBrokerError";}},d=class extends a{constructor(e){super({...e,transient:true}),this.name="TickerallServiceUnavailableError";}},$=new Set(["BROKER_REJECTED","BROKER_AUTH_FAILED","BROKER_UNREACHABLE","BROKER_ACCOUNT_NOT_HOT","BROKER_ACCOUNT_ALREADY_LINKED","BROKER_ACCOUNT_NOT_FOUND","TICKET_NOT_FOUND"]);function q(r){return r.code==="POOL_SHUTTING_DOWN"?new d(r):$.has(r.code)?new T(r):r.status===401?new h(r):r.status===403?new y(r):r.status===404?new f(r):r.status===400||r.status===422?new g(r):r.status===503||r.status===502?new d(r):new a(r)}var b=class{constructor(e){this.client=e;}start(e,t){return this.client.requestIdempotent({method:"POST",path:"/v1/sessions",body:e},t)}async keepAlive(e,t){let s=await this.start(e,t);return this.client.registerKeptSession(s.accountId,e),s}stopKeepAlive(e){this.client.unregisterKeptSession(e);}rearm(e){return this.client.rearm(e)}async pendingRearm(e){return (await this.client.requestPlain({method:"GET",path:"/v1/always-hot/pending"},e)).pending}async rearmPending(e){let t=await this.pendingRearm(e),s=new Set(this.client.keptSessionIds()),n=[];for(let i of t)s.has(i.id)&&(await this.client.rearm(i.id).catch(()=>{}),n.push(i.id));return n}end(e,t){return this.client.unregisterKeptSession(e),this.client.requestPlain({method:"DELETE",path:`/v1/sessions/${encodeURIComponent(e)}`,expectNoContent:true},t)}};var R=class{constructor(e){this.client=e;}list(e){return this.client.requestPlain({method:"GET",path:"/v1/accounts"},e)}get(e,t){return this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}`,accountId:e},t)}async symbols(e,t){return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/symbols`,accountId:e},t)).symbols}async symbolSpecs(e,t){return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/symbol-specs`,accountId:e},t)).specs}};var P=class{constructor(e){this.client=e;}place(e,t,s){return this.client.requestIdempotent({method:"POST",path:`/v1/accounts/${encodeURIComponent(e)}/orders`,body:t,accountId:e},s)}async listPending(e,t={},s){let n=t.waitMs!==void 0?`?waitMs=${encodeURIComponent(String(t.waitMs))}`:"";return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/orders/pending${n}`,accountId:e},s)).orders}cancelPending(e,t,s){return this.client.requestIdempotent({method:"DELETE",path:`/v1/accounts/${encodeURIComponent(e)}/orders/${t}`,accountId:e},s)}modifyPending(e,t,s,n){return this.client.requestIdempotent({method:"PATCH",path:`/v1/accounts/${encodeURIComponent(e)}/orders/${t}`,body:s,accountId:e},n)}};var v=class{constructor(e){this.client=e;}close(e,t,s={},n){return this.client.requestIdempotent({method:"DELETE",path:`/v1/accounts/${encodeURIComponent(e)}/positions/${t}`,body:s,accountId:e},n)}modify(e,t,s,n){return this.client.requestIdempotent({method:"PATCH",path:`/v1/accounts/${encodeURIComponent(e)}/positions/${t}`,body:s,accountId:e},n)}};var K=25e3,L=1e4,U=[1e3,2e3,4e3,8e3,16e3,3e4],_=3e4,H={opened:"position-opened",updated:"position-updated",closed:"position-closed"},S=class extends events.EventEmitter{constructor(t,s,n){super();this.ws=null;this.closedByUser=false;this.state="closed";this.reconnectAttempts=0;this.reconnectTimer=null;this.heartbeatTimer=null;this.heartbeatTimeoutTimer=null;this.subs=new Map;this.url=t,this.headers={Authorization:`Bearer ${s}`,"User-Agent":n},this.on("error",()=>{});}on(t,s){return super.on(t,s)}once(t,s){return super.once(t,s)}off(t,s){return super.off(t,s)}async connect(){this.closedByUser=false,this.state="connecting",await this.openOnce();}setBeforeResubscribe(t){this.beforeResubscribe=t;}getState(){return this.state}isConnected(){return this.state==="open"&&this.ws?.readyState===p__default.default.OPEN}waitUntilConnected(t=3e4){return this.isConnected()?Promise.resolve():this.state==="closed"?Promise.reject(new Error("Stream is closed")):new Promise((s,n)=>{let i,o=()=>{clearTimeout(i),s();};i=setTimeout(()=>{this.off("open",o),n(new Error(`waitUntilConnected: timed out after ${t}ms`));},t),this.once("open",o);})}openOnce(){return new Promise((t,s)=>{let n=new p__default.default(this.url,{headers:this.headers});this.ws=n;let i=false,o=async()=>{if(i)return;i=true;let u=this.reconnectAttempts>0;if(this.state="open",this.reconnectAttempts=0,this.startHeartbeat(),u&&this.beforeResubscribe)try{await this.beforeResubscribe();}catch{}this.resendSubscriptions(),this.emit("open"),t();},m=u=>{try{let c=JSON.parse(u.toString());this.handleFrame(c);}catch(c){this.emit("error",{message:"Failed to parse server frame",cause:c});}},l=u=>{i||(i=true,s(u)),this.emit("error",{message:u.message,cause:u});},O=(u,c)=>{this.stopHeartbeat(),this.ws=null;let A=c?.toString()??"";this.emit("close",{code:u,reason:A}),i||(i=true,s(new Error(`WebSocket closed before open (code=${u})`))),this.closedByUser||(this.state="reconnecting",this.scheduleReconnect());};n.on("open",o),n.on("message",m),n.on("error",l),n.on("close",O),n.on("pong",()=>this.clearHeartbeatTimeout());})}handleFrame(t){switch(t.type){case "tick":this.emit("tick",{type:"tick",accountId:t.accountId,symbol:t.symbol,bid:t.bid,ask:t.ask,timestamp:t.timestamp});return;case "position_update":this.emit("position",{type:"position",accountId:t.accountId,event:H[t.event]??"position-updated",position:t.position});return;case "account_update":this.emit("account",{type:"account",accountId:t.accountId,snapshot:t.snapshot});return;case "subscribed":t.rejected&&t.rejected.length>0&&this.emit("error",{message:`Subscribe rejected: ${t.rejected.map(s=>`${s.code} (${s.reason})`).join(", ")}`});return;case "error":this.emit("error",{message:`${t.code}: ${t.message}`});return;case "pong":this.clearHeartbeatTimeout();return}}startHeartbeat(){this.stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{if(!(!this.ws||this.ws.readyState!==p__default.default.OPEN)){this.send({type:"ping"});try{this.ws.ping();}catch{}this.heartbeatTimeoutTimer=setTimeout(()=>this.forceReconnect("heartbeat-timeout"),L);}},K);}clearHeartbeatTimeout(){this.heartbeatTimeoutTimer&&(clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimeoutTimer=null);}stopHeartbeat(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimeoutTimer&&clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimer=null,this.heartbeatTimeoutTimer=null;}forceReconnect(t){if(this.ws)try{this.ws.terminate();}catch{}}scheduleReconnect(){if(this.closedByUser||this.reconnectTimer)return;let t=Math.min(this.reconnectAttempts,U.length-1),s=U[t]??_,n=Math.floor(Math.random()*Math.min(s,1e3)),i=Math.min(s+n,_+1e3);this.reconnectAttempts+=1;let o=this.reconnectAttempts;this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.emit("reconnect",{attempt:o}),this.openOnce().catch(m=>{this.emit("error",{message:"Reconnect failed",cause:m}),this.scheduleReconnect();});},i);}resendSubscriptions(){let t=[];for(let s of this.subs.values())s.kind==="ticks"?t.push({kind:"ticks",accountId:s.accountId,symbols:[...s.symbols]}):t.push({kind:s.kind,accountId:s.accountId});t.length>0&&this.send({type:"subscribe",channels:t});}send(t){if(!(!this.ws||this.ws.readyState!==p__default.default.OPEN))try{this.ws.send(JSON.stringify(t));}catch(s){this.emit("error",{message:"Failed to send frame",cause:s});}}async subscribeTicks(t,s){let n=E("ticks",t),i=this.subs.get(n);if(i&&i.kind==="ticks")for(let o of s)i.symbols.add(o);else this.subs.set(n,{kind:"ticks",accountId:t,symbols:new Set(s)});this.send({type:"subscribe",channels:[{kind:"ticks",accountId:t,symbols:s}]});}async unsubscribeTicks(t,s){let n=E("ticks",t),i=this.subs.get(n);if(i&&i.kind==="ticks"){for(let o of s)i.symbols.delete(o);i.symbols.size===0&&this.subs.delete(n);}this.send({type:"unsubscribe",channels:[{kind:"ticks",accountId:t,symbols:s}]});}async subscribePositions(t){this.subs.set(E("positions",t),{kind:"positions",accountId:t}),this.send({type:"subscribe",channels:[{kind:"positions",accountId:t}]});}async subscribeAccount(t){this.subs.set(E("account",t),{kind:"account",accountId:t}),this.send({type:"subscribe",channels:[{kind:"account",accountId:t}]});}async close(){this.closedByUser=true,this.state="closed",this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.stopHeartbeat();let t=this.ws;if(t&&t.readyState!==p__default.default.CLOSED)return new Promise(s=>{let n=()=>s();t.once("close",n);try{t.close();}catch{s();}})}};function E(r,e){return `${r}:${e}`}var k=class{constructor(e,t){this.client=e,this.streamUrl=t.streamUrl,this.apiKey=t.apiKey,this.userAgent=t.userAgent;}async connect(){let e=new S(this.streamUrl,this.apiKey,this.userAgent);return e.setBeforeResubscribe(()=>this.client.rearmAll()),await e.connect(),e}};var I=class{constructor(e){this.client=e;}async get(e,t,s){let n=new URLSearchParams({symbol:t.symbol,hours:String(t.hours)});return t.timeframe&&n.set("timeframe",t.timeframe),(await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/candles?${n.toString()}`},s)).candles}};function x(r){return r instanceof Date?r.toISOString():String(r)}var w=class{constructor(e){this.client=e;}async get(e,t={},s){let n=new URLSearchParams;t.symbol&&n.set("symbol",t.symbol),t.from!==void 0&&n.set("from",x(t.from)),t.to!==void 0&&n.set("to",x(t.to)),t.limit!==void 0&&n.set("limit",String(t.limit)),t.waitMs!==void 0&&n.set("waitMs",String(t.waitMs));let i=n.toString();return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/history${i?`?${i}`:""}`},s)).trades}};var B="https://api.tickerall.com",F="wss://api.tickerall.com/v1/stream",j=3e4,M="0.1.2",Q=6e4,N=[500,1e3,2e3,4e3,8e3];function G(r){return new Promise(e=>setTimeout(e,r))}var C=class{constructor(e){this.replayQueue=[];this.replayDraining=false;this.keptCreds=new Map;if(!e||!e.apiKey)throw new TypeError("Tickerall: `apiKey` is required.");this.apiKey=e.apiKey,this.baseUrl=W(e.baseUrl??B),this.streamUrl=e.streamUrl??F,this.timeout=e.timeout??j;let t=e.fetch??globalThis.fetch;if(typeof t!="function")throw new TypeError("Tickerall: no `fetch` available \u2014 pass `fetch` in the config (Node <18 needs an explicit fetch).");this.fetchImpl=t.bind(globalThis),this.userAgent=e.userAgent?`${e.userAgent} tickerall-js/${M}`:`tickerall-js/${M}`,this.onRearm=e.onRearm,this.sessions=new b(this),this.accounts=new R(this),this.orders=new P(this),this.positions=new v(this),this.candles=new I(this),this.history=new w(this),this.stream=new k(this,{streamUrl:this.streamUrl,apiKey:this.apiKey,userAgent:this.userAgent});}request(e){return this.requestWithRearm(e,false)}async requestWithRearm(e,t){try{return await this.requestOnce(e)}catch(s){if(!t&&e.accountId!==void 0&&this.keptCreds.has(e.accountId)&&s instanceof a&&s.code==="BROKER_ACCOUNT_NOT_HOT")return await this.rearm(e.accountId),this.requestWithRearm(e,true);throw s}}async requestOnce(e){let t=`${this.baseUrl}${e.path}`,s={Authorization:`Bearer ${this.apiKey}`,"User-Agent":this.userAgent,Accept:"application/json"};e.body!==void 0&&(s["Content-Type"]="application/json"),e.idempotencyKey&&(s["Idempotency-Key"]=e.idempotencyKey);let n=e.timeout??this.timeout,i=new AbortController,o=false,m=setTimeout(()=>{o=true,i.abort(new Error(`Request timed out after ${n}ms`));},n);e.signal&&(e.signal.aborted?i.abort(e.signal.reason):e.signal.addEventListener("abort",()=>i.abort(e.signal.reason),{once:true}));let l;try{l=await this.fetchImpl(t,{method:e.method,headers:s,body:e.body!==void 0?JSON.stringify(e.body):void 0,signal:i.signal});}catch(c){if(clearTimeout(m),o)throw new d({status:0,code:"REQUEST_TIMEOUT",message:`Request timed out after ${n}ms`});if(i.signal.aborted){let A=i.signal.reason?.message??c.message??"Request aborted";throw new a({status:0,code:"REQUEST_ABORTED",message:A})}throw new d({status:0,code:"NETWORK_ERROR",message:c.message||"Network request failed",details:c})}finally{clearTimeout(m);}let O=l.headers.get("x-request-id")??void 0;if(e.expectNoContent&&l.status===204)return;if(!l.ok){let c=await J(l);throw q({status:l.status,code:c?.error??`HTTP_${l.status}`,message:c?.message??l.statusText??"Request failed",details:c?.details,requestId:O})}return l.status===204?void 0:await l.json()}async requestIdempotent(e,t){let s=t?.idempotencyKey??Y(),n={...e,idempotencyKey:s,signal:t?.signal,timeout:t?.timeout};return t?.queueIfReconnecting?this.enqueueReplay(n,t.queueMaxMs??Q):this.request(n)}enqueueReplay(e,t){return new Promise((s,n)=>{this.replayQueue.push({run:()=>this.request(e),resolve:s,reject:n,deadline:Date.now()+t}),this.drainReplayQueue();})}async drainReplayQueue(){if(!this.replayDraining){this.replayDraining=true;try{for(;this.replayQueue.length>0;){let e=this.replayQueue[0];if(Date.now()>=e.deadline){e.reject(new d({status:0,code:"QUEUE_TIMEOUT",message:"Queued request expired before connectivity returned"})),this.replayQueue.shift();continue}let t=0;for(;;)try{e.resolve(await e.run()),this.replayQueue.shift();break}catch(s){let n=s instanceof a&&s.transient,i=e.deadline-Date.now();if(!n||i<=0){e.reject(s),this.replayQueue.shift();break}let o=N[Math.min(t,N.length-1)];t+=1,await G(Math.min(o,i));}}}finally{this.replayDraining=false;}}}requestPlain(e,t){return this.request({...e,signal:t?.signal,timeout:t?.timeout})}registerKeptSession(e,t){this.keptCreds.set(e,t);}unregisterKeptSession(e){this.keptCreds.delete(e);}keptSessionIds(){return [...this.keptCreds.keys()]}async rearm(e){let t=this.keptCreds.get(e);if(!t)throw new a({status:0,code:"NO_KEPT_CREDENTIALS",message:`No kept credentials for account ${e}; call sessions.keepAlive first.`});this.onRearm?.(e),await this.requestIdempotent({method:"POST",path:"/v1/sessions",body:t});}async rearmAll(){await Promise.all([...this.keptCreds.keys()].map(e=>this.rearm(e).catch(()=>{})));}};function W(r){return r.endsWith("/")?r.slice(0,-1):r}async function J(r){try{let e=await r.text();if(!e)return null;try{return JSON.parse(e)}catch{return {error:"PARSE_ERROR",message:e}}}catch{return null}}function Y(){let r=globalThis.crypto;return r&&typeof r.randomUUID=="function"?r.randomUUID():z()}function z(){let r=new Uint8Array(16);for(let t=0;t<16;t++)r[t]=Math.floor(Math.random()*256);r[6]=r[6]&15|64,r[8]=r[8]&63|128;let e=Array.from(r,t=>t.toString(16).padStart(2,"0")).join("");return `${e.slice(0,8)}-${e.slice(8,12)}-${e.slice(12,16)}-${e.slice(16,20)}-${e.slice(20)}`}
|
|
1
|
+
'use strict';var events=require('events'),p=require('ws');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var p__default=/*#__PURE__*/_interopDefault(p);var a=class extends Error{constructor(e){super(e.message),this.name="TickerallApiError",this.status=e.status,this.code=e.code,this.requestId=e.requestId,this.details=e.details,this.transient=e.transient??false;}},h=class extends a{constructor(e){super(e),this.name="TickerallAuthError";}},y=class extends a{constructor(e){super(e),this.name="TickerallForbiddenError";}},g=class extends a{constructor(e){super(e),this.name="TickerallValidationError";}},f=class extends a{constructor(e){super(e),this.name="TickerallNotFoundError";}},T=class extends a{constructor(e){super(e),this.name="TickerallBrokerError";}},d=class extends a{constructor(e){super({...e,transient:true}),this.name="TickerallServiceUnavailableError";}},$=new Set(["BROKER_REJECTED","BROKER_AUTH_FAILED","BROKER_UNREACHABLE","BROKER_ACCOUNT_NOT_HOT","BROKER_ACCOUNT_ALREADY_LINKED","BROKER_ACCOUNT_NOT_FOUND","TICKET_NOT_FOUND"]);function q(r){return r.code==="POOL_SHUTTING_DOWN"?new d(r):$.has(r.code)?new T(r):r.status===401?new h(r):r.status===403?new y(r):r.status===404?new f(r):r.status===400||r.status===422?new g(r):r.status===503||r.status===502?new d(r):new a(r)}var b=class{constructor(e){this.client=e;}start(e,t){return this.client.requestIdempotent({method:"POST",path:"/v1/sessions",body:e},t)}async keepAlive(e,t){let s=await this.start(e,t);return this.client.registerKeptSession(s.accountId,e),s}stopKeepAlive(e){this.client.unregisterKeptSession(e);}rearm(e){return this.client.rearm(e)}async pendingRearm(e){return (await this.client.requestPlain({method:"GET",path:"/v1/always-hot/pending"},e)).pending}async rearmPending(e){let t=await this.pendingRearm(e),s=new Set(this.client.keptSessionIds()),n=[];for(let i of t)s.has(i.id)&&(await this.client.rearm(i.id).catch(()=>{}),n.push(i.id));return n}end(e,t){return this.client.unregisterKeptSession(e),this.client.requestPlain({method:"DELETE",path:`/v1/sessions/${encodeURIComponent(e)}`,expectNoContent:true},t)}};var R=class{constructor(e){this.client=e;}list(e){return this.client.requestPlain({method:"GET",path:"/v1/accounts"},e)}get(e,t){return this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}`,accountId:e},t)}async symbols(e,t){return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/symbols`,accountId:e},t)).symbols}async symbolSpecs(e,t){return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/symbol-specs`,accountId:e},t)).specs}};var P=class{constructor(e){this.client=e;}place(e,t,s){return this.client.requestIdempotent({method:"POST",path:`/v1/accounts/${encodeURIComponent(e)}/orders`,body:t,accountId:e},s)}async listPending(e,t={},s){let n=t.waitMs!==void 0?`?waitMs=${encodeURIComponent(String(t.waitMs))}`:"";return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/orders/pending${n}`,accountId:e},s)).orders}cancelPending(e,t,s){return this.client.requestIdempotent({method:"DELETE",path:`/v1/accounts/${encodeURIComponent(e)}/orders/${t}`,accountId:e},s)}modifyPending(e,t,s,n){return this.client.requestIdempotent({method:"PATCH",path:`/v1/accounts/${encodeURIComponent(e)}/orders/${t}`,body:s,accountId:e},n)}};var v=class{constructor(e){this.client=e;}close(e,t,s={},n){return this.client.requestIdempotent({method:"DELETE",path:`/v1/accounts/${encodeURIComponent(e)}/positions/${t}`,body:s,accountId:e},n)}modify(e,t,s,n){return this.client.requestIdempotent({method:"PATCH",path:`/v1/accounts/${encodeURIComponent(e)}/positions/${t}`,body:s,accountId:e},n)}};var K=25e3,L=1e4,U=[1e3,2e3,4e3,8e3,16e3,3e4],_=3e4,H={opened:"position-opened",updated:"position-updated",closed:"position-closed"},S=class extends events.EventEmitter{constructor(t,s,n){super();this.ws=null;this.closedByUser=false;this.state="closed";this.reconnectAttempts=0;this.reconnectTimer=null;this.heartbeatTimer=null;this.heartbeatTimeoutTimer=null;this.subs=new Map;this.url=t,this.headers={Authorization:`Bearer ${s}`,"User-Agent":n},this.on("error",()=>{});}on(t,s){return super.on(t,s)}once(t,s){return super.once(t,s)}off(t,s){return super.off(t,s)}async connect(){this.closedByUser=false,this.state="connecting",await this.openOnce();}setBeforeResubscribe(t){this.beforeResubscribe=t;}getState(){return this.state}isConnected(){return this.state==="open"&&this.ws?.readyState===p__default.default.OPEN}waitUntilConnected(t=3e4){return this.isConnected()?Promise.resolve():this.state==="closed"?Promise.reject(new Error("Stream is closed")):new Promise((s,n)=>{let i,o=()=>{clearTimeout(i),s();};i=setTimeout(()=>{this.off("open",o),n(new Error(`waitUntilConnected: timed out after ${t}ms`));},t),this.once("open",o);})}openOnce(){return new Promise((t,s)=>{let n=new p__default.default(this.url,{headers:this.headers});this.ws=n;let i=false,o=async()=>{if(i)return;i=true;let u=this.reconnectAttempts>0;if(this.state="open",this.reconnectAttempts=0,this.startHeartbeat(),u&&this.beforeResubscribe)try{await this.beforeResubscribe();}catch{}this.resendSubscriptions(),this.emit("open"),t();},m=u=>{try{let c=JSON.parse(u.toString());this.handleFrame(c);}catch(c){this.emit("error",{message:"Failed to parse server frame",cause:c});}},l=u=>{i||(i=true,s(u)),this.emit("error",{message:u.message,cause:u});},O=(u,c)=>{this.stopHeartbeat(),this.ws=null;let A=c?.toString()??"";this.emit("close",{code:u,reason:A}),i||(i=true,s(new Error(`WebSocket closed before open (code=${u})`))),this.closedByUser||(this.state="reconnecting",this.scheduleReconnect());};n.on("open",o),n.on("message",m),n.on("error",l),n.on("close",O),n.on("pong",()=>this.clearHeartbeatTimeout());})}handleFrame(t){switch(t.type){case "tick":this.emit("tick",{type:"tick",accountId:t.accountId,symbol:t.symbol,bid:t.bid,ask:t.ask,timestamp:t.timestamp});return;case "position_update":this.emit("position",{type:"position",accountId:t.accountId,event:H[t.event]??"position-updated",position:t.position});return;case "account_update":this.emit("account",{type:"account",accountId:t.accountId,snapshot:t.snapshot});return;case "subscribed":t.rejected&&t.rejected.length>0&&this.emit("error",{message:`Subscribe rejected: ${t.rejected.map(s=>`${s.code} (${s.reason})`).join(", ")}`});return;case "error":this.emit("error",{message:`${t.code}: ${t.message}`});return;case "pong":this.clearHeartbeatTimeout();return}}startHeartbeat(){this.stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{if(!(!this.ws||this.ws.readyState!==p__default.default.OPEN)){this.send({type:"ping"});try{this.ws.ping();}catch{}this.heartbeatTimeoutTimer=setTimeout(()=>this.forceReconnect("heartbeat-timeout"),L);}},K);}clearHeartbeatTimeout(){this.heartbeatTimeoutTimer&&(clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimeoutTimer=null);}stopHeartbeat(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimeoutTimer&&clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimer=null,this.heartbeatTimeoutTimer=null;}forceReconnect(t){if(this.ws)try{this.ws.terminate();}catch{}}scheduleReconnect(){if(this.closedByUser||this.reconnectTimer)return;let t=Math.min(this.reconnectAttempts,U.length-1),s=U[t]??_,n=Math.floor(Math.random()*Math.min(s,1e3)),i=Math.min(s+n,_+1e3);this.reconnectAttempts+=1;let o=this.reconnectAttempts;this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.emit("reconnect",{attempt:o}),this.openOnce().catch(m=>{this.emit("error",{message:"Reconnect failed",cause:m}),this.scheduleReconnect();});},i);}resendSubscriptions(){let t=[];for(let s of this.subs.values())s.kind==="ticks"?t.push({kind:"ticks",accountId:s.accountId,symbols:[...s.symbols]}):t.push({kind:s.kind,accountId:s.accountId});t.length>0&&this.send({type:"subscribe",channels:t});}send(t){if(!(!this.ws||this.ws.readyState!==p__default.default.OPEN))try{this.ws.send(JSON.stringify(t));}catch(s){this.emit("error",{message:"Failed to send frame",cause:s});}}async subscribeTicks(t,s){let n=E("ticks",t),i=this.subs.get(n);if(i&&i.kind==="ticks")for(let o of s)i.symbols.add(o);else this.subs.set(n,{kind:"ticks",accountId:t,symbols:new Set(s)});this.send({type:"subscribe",channels:[{kind:"ticks",accountId:t,symbols:s}]});}async unsubscribeTicks(t,s){let n=E("ticks",t),i=this.subs.get(n);if(i&&i.kind==="ticks"){for(let o of s)i.symbols.delete(o);i.symbols.size===0&&this.subs.delete(n);}this.send({type:"unsubscribe",channels:[{kind:"ticks",accountId:t,symbols:s}]});}async subscribePositions(t){this.subs.set(E("positions",t),{kind:"positions",accountId:t}),this.send({type:"subscribe",channels:[{kind:"positions",accountId:t}]});}async subscribeAccount(t){this.subs.set(E("account",t),{kind:"account",accountId:t}),this.send({type:"subscribe",channels:[{kind:"account",accountId:t}]});}async close(){this.closedByUser=true,this.state="closed",this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.stopHeartbeat();let t=this.ws;if(t&&t.readyState!==p__default.default.CLOSED)return new Promise(s=>{let n=()=>s();t.once("close",n);try{t.close();}catch{s();}})}};function E(r,e){return `${r}:${e}`}var k=class{constructor(e,t){this.client=e,this.streamUrl=t.streamUrl,this.apiKey=t.apiKey,this.userAgent=t.userAgent;}async connect(){let e=new S(this.streamUrl,this.apiKey,this.userAgent);return e.setBeforeResubscribe(()=>this.client.rearmAll()),await e.connect(),e}};var I=class{constructor(e){this.client=e;}async get(e,t,s){let n=new URLSearchParams({symbol:t.symbol,hours:String(t.hours)});return t.timeframe&&n.set("timeframe",t.timeframe),(await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/candles?${n.toString()}`},s)).candles}};function x(r){return r instanceof Date?r.toISOString():String(r)}var w=class{constructor(e){this.client=e;}async get(e,t={},s){let n=new URLSearchParams;t.symbol&&n.set("symbol",t.symbol),t.from!==void 0&&n.set("from",x(t.from)),t.to!==void 0&&n.set("to",x(t.to)),t.limit!==void 0&&n.set("limit",String(t.limit)),t.waitMs!==void 0&&n.set("waitMs",String(t.waitMs));let i=n.toString();return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/history${i?`?${i}`:""}`},s)).trades}};var B="https://api.tickerall.com",F="wss://api.tickerall.com/v1/stream",j=3e4,M="0.1.3",Q=6e4,N=[500,1e3,2e3,4e3,8e3];function G(r){return new Promise(e=>setTimeout(e,r))}var C=class{constructor(e){this.replayQueue=[];this.replayDraining=false;this.keptCreds=new Map;if(!e||!e.apiKey)throw new TypeError("Tickerall: `apiKey` is required.");this.apiKey=e.apiKey,this.baseUrl=W(e.baseUrl??B),this.streamUrl=e.streamUrl??F,this.timeout=e.timeout??j;let t=e.fetch??globalThis.fetch;if(typeof t!="function")throw new TypeError("Tickerall: no `fetch` available \u2014 pass `fetch` in the config (Node <18 needs an explicit fetch).");this.fetchImpl=t.bind(globalThis),this.userAgent=e.userAgent?`${e.userAgent} tickerall-js/${M}`:`tickerall-js/${M}`,this.onRearm=e.onRearm,this.sessions=new b(this),this.accounts=new R(this),this.orders=new P(this),this.positions=new v(this),this.candles=new I(this),this.history=new w(this),this.stream=new k(this,{streamUrl:this.streamUrl,apiKey:this.apiKey,userAgent:this.userAgent});}request(e){return this.requestWithRearm(e,false)}async requestWithRearm(e,t){try{return await this.requestOnce(e)}catch(s){if(!t&&e.accountId!==void 0&&this.keptCreds.has(e.accountId)&&s instanceof a&&s.code==="BROKER_ACCOUNT_NOT_HOT")return await this.rearm(e.accountId),this.requestWithRearm(e,true);throw s}}async requestOnce(e){let t=`${this.baseUrl}${e.path}`,s={Authorization:`Bearer ${this.apiKey}`,"User-Agent":this.userAgent,Accept:"application/json"};e.body!==void 0&&(s["Content-Type"]="application/json"),e.idempotencyKey&&(s["Idempotency-Key"]=e.idempotencyKey);let n=e.timeout??this.timeout,i=new AbortController,o=false,m=setTimeout(()=>{o=true,i.abort(new Error(`Request timed out after ${n}ms`));},n);e.signal&&(e.signal.aborted?i.abort(e.signal.reason):e.signal.addEventListener("abort",()=>i.abort(e.signal.reason),{once:true}));let l;try{l=await this.fetchImpl(t,{method:e.method,headers:s,body:e.body!==void 0?JSON.stringify(e.body):void 0,signal:i.signal});}catch(c){if(clearTimeout(m),o)throw new d({status:0,code:"REQUEST_TIMEOUT",message:`Request timed out after ${n}ms`});if(i.signal.aborted){let A=i.signal.reason?.message??c.message??"Request aborted";throw new a({status:0,code:"REQUEST_ABORTED",message:A})}throw new d({status:0,code:"NETWORK_ERROR",message:c.message||"Network request failed",details:c})}finally{clearTimeout(m);}let O=l.headers.get("x-request-id")??void 0;if(e.expectNoContent&&l.status===204)return;if(!l.ok){let c=await J(l);throw q({status:l.status,code:c?.error??`HTTP_${l.status}`,message:c?.message??l.statusText??"Request failed",details:c?.details,requestId:O})}return l.status===204?void 0:await l.json()}async requestIdempotent(e,t){let s=t?.idempotencyKey??Y(),n={...e,idempotencyKey:s,signal:t?.signal,timeout:t?.timeout};return t?.queueIfReconnecting?this.enqueueReplay(n,t.queueMaxMs??Q):this.request(n)}enqueueReplay(e,t){return new Promise((s,n)=>{this.replayQueue.push({run:()=>this.request(e),resolve:s,reject:n,deadline:Date.now()+t}),this.drainReplayQueue();})}async drainReplayQueue(){if(!this.replayDraining){this.replayDraining=true;try{for(;this.replayQueue.length>0;){let e=this.replayQueue[0];if(Date.now()>=e.deadline){e.reject(new d({status:0,code:"QUEUE_TIMEOUT",message:"Queued request expired before connectivity returned"})),this.replayQueue.shift();continue}let t=0;for(;;)try{e.resolve(await e.run()),this.replayQueue.shift();break}catch(s){let n=s instanceof a&&s.transient,i=e.deadline-Date.now();if(!n||i<=0){e.reject(s),this.replayQueue.shift();break}let o=N[Math.min(t,N.length-1)];t+=1,await G(Math.min(o,i));}}}finally{this.replayDraining=false;}}}requestPlain(e,t){return this.request({...e,signal:t?.signal,timeout:t?.timeout})}registerKeptSession(e,t){this.keptCreds.set(e,t);}unregisterKeptSession(e){this.keptCreds.delete(e);}keptSessionIds(){return [...this.keptCreds.keys()]}async rearm(e){let t=this.keptCreds.get(e);if(!t)throw new a({status:0,code:"NO_KEPT_CREDENTIALS",message:`No kept credentials for account ${e}; call sessions.keepAlive first.`});this.onRearm?.(e),await this.requestIdempotent({method:"POST",path:"/v1/sessions",body:t});}async rearmAll(){await Promise.all([...this.keptCreds.keys()].map(e=>this.rearm(e).catch(()=>{})));}};function W(r){return r.endsWith("/")?r.slice(0,-1):r}async function J(r){try{let e=await r.text();if(!e)return null;try{return JSON.parse(e)}catch{return {error:"PARSE_ERROR",message:e}}}catch{return null}}function Y(){let r=globalThis.crypto;return r&&typeof r.randomUUID=="function"?r.randomUUID():z()}function z(){let r=new Uint8Array(16);for(let t=0;t<16;t++)r[t]=Math.floor(Math.random()*256);r[6]=r[6]&15|64,r[8]=r[8]&63|128;let e=Array.from(r,t=>t.toString(16).padStart(2,"0")).join("");return `${e.slice(0,8)}-${e.slice(8,12)}-${e.slice(12,16)}-${e.slice(16,20)}-${e.slice(20)}`}
|
|
2
2
|
exports.Tickerall=C;exports.TickerallApiError=a;exports.TickerallAuthError=h;exports.TickerallBrokerError=T;exports.TickerallForbiddenError=y;exports.TickerallNotFoundError=f;exports.TickerallServiceUnavailableError=d;exports.TickerallStream=S;exports.TickerallValidationError=g;//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/namespaces/sessions.ts","../src/namespaces/accounts.ts","../src/namespaces/orders.ts","../src/namespaces/positions.ts","../src/namespaces/stream.ts","../src/namespaces/candles.ts","../src/namespaces/history.ts","../src/client.ts"],"names":["TickerallApiError","init","TickerallAuthError","TickerallForbiddenError","TickerallValidationError","TickerallNotFoundError","TickerallBrokerError","TickerallServiceUnavailableError","BROKER_CODES","mapErrorResponse","SessionsNamespace","client","params","options","result","accountId","pending","kept","rearmed","p","AccountsNamespace","OrdersNamespace","query","ticket","PositionsNamespace","HEARTBEAT_INTERVAL_MS","HEARTBEAT_TIMEOUT_MS","RECONNECT_DELAYS","RECONNECT_MAX_MS","POSITION_PHASE_MAP","TickerallStream","EventEmitter","url","apiKey","userAgent","event","listener","cb","WebSocket","timeoutMs","resolve","reject","timer","onOpen","ws","settled","wasReconnect","onMessage","data","frame","err","onError","onClose","code","reason","reasonStr","r","_reason","idx","base","jitter","delay","attempt","channels","sub","symbols","key","subKey","existing","s","topic","StreamNamespace","config","stream","CandlesNamespace","toQueryTime","v","HistoryNamespace","qs","DEFAULT_BASE_URL","DEFAULT_STREAM_URL","DEFAULT_TIMEOUT_MS","SDK_VERSION","DEFAULT_QUEUE_MAX_MS","REPLAY_DELAYS_MS","sleep","ms","Tickerall","trimTrailingSlash","resolvedFetch","isRearmRetry","headers","controller","timedOut","response","requestId","body","safeReadErrorBody","generateIdempotencyKey","full","maxMs","job","isTransient","remaining","creds","id","text","c","fallbackUuid","bytes","i","hex","b"],"mappings":"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","file":"index.js","sourcesContent":["export interface TickerallErrorInit {\n status: number\n code: string\n message: string\n requestId?: string\n details?: unknown\n /**\n * Transient = the request failed because TickerAll was momentarily\n * unreachable (network blip, deploy, restart) rather than because the\n * request itself was bad. Safe to retry. Set automatically for\n * `TickerallServiceUnavailableError`; `false` for every other error.\n */\n transient?: boolean\n}\n\nexport class TickerallApiError extends Error {\n readonly status: number\n readonly code: string\n readonly requestId?: string\n readonly details?: unknown\n /**\n * `true` when the failure is a momentary connectivity issue that is safe\n * to retry (see {@link TickerallServiceUnavailableError}). `false` for\n * application errors (auth, validation, broker rejection, …) that won't\n * change on retry. Use it to decide whether to back off and try again.\n */\n readonly transient: boolean\n\n constructor(init: TickerallErrorInit) {\n super(init.message)\n this.name = 'TickerallApiError'\n this.status = init.status\n this.code = init.code\n this.requestId = init.requestId\n this.details = init.details\n this.transient = init.transient ?? false\n }\n}\n\nexport class TickerallAuthError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallAuthError'\n }\n}\n\nexport class TickerallForbiddenError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallForbiddenError'\n }\n}\n\nexport class TickerallValidationError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallValidationError'\n }\n}\n\nexport class TickerallNotFoundError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallNotFoundError'\n }\n}\n\nexport class TickerallBrokerError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallBrokerError'\n }\n}\n\n/**\n * TickerAll was momentarily unreachable — a network blip, a deploy, or the\n * service restarting. This is NOT your fault and NOT a broker rejection: the\n * request never reached a verdict, so it's safe to retry. `transient` is\n * always `true`.\n *\n * The SDK throws this for network failures, request timeouts, and bare\n * 502/503s (and `POOL_SHUTTING_DOWN`). By default a trade fails fast with\n * this error so you can re-decide with fresh prices; pass\n * `{ queueIfReconnecting: true }` to instead queue the call and replay it\n * (with its stable idempotency key, so it can't double-execute) once\n * connectivity returns.\n */\nexport class TickerallServiceUnavailableError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super({ ...init, transient: true })\n this.name = 'TickerallServiceUnavailableError'\n }\n}\n\nconst BROKER_CODES = new Set([\n 'BROKER_REJECTED',\n 'BROKER_AUTH_FAILED',\n 'BROKER_UNREACHABLE',\n 'BROKER_ACCOUNT_NOT_HOT',\n 'BROKER_ACCOUNT_ALREADY_LINKED',\n 'BROKER_ACCOUNT_NOT_FOUND',\n 'TICKET_NOT_FOUND',\n])\n\nexport function mapErrorResponse(init: TickerallErrorInit): TickerallApiError {\n // The pool draining for a deploy/restart is the canonical transient case —\n // a retry lands on the fresh instance, so surface it as service-unavailable\n // (retryable) rather than a broker error.\n if (init.code === 'POOL_SHUTTING_DOWN') return new TickerallServiceUnavailableError(init)\n if (BROKER_CODES.has(init.code)) return new TickerallBrokerError(init)\n if (init.status === 401) return new TickerallAuthError(init)\n if (init.status === 403) return new TickerallForbiddenError(init)\n if (init.status === 404) return new TickerallNotFoundError(init)\n if (init.status === 400 || init.status === 422) return new TickerallValidationError(init)\n // A bare 502/503 with no recognised broker code is the proxy/load-balancer\n // reporting TickerAll itself as momentarily down (e.g. mid-deploy) — that's\n // transient and retryable. Broker-coded 5xx were already caught above.\n if (init.status === 503 || init.status === 502) return new TickerallServiceUnavailableError(init)\n return new TickerallApiError(init)\n}\n","import type { Tickerall } from '../client'\nimport type {\n IdempotentRequestOptions,\n PendingRearmAccount,\n RequestOptions,\n SessionStartParams,\n SessionStartResult,\n} from '../types'\n\nexport class SessionsNamespace {\n constructor(private readonly client: Tickerall) {}\n\n start(params: SessionStartParams, options?: IdempotentRequestOptions): Promise<SessionStartResult> {\n return this.client.requestIdempotent<SessionStartResult>(\n { method: 'POST', path: '/v1/sessions', body: params },\n options,\n )\n }\n\n /**\n * Start a session AND keep it alive: the broker credentials are cached in\n * this process's memory (never persisted) so the client transparently\n * re-arms the account if it later goes cold — e.g. after an atlas restart.\n * Pair with an always-hot account for a connection that stays up with no\n * manual reconnect. Call {@link stopKeepAlive} (or {@link end}) to forget\n * the credentials.\n */\n async keepAlive(params: SessionStartParams, options?: IdempotentRequestOptions): Promise<SessionStartResult> {\n const result = await this.start(params, options)\n this.client.registerKeptSession(result.accountId, params)\n return result\n }\n\n /** Stop auto-re-arming an account and drop its cached credentials. */\n stopKeepAlive(accountId: string): void {\n this.client.unregisterKeptSession(accountId)\n }\n\n /**\n * Manually re-arm a kept account now (a fresh session.start with the cached\n * credentials). Normally unnecessary — the client re-arms on demand — but\n * useful to proactively recover accounts listed by `GET /v1/always-hot/pending`.\n */\n rearm(accountId: string): Promise<void> {\n return this.client.rearm(accountId)\n }\n\n /**\n * Always-hot accounts that currently have no live connection — they need a\n * credentials refresh (e.g. after a TickerAll restart). Poll this after a\n * suspected outage; the next call or stream reconnect also re-arms them\n * automatically.\n */\n async pendingRearm(options?: RequestOptions): Promise<PendingRearmAccount[]> {\n const res = await this.client.requestPlain<{ pending: PendingRearmAccount[] }>(\n { method: 'GET', path: '/v1/always-hot/pending' },\n options,\n )\n return res.pending\n }\n\n /**\n * Re-arm every pending account we hold kept credentials for (the ones we\n * actually can recover). Returns the account IDs that were re-armed.\n */\n async rearmPending(options?: RequestOptions): Promise<string[]> {\n const pending = await this.pendingRearm(options)\n const kept = new Set(this.client.keptSessionIds())\n const rearmed: string[] = []\n for (const p of pending) {\n if (!kept.has(p.id)) continue\n await this.client.rearm(p.id).catch(() => { /* best-effort */ })\n rearmed.push(p.id)\n }\n return rearmed\n }\n\n end(accountId: string, options?: RequestOptions): Promise<void> {\n // Ending a session also stops keeping it alive.\n this.client.unregisterKeptSession(accountId)\n return this.client.requestPlain<void>(\n {\n method: 'DELETE',\n path: `/v1/sessions/${encodeURIComponent(accountId)}`,\n expectNoContent: true,\n },\n options,\n )\n }\n}\n","import type { Tickerall } from '../client'\nimport type {\n AccountDetail,\n AccountListing,\n RequestOptions,\n SymbolSpec,\n SymbolSpecsResponse,\n SymbolsResponse,\n} from '../types'\n\nexport class AccountsNamespace {\n constructor(private readonly client: Tickerall) {}\n\n list(options?: RequestOptions): Promise<AccountListing[]> {\n return this.client.requestPlain<AccountListing[]>(\n { method: 'GET', path: '/v1/accounts' },\n options,\n )\n }\n\n get(accountId: string, options?: RequestOptions): Promise<AccountDetail> {\n return this.client.requestPlain<AccountDetail>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}`, accountId },\n options,\n )\n }\n\n async symbols(accountId: string, options?: RequestOptions): Promise<string[]> {\n const res = await this.client.requestPlain<SymbolsResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/symbols`, accountId },\n options,\n )\n return res.symbols\n }\n\n /**\n * Per-symbol volume specs (min / max / step) for this account's tradeable\n * symbols — use these to check an order volume before placing it. Each spec\n * carries `specSource`: `'broker'` (the broker pushed it, authoritative) or\n * `'derived'` (filled from category defaults — best-effort). MT5 only; an\n * MT4 account returns an empty list.\n */\n async symbolSpecs(accountId: string, options?: RequestOptions): Promise<SymbolSpec[]> {\n const res = await this.client.requestPlain<SymbolSpecsResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/symbol-specs`, accountId },\n options,\n )\n return res.specs\n }\n}\n","import type { Tickerall } from '../client'\nimport type {\n CancelPendingResult,\n IdempotentRequestOptions,\n ListPendingParams,\n ModifyPendingParams,\n ModifyPendingResult,\n PendingOrder,\n PendingOrdersResponse,\n PlaceOrderParams,\n PlaceOrderResult,\n RequestOptions,\n} from '../types'\n\nexport class OrdersNamespace {\n constructor(private readonly client: Tickerall) {}\n\n place(\n accountId: string,\n params: PlaceOrderParams,\n options?: IdempotentRequestOptions,\n ): Promise<PlaceOrderResult> {\n return this.client.requestIdempotent<PlaceOrderResult>(\n {\n method: 'POST',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders`,\n body: params,\n accountId,\n },\n options,\n )\n }\n\n /**\n * List the account's resting pending orders (LIMIT / STOP). MT5 only — an\n * MT4 account returns an empty list. `waitMs` lets a just-warmed connection's\n * pending snapshot settle; pass 0 on a hot poller to skip the wait.\n */\n async listPending(\n accountId: string,\n params: ListPendingParams = {},\n options?: RequestOptions,\n ): Promise<PendingOrder[]> {\n const query = params.waitMs !== undefined ? `?waitMs=${encodeURIComponent(String(params.waitMs))}` : ''\n const res = await this.client.requestPlain<PendingOrdersResponse>(\n {\n method: 'GET',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders/pending${query}`,\n accountId,\n },\n options,\n )\n return res.orders\n }\n\n /**\n * Cancel a resting pending order by its ticket. MT5 only.\n */\n cancelPending(\n accountId: string,\n ticket: number,\n options?: IdempotentRequestOptions,\n ): Promise<CancelPendingResult> {\n return this.client.requestIdempotent<CancelPendingResult>(\n {\n method: 'DELETE',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders/${ticket}`,\n accountId,\n },\n options,\n )\n }\n\n /**\n * Modify a resting pending order's trigger price / SL / TP. Any field you\n * omit is preserved at its current value. Provide at least one. MT5 only.\n */\n modifyPending(\n accountId: string,\n ticket: number,\n params: ModifyPendingParams,\n options?: IdempotentRequestOptions,\n ): Promise<ModifyPendingResult> {\n return this.client.requestIdempotent<ModifyPendingResult>(\n {\n method: 'PATCH',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders/${ticket}`,\n body: params,\n accountId,\n },\n options,\n )\n }\n}\n","import type { Tickerall } from '../client'\nimport type {\n ClosePositionParams,\n ClosePositionResult,\n IdempotentRequestOptions,\n ModifyPositionParams,\n ModifyPositionResult,\n} from '../types'\n\nexport class PositionsNamespace {\n constructor(private readonly client: Tickerall) {}\n\n close(\n accountId: string,\n ticket: number,\n params: ClosePositionParams = {},\n options?: IdempotentRequestOptions,\n ): Promise<ClosePositionResult> {\n return this.client.requestIdempotent<ClosePositionResult>(\n {\n method: 'DELETE',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/positions/${ticket}`,\n body: params,\n accountId,\n },\n options,\n )\n }\n\n modify(\n accountId: string,\n ticket: number,\n params: ModifyPositionParams,\n options?: IdempotentRequestOptions,\n ): Promise<ModifyPositionResult> {\n return this.client.requestIdempotent<ModifyPositionResult>(\n {\n method: 'PATCH',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/positions/${ticket}`,\n body: params,\n accountId,\n },\n options,\n )\n }\n}\n","import { EventEmitter } from 'node:events'\nimport WebSocket from 'ws'\nimport type { Tickerall } from '../client'\nimport type {\n AccountEvent,\n PositionEvent,\n StreamCloseEvent,\n StreamErrorEvent,\n StreamReconnectEvent,\n StreamState,\n TickEvent,\n} from '../types'\n\nexport interface StreamConfig {\n streamUrl: string\n apiKey: string\n userAgent: string\n}\n\nexport interface StreamConnectOptions {\n signal?: AbortSignal\n}\n\nconst HEARTBEAT_INTERVAL_MS = 25_000\nconst HEARTBEAT_TIMEOUT_MS = 10_000\nconst RECONNECT_DELAYS = [1_000, 2_000, 4_000, 8_000, 16_000, 30_000]\nconst RECONNECT_MAX_MS = 30_000\n\ninterface TickSubscription {\n kind: 'ticks'\n accountId: string\n symbols: Set<string>\n}\n\ninterface AccountTopicSubscription {\n kind: 'positions' | 'account'\n accountId: string\n}\n\ntype Subscription = TickSubscription | AccountTopicSubscription\n\n// Subscription channels — the server subscribes by `{ kind, accountId, ... }`\n// wrapped in a `channels` array (see the server's ws/protocol).\ntype ChannelFrame =\n | { kind: 'ticks'; accountId: string; symbols: string[] }\n | { kind: 'positions'; accountId: string }\n | { kind: 'account'; accountId: string }\n\ninterface SubscribeFrame {\n type: 'subscribe'\n channels: ChannelFrame[]\n correlationId?: string\n}\n\ninterface UnsubscribeFrame {\n type: 'unsubscribe'\n channels: ChannelFrame[]\n correlationId?: string\n}\n\ntype ClientFrame = SubscribeFrame | UnsubscribeFrame | { type: 'ping' }\n\ninterface IncomingTick {\n type: 'tick'\n accountId: string\n symbol: string\n bid: number\n ask: number\n ordinal?: number\n subtype?: number\n timestamp: string\n}\n\n// The server emits position events as `position_update` with an\n// opened/updated/closed phase, and account events as `account_update`.\ninterface IncomingPositionUpdate {\n type: 'position_update'\n accountId: string\n event: 'opened' | 'updated' | 'closed'\n position: PositionEvent['position']\n}\n\ninterface IncomingAccountUpdate {\n type: 'account_update'\n accountId: string\n snapshot: AccountEvent['snapshot']\n}\n\ninterface IncomingPong {\n type: 'pong'\n ts?: number\n}\n\ninterface IncomingSubscribed {\n type: 'subscribed'\n channels: unknown[]\n rejected: Array<{ channel: unknown; reason: string; code: string }>\n correlationId?: string\n}\n\ninterface IncomingError {\n type: 'error'\n code: string\n message: string\n correlationId?: string\n}\n\ntype IncomingFrame =\n | IncomingTick\n | IncomingPositionUpdate\n | IncomingAccountUpdate\n | IncomingPong\n | IncomingSubscribed\n | IncomingError\n\nconst POSITION_PHASE_MAP: Record<string, PositionEvent['event']> = {\n opened: 'position-opened',\n updated: 'position-updated',\n closed: 'position-closed',\n}\n\nexport interface TickerallStreamEvents {\n tick: (e: TickEvent) => void\n position: (e: PositionEvent) => void\n account: (e: AccountEvent) => void\n error: (e: StreamErrorEvent) => void\n close: (e: StreamCloseEvent) => void\n reconnect: (e: StreamReconnectEvent) => void\n open: () => void\n}\n\nexport class TickerallStream extends EventEmitter {\n private ws: WebSocket | null = null\n private closedByUser = false\n private state: StreamState = 'closed'\n private beforeResubscribe?: () => Promise<void>\n private reconnectAttempts = 0\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null\n private heartbeatTimeoutTimer: ReturnType<typeof setTimeout> | null = null\n private readonly subs: Map<string, Subscription> = new Map()\n private readonly url: string\n private readonly headers: Record<string, string>\n\n constructor(url: string, apiKey: string, userAgent: string) {\n super()\n this.url = url\n this.headers = {\n 'Authorization': `Bearer ${apiKey}`,\n 'User-Agent': userAgent,\n }\n // Swallow `error` events that have no listener; the SDK reports errors\n // via the `error` event and via promise rejection on `connect()`, so a\n // missing listener should not crash the process.\n this.on('error', () => { /* noop default */ })\n }\n\n override on<E extends keyof TickerallStreamEvents>(event: E, listener: TickerallStreamEvents[E]): this {\n return super.on(event, listener as (...args: unknown[]) => void)\n }\n\n override once<E extends keyof TickerallStreamEvents>(event: E, listener: TickerallStreamEvents[E]): this {\n return super.once(event, listener as (...args: unknown[]) => void)\n }\n\n override off<E extends keyof TickerallStreamEvents>(event: E, listener: TickerallStreamEvents[E]): this {\n return super.off(event, listener as (...args: unknown[]) => void)\n }\n\n async connect(): Promise<void> {\n this.closedByUser = false\n this.state = 'connecting'\n await this.openOnce()\n }\n\n /**\n * Internal: callback run after a RECONNECT (not the initial connect), before\n * subscriptions are re-sent. The SDK wires this to re-arm kept sessions so a\n * connection transparently survives an atlas restart.\n */\n setBeforeResubscribe(cb: () => Promise<void>): void {\n this.beforeResubscribe = cb\n }\n\n /**\n * Current connection state. `'open'` means live; `'reconnecting'` means the\n * SDK is silently re-establishing the link (idle apps need do nothing).\n * Queryable any time — never thrown at you.\n */\n getState(): StreamState {\n return this.state\n }\n\n /** `true` only when the stream is live and ready to receive. */\n isConnected(): boolean {\n return this.state === 'open' && this.ws?.readyState === WebSocket.OPEN\n }\n\n /**\n * Resolve once the stream is live (immediately if already open), or reject\n * after `timeoutMs`. Rejects right away if the stream was closed by the\n * caller. Handy to gate logic on a confirmed connection without polling.\n */\n waitUntilConnected(timeoutMs = 30_000): Promise<void> {\n if (this.isConnected()) return Promise.resolve()\n if (this.state === 'closed') return Promise.reject(new Error('Stream is closed'))\n return new Promise<void>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout>\n const onOpen = (): void => {\n clearTimeout(timer)\n resolve()\n }\n timer = setTimeout(() => {\n this.off('open', onOpen)\n reject(new Error(`waitUntilConnected: timed out after ${timeoutMs}ms`))\n }, timeoutMs)\n this.once('open', onOpen)\n })\n }\n\n private openOnce(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const ws = new WebSocket(this.url, { headers: this.headers })\n this.ws = ws\n let settled = false\n\n const onOpen = async (): Promise<void> => {\n if (settled) return\n settled = true\n const wasReconnect = this.reconnectAttempts > 0\n this.state = 'open'\n this.reconnectAttempts = 0\n this.startHeartbeat()\n // After a RECONNECT (atlas may have restarted and lost the broker\n // session), re-arm kept sessions BEFORE resubscribing so the account\n // is hot again on atlas. Skipped on the initial connect.\n if (wasReconnect && this.beforeResubscribe) {\n try { await this.beforeResubscribe() } catch { /* best-effort */ }\n }\n this.resendSubscriptions()\n this.emit('open')\n resolve()\n }\n\n const onMessage = (data: WebSocket.RawData): void => {\n try {\n const frame = JSON.parse(data.toString()) as IncomingFrame\n this.handleFrame(frame)\n } catch (err) {\n this.emit('error', { message: 'Failed to parse server frame', cause: err })\n }\n }\n\n const onError = (err: Error): void => {\n if (!settled) {\n settled = true\n reject(err)\n }\n this.emit('error', { message: err.message, cause: err })\n }\n\n const onClose = (code: number, reason: Buffer): void => {\n this.stopHeartbeat()\n this.ws = null\n const reasonStr = reason?.toString() ?? ''\n this.emit('close', { code, reason: reasonStr })\n if (!settled) {\n settled = true\n reject(new Error(`WebSocket closed before open (code=${code})`))\n }\n if (!this.closedByUser) {\n this.state = 'reconnecting'\n this.scheduleReconnect()\n }\n }\n\n ws.on('open', onOpen)\n ws.on('message', onMessage)\n ws.on('error', onError)\n ws.on('close', onClose)\n ws.on('pong', () => this.clearHeartbeatTimeout())\n })\n }\n\n private handleFrame(frame: IncomingFrame): void {\n switch (frame.type) {\n case 'tick':\n this.emit('tick', {\n type: 'tick',\n accountId: frame.accountId,\n symbol: frame.symbol,\n bid: frame.bid,\n ask: frame.ask,\n timestamp: frame.timestamp,\n })\n return\n case 'position_update':\n this.emit('position', {\n type: 'position',\n accountId: frame.accountId,\n event: POSITION_PHASE_MAP[frame.event] ?? 'position-updated',\n position: frame.position,\n })\n return\n case 'account_update':\n this.emit('account', {\n type: 'account',\n accountId: frame.accountId,\n snapshot: frame.snapshot,\n })\n return\n case 'subscribed':\n if (frame.rejected && frame.rejected.length > 0) {\n this.emit('error', {\n message: `Subscribe rejected: ${frame.rejected.map(r => `${r.code} (${r.reason})`).join(', ')}`,\n })\n }\n return\n case 'error':\n this.emit('error', { message: `${frame.code}: ${frame.message}` })\n return\n case 'pong':\n this.clearHeartbeatTimeout()\n return\n }\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat()\n this.heartbeatTimer = setInterval(() => {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return\n this.send({ type: 'ping' })\n try { this.ws.ping() } catch { /* noop */ }\n this.heartbeatTimeoutTimer = setTimeout(() => this.forceReconnect('heartbeat-timeout'), HEARTBEAT_TIMEOUT_MS)\n }, HEARTBEAT_INTERVAL_MS)\n }\n\n private clearHeartbeatTimeout(): void {\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer)\n this.heartbeatTimeoutTimer = null\n }\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) clearInterval(this.heartbeatTimer)\n if (this.heartbeatTimeoutTimer) clearTimeout(this.heartbeatTimeoutTimer)\n this.heartbeatTimer = null\n this.heartbeatTimeoutTimer = null\n }\n\n private forceReconnect(_reason: string): void {\n if (!this.ws) return\n try { this.ws.terminate() } catch { /* noop */ }\n }\n\n private scheduleReconnect(): void {\n if (this.closedByUser) return\n if (this.reconnectTimer) return\n const idx = Math.min(this.reconnectAttempts, RECONNECT_DELAYS.length - 1)\n const base = RECONNECT_DELAYS[idx] ?? RECONNECT_MAX_MS\n const jitter = Math.floor(Math.random() * Math.min(base, 1_000))\n const delay = Math.min(base + jitter, RECONNECT_MAX_MS + 1_000)\n this.reconnectAttempts += 1\n const attempt = this.reconnectAttempts\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null\n this.emit('reconnect', { attempt })\n this.openOnce().catch(err => {\n this.emit('error', { message: 'Reconnect failed', cause: err })\n this.scheduleReconnect()\n })\n }, delay)\n }\n\n private resendSubscriptions(): void {\n const channels: ChannelFrame[] = []\n for (const sub of this.subs.values()) {\n if (sub.kind === 'ticks') {\n channels.push({ kind: 'ticks', accountId: sub.accountId, symbols: [...sub.symbols] })\n } else {\n channels.push({ kind: sub.kind, accountId: sub.accountId })\n }\n }\n if (channels.length > 0) this.send({ type: 'subscribe', channels })\n }\n\n private send(frame: ClientFrame): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return\n try {\n this.ws.send(JSON.stringify(frame))\n } catch (err) {\n this.emit('error', { message: 'Failed to send frame', cause: err })\n }\n }\n\n async subscribeTicks(accountId: string, symbols: string[]): Promise<void> {\n const key = subKey('ticks', accountId)\n const existing = this.subs.get(key)\n if (existing && existing.kind === 'ticks') {\n for (const s of symbols) existing.symbols.add(s)\n } else {\n this.subs.set(key, { kind: 'ticks', accountId, symbols: new Set(symbols) })\n }\n this.send({ type: 'subscribe', channels: [{ kind: 'ticks', accountId, symbols }] })\n }\n\n async unsubscribeTicks(accountId: string, symbols: string[]): Promise<void> {\n const key = subKey('ticks', accountId)\n const existing = this.subs.get(key)\n if (existing && existing.kind === 'ticks') {\n for (const s of symbols) existing.symbols.delete(s)\n if (existing.symbols.size === 0) this.subs.delete(key)\n }\n this.send({ type: 'unsubscribe', channels: [{ kind: 'ticks', accountId, symbols }] })\n }\n\n async subscribePositions(accountId: string): Promise<void> {\n this.subs.set(subKey('positions', accountId), { kind: 'positions', accountId })\n this.send({ type: 'subscribe', channels: [{ kind: 'positions', accountId }] })\n }\n\n async subscribeAccount(accountId: string): Promise<void> {\n this.subs.set(subKey('account', accountId), { kind: 'account', accountId })\n this.send({ type: 'subscribe', channels: [{ kind: 'account', accountId }] })\n }\n\n async close(): Promise<void> {\n this.closedByUser = true\n this.state = 'closed'\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n this.stopHeartbeat()\n const ws = this.ws\n if (!ws) return\n if (ws.readyState === WebSocket.CLOSED) return\n return new Promise<void>(resolve => {\n const onClose = (): void => resolve()\n ws.once('close', onClose)\n try { ws.close() } catch { resolve() }\n })\n }\n}\n\nfunction subKey(topic: 'ticks' | 'positions' | 'account', accountId: string): string {\n return `${topic}:${accountId}`\n}\n\nexport class StreamNamespace {\n private readonly client: Tickerall\n private readonly streamUrl: string\n private readonly apiKey: string\n private readonly userAgent: string\n\n constructor(client: Tickerall, config: StreamConfig) {\n this.client = client\n this.streamUrl = config.streamUrl\n this.apiKey = config.apiKey\n this.userAgent = config.userAgent\n }\n\n async connect(): Promise<TickerallStream> {\n const stream = new TickerallStream(this.streamUrl, this.apiKey, this.userAgent)\n // On reconnect (atlas may have restarted), re-arm kept sessions before the\n // stream resubscribes, so subscriptions resume against a hot account.\n stream.setBeforeResubscribe(() => this.client.rearmAll())\n await stream.connect()\n return stream\n }\n}\n","import type { Tickerall } from '../client'\nimport type { Candle, CandlesParams, CandlesResponse, RequestOptions } from '../types'\n\nexport class CandlesNamespace {\n constructor(private readonly client: Tickerall) {}\n\n /**\n * Fetch historical OHLC candles for a symbol from one of your broker\n * accounts.\n *\n * Candles are read from the account's own live broker connection, so pass\n * the `accountId` of a connected account. Coarser timeframes reach further\n * back; a single request returns as much history as fits in a few seconds,\n * so pass a large `hours` and take what comes back. Deep look-backs are\n * served on an isolated history connection and won't disturb your live tick\n * stream.\n *\n * @example\n * const bars = await client.candles.get(accountId, { symbol: 'BTCUSDm', hours: 8760, timeframe: 'D1' })\n */\n async get(accountId: string, params: CandlesParams, options?: RequestOptions): Promise<Candle[]> {\n const query = new URLSearchParams({ symbol: params.symbol, hours: String(params.hours) })\n if (params.timeframe) query.set('timeframe', params.timeframe)\n const res = await this.client.requestPlain<CandlesResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/candles?${query.toString()}` },\n options,\n )\n return res.candles\n }\n}\n","import type { Tickerall } from '../client'\nimport type { HistoryParams, HistoryResponse, HistoryTrade, RequestOptions } from '../types'\n\nfunction toQueryTime(v: string | number | Date): string {\n return v instanceof Date ? v.toISOString() : String(v)\n}\n\nexport class HistoryNamespace {\n constructor(private readonly client: Tickerall) {}\n\n /**\n * Closed-trade history for one of your broker accounts — executed deals\n * paired into round-trips, read from the account's own live broker\n * connection (the equivalent of MT5's history_deals_get for the recent\n * window).\n *\n * `symbol`/`from`/`to`/`limit` FILTER the broker's recent deal log (a few\n * weeks deep, broker-controlled) plus any closes seen live this session —\n * they don't fetch deeper than the broker's window. Pass the `accountId` of\n * a connected account.\n *\n * @example\n * const trades = await client.history.get(accountId, { symbol: 'BTCUSDm', limit: 100 })\n */\n async get(accountId: string, params: HistoryParams = {}, options?: RequestOptions): Promise<HistoryTrade[]> {\n const query = new URLSearchParams()\n if (params.symbol) query.set('symbol', params.symbol)\n if (params.from !== undefined) query.set('from', toQueryTime(params.from))\n if (params.to !== undefined) query.set('to', toQueryTime(params.to))\n if (params.limit !== undefined) query.set('limit', String(params.limit))\n if (params.waitMs !== undefined) query.set('waitMs', String(params.waitMs))\n const qs = query.toString()\n const res = await this.client.requestPlain<HistoryResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/history${qs ? `?${qs}` : ''}` },\n options,\n )\n return res.trades\n }\n}\n","import { mapErrorResponse, TickerallApiError, TickerallServiceUnavailableError } from './errors'\nimport { SessionsNamespace } from './namespaces/sessions'\nimport { AccountsNamespace } from './namespaces/accounts'\nimport { OrdersNamespace } from './namespaces/orders'\nimport { PositionsNamespace } from './namespaces/positions'\nimport { StreamNamespace } from './namespaces/stream'\nimport { CandlesNamespace } from './namespaces/candles'\nimport { HistoryNamespace } from './namespaces/history'\nimport type {\n ErrorBody,\n FetchLike,\n IdempotentRequestOptions,\n RequestOptions,\n SessionStartParams,\n SessionStartResult,\n TickerallClientConfig,\n} from './types'\n\nconst DEFAULT_BASE_URL = 'https://api.tickerall.com'\nconst DEFAULT_STREAM_URL = 'wss://api.tickerall.com/v1/stream'\nconst DEFAULT_TIMEOUT_MS = 30_000\nconst SDK_VERSION = '0.1.2'\n\n// Default ceiling on how long a `queueIfReconnecting` call waits across\n// replays before giving up. Bounded on purpose — a queued trade that finally\n// fires minutes late is rarely what the caller wanted.\nconst DEFAULT_QUEUE_MAX_MS = 60_000\n// Backoff between replay attempts for a queued request (ms). Each value is\n// also clamped to the remaining time before the call's deadline.\nconst REPLAY_DELAYS_MS = [500, 1_000, 2_000, 4_000, 8_000]\n\ninterface ReplayJob {\n run: () => Promise<unknown>\n resolve: (value: unknown) => void\n reject: (err: unknown) => void\n deadline: number\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/** @internal */\nexport interface InternalRequestInit {\n method: 'GET' | 'POST' | 'DELETE' | 'PATCH' | 'PUT'\n path: string\n body?: unknown\n idempotencyKey?: string\n signal?: AbortSignal\n timeout?: number\n expectNoContent?: boolean\n // The broker account this request targets, if any. Set by account-scoped\n // namespace methods so the client can transparently re-arm a kept session\n // (re-supply credentials) when the account has gone cold, then retry.\n accountId?: string\n}\n\nexport class Tickerall {\n readonly sessions: SessionsNamespace\n readonly accounts: AccountsNamespace\n readonly orders: OrdersNamespace\n readonly positions: PositionsNamespace\n readonly stream: StreamNamespace\n readonly candles: CandlesNamespace\n readonly history: HistoryNamespace\n\n private readonly apiKey: string\n private readonly baseUrl: string\n private readonly streamUrl: string\n private readonly timeout: number\n private readonly fetchImpl: FetchLike\n private readonly userAgent: string\n\n // In-order replay queue for `queueIfReconnecting` calls. Only opted-in\n // requests ever enter it; everything else bypasses it entirely.\n private readonly replayQueue: ReplayJob[] = []\n private replayDraining = false\n\n // Kept-session credentials — RAM only, NEVER persisted. The broker creds for\n // sessions the customer asked us to keep alive (sessions.keepAlive), so the\n // client can transparently re-arm them when atlas reports the account cold\n // (e.g. after an atlas restart dropped its server-side credentials).\n private readonly keptCreds = new Map<string, SessionStartParams>()\n private readonly onRearm?: (accountId: string) => void\n\n constructor(config: TickerallClientConfig) {\n if (!config || !config.apiKey) {\n throw new TypeError('Tickerall: `apiKey` is required.')\n }\n this.apiKey = config.apiKey\n this.baseUrl = trimTrailingSlash(config.baseUrl ?? DEFAULT_BASE_URL)\n this.streamUrl = config.streamUrl ?? DEFAULT_STREAM_URL\n this.timeout = config.timeout ?? DEFAULT_TIMEOUT_MS\n const resolvedFetch = config.fetch ?? globalThis.fetch\n if (typeof resolvedFetch !== 'function') {\n throw new TypeError('Tickerall: no `fetch` available — pass `fetch` in the config (Node <18 needs an explicit fetch).')\n }\n this.fetchImpl = resolvedFetch.bind(globalThis)\n this.userAgent = config.userAgent\n ? `${config.userAgent} tickerall-js/${SDK_VERSION}`\n : `tickerall-js/${SDK_VERSION}`\n this.onRearm = config.onRearm\n\n this.sessions = new SessionsNamespace(this)\n this.accounts = new AccountsNamespace(this)\n this.orders = new OrdersNamespace(this)\n this.positions = new PositionsNamespace(this)\n this.candles = new CandlesNamespace(this)\n this.history = new HistoryNamespace(this)\n this.stream = new StreamNamespace(this, {\n streamUrl: this.streamUrl,\n apiKey: this.apiKey,\n userAgent: this.userAgent,\n })\n }\n\n // Public entry — runs the request, transparently re-arming a kept session\n // and retrying ONCE if the account has gone cold.\n /** @internal */\n request<T>(init: InternalRequestInit): Promise<T> {\n return this.requestWithRearm<T>(init, false)\n }\n\n private async requestWithRearm<T>(init: InternalRequestInit, isRearmRetry: boolean): Promise<T> {\n try {\n return await this.requestOnce<T>(init)\n } catch (err) {\n // If a kept session's account went cold (e.g. an atlas restart dropped\n // its credentials), refresh them and retry the original request once.\n if (\n !isRearmRetry &&\n init.accountId !== undefined &&\n this.keptCreds.has(init.accountId) &&\n err instanceof TickerallApiError &&\n err.code === 'BROKER_ACCOUNT_NOT_HOT'\n ) {\n await this.rearm(init.accountId)\n return this.requestWithRearm<T>(init, true)\n }\n throw err\n }\n }\n\n private async requestOnce<T>(init: InternalRequestInit): Promise<T> {\n const url = `${this.baseUrl}${init.path}`\n const headers: Record<string, string> = {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'User-Agent': this.userAgent,\n 'Accept': 'application/json',\n }\n if (init.body !== undefined) headers['Content-Type'] = 'application/json'\n if (init.idempotencyKey) headers['Idempotency-Key'] = init.idempotencyKey\n\n const timeoutMs = init.timeout ?? this.timeout\n const controller = new AbortController()\n // Track who aborted: our own timeout is a transient connectivity symptom\n // (retryable), whereas a caller-supplied signal is a deliberate cancel.\n let timedOut = false\n const timer = setTimeout(() => {\n timedOut = true\n controller.abort(new Error(`Request timed out after ${timeoutMs}ms`))\n }, timeoutMs)\n if (init.signal) {\n if (init.signal.aborted) controller.abort(init.signal.reason)\n else init.signal.addEventListener('abort', () => controller.abort(init.signal!.reason), { once: true })\n }\n\n let response: Response\n try {\n response = await this.fetchImpl(url, {\n method: init.method,\n headers,\n body: init.body !== undefined ? JSON.stringify(init.body) : undefined,\n signal: controller.signal,\n })\n } catch (err) {\n clearTimeout(timer)\n if (timedOut) {\n // Timed out waiting for TickerAll — transient, safe to retry.\n throw new TickerallServiceUnavailableError({\n status: 0,\n code: 'REQUEST_TIMEOUT',\n message: `Request timed out after ${timeoutMs}ms`,\n })\n }\n if (controller.signal.aborted) {\n // Caller cancelled via their AbortSignal — deliberate, not transient.\n const reason = (controller.signal.reason as Error | undefined)?.message ?? (err as Error).message ?? 'Request aborted'\n throw new TickerallApiError({\n status: 0,\n code: 'REQUEST_ABORTED',\n message: reason,\n })\n }\n // fetch threw before any response — TickerAll was unreachable. Transient.\n throw new TickerallServiceUnavailableError({\n status: 0,\n code: 'NETWORK_ERROR',\n message: (err as Error).message || 'Network request failed',\n details: err,\n })\n } finally {\n clearTimeout(timer)\n }\n\n const requestId = response.headers.get('x-request-id') ?? undefined\n\n if (init.expectNoContent && response.status === 204) {\n return undefined as T\n }\n\n if (!response.ok) {\n const body = await safeReadErrorBody(response)\n throw mapErrorResponse({\n status: response.status,\n code: body?.error ?? `HTTP_${response.status}`,\n message: body?.message ?? response.statusText ?? 'Request failed',\n details: body?.details,\n requestId,\n })\n }\n\n if (response.status === 204) return undefined as T\n const json = (await response.json()) as T\n return json\n }\n\n /** @internal */\n async requestIdempotent<T>(init: InternalRequestInit, options?: IdempotentRequestOptions): Promise<T> {\n // Fix the idempotency key ONCE so every replay attempt carries the same\n // key — the server then dedupes any attempt that already executed, which\n // is what makes queue-and-replay safe (no double trade).\n const key = options?.idempotencyKey ?? generateIdempotencyKey()\n const full: InternalRequestInit = {\n ...init,\n idempotencyKey: key,\n signal: options?.signal,\n timeout: options?.timeout,\n }\n if (options?.queueIfReconnecting) {\n return this.enqueueReplay<T>(full, options.queueMaxMs ?? DEFAULT_QUEUE_MAX_MS)\n }\n // Default: fail fast. A transient connectivity failure surfaces as\n // TickerallServiceUnavailableError for the caller to re-decide.\n return this.request<T>(full)\n }\n\n // Queue a request for in-order replay, retrying transient failures with\n // backoff until it succeeds or `maxMs` elapses.\n private enqueueReplay<T>(init: InternalRequestInit, maxMs: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n this.replayQueue.push({\n run: () => this.request<unknown>(init),\n resolve: resolve as (value: unknown) => void,\n reject,\n deadline: Date.now() + maxMs,\n })\n void this.drainReplayQueue()\n })\n }\n\n // Serial drain: the head job must settle (resolve, reject, or expire) before\n // the next is attempted, so queued writes replay in submission order.\n private async drainReplayQueue(): Promise<void> {\n if (this.replayDraining) return\n this.replayDraining = true\n try {\n while (this.replayQueue.length > 0) {\n const job = this.replayQueue[0]!\n // Reject up front if this job already expired while head-of-line\n // blocked behind an earlier one riding out a long outage.\n if (Date.now() >= job.deadline) {\n job.reject(new TickerallServiceUnavailableError({\n status: 0,\n code: 'QUEUE_TIMEOUT',\n message: 'Queued request expired before connectivity returned',\n }))\n this.replayQueue.shift()\n continue\n }\n let attempt = 0\n for (;;) {\n try {\n job.resolve(await job.run())\n this.replayQueue.shift()\n break\n } catch (err) {\n const isTransient = err instanceof TickerallApiError && err.transient\n const remaining = job.deadline - Date.now()\n if (!isTransient || remaining <= 0) {\n // Non-transient (bad request, broker rejection, …) never retries;\n // a transient failure past the deadline gives up.\n job.reject(err)\n this.replayQueue.shift()\n break\n }\n const base = REPLAY_DELAYS_MS[Math.min(attempt, REPLAY_DELAYS_MS.length - 1)]!\n attempt += 1\n await sleep(Math.min(base, remaining))\n }\n }\n }\n } finally {\n this.replayDraining = false\n }\n }\n\n /** @internal */\n requestPlain<T>(init: InternalRequestInit, options?: RequestOptions): Promise<T> {\n return this.request<T>({\n ...init,\n signal: options?.signal,\n timeout: options?.timeout,\n })\n }\n\n // ── Kept sessions (auto re-arm) ──────────────────────────────────────────\n // Credentials live in this process's memory only — nothing is persisted.\n\n /** Cache broker creds for an account so the client can auto re-arm it. @internal */\n registerKeptSession(accountId: string, params: SessionStartParams): void {\n this.keptCreds.set(accountId, params)\n }\n\n /** Stop auto-re-arming an account and drop its cached credentials. @internal */\n unregisterKeptSession(accountId: string): void {\n this.keptCreds.delete(accountId)\n }\n\n /** Account IDs currently kept alive (i.e. have cached re-arm credentials). @internal */\n keptSessionIds(): string[] {\n return [...this.keptCreds.keys()]\n }\n\n /**\n * Re-supply credentials for a kept account (a fresh `session.start`) to bring\n * a cold connection back. Throws if the account isn't being kept alive.\n * @internal\n */\n async rearm(accountId: string): Promise<void> {\n const creds = this.keptCreds.get(accountId)\n if (!creds) {\n throw new TickerallApiError({\n status: 0,\n code: 'NO_KEPT_CREDENTIALS',\n message: `No kept credentials for account ${accountId}; call sessions.keepAlive first.`,\n })\n }\n this.onRearm?.(accountId)\n // session.start carries no accountId, so this never recurses into re-arm.\n await this.requestIdempotent<SessionStartResult>({ method: 'POST', path: '/v1/sessions', body: creds })\n }\n\n /**\n * Re-arm every kept session — best-effort (one failure won't block the\n * others). Used after the stream reconnects (atlas may have restarted).\n * @internal\n */\n async rearmAll(): Promise<void> {\n await Promise.all([...this.keptCreds.keys()].map(id => this.rearm(id).catch(() => { /* best-effort */ })))\n }\n}\n\nfunction trimTrailingSlash(s: string): string {\n return s.endsWith('/') ? s.slice(0, -1) : s\n}\n\nasync function safeReadErrorBody(response: Response): Promise<ErrorBody | null> {\n try {\n const text = await response.text()\n if (!text) return null\n try {\n return JSON.parse(text) as ErrorBody\n } catch {\n return { error: 'PARSE_ERROR', message: text }\n }\n } catch {\n return null\n }\n}\n\nexport function generateIdempotencyKey(): string {\n const c: { randomUUID?: () => string } | undefined = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n if (c && typeof c.randomUUID === 'function') return c.randomUUID()\n return fallbackUuid()\n}\n\nfunction fallbackUuid(): string {\n const bytes = new Uint8Array(16)\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256)\n bytes[6] = (bytes[6]! & 0x0f) | 0x40\n bytes[8] = (bytes[8]! & 0x3f) | 0x80\n const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/namespaces/sessions.ts","../src/namespaces/accounts.ts","../src/namespaces/orders.ts","../src/namespaces/positions.ts","../src/namespaces/stream.ts","../src/namespaces/candles.ts","../src/namespaces/history.ts","../src/client.ts"],"names":["TickerallApiError","init","TickerallAuthError","TickerallForbiddenError","TickerallValidationError","TickerallNotFoundError","TickerallBrokerError","TickerallServiceUnavailableError","BROKER_CODES","mapErrorResponse","SessionsNamespace","client","params","options","result","accountId","pending","kept","rearmed","p","AccountsNamespace","OrdersNamespace","query","ticket","PositionsNamespace","HEARTBEAT_INTERVAL_MS","HEARTBEAT_TIMEOUT_MS","RECONNECT_DELAYS","RECONNECT_MAX_MS","POSITION_PHASE_MAP","TickerallStream","EventEmitter","url","apiKey","userAgent","event","listener","cb","WebSocket","timeoutMs","resolve","reject","timer","onOpen","ws","settled","wasReconnect","onMessage","data","frame","err","onError","onClose","code","reason","reasonStr","r","_reason","idx","base","jitter","delay","attempt","channels","sub","symbols","key","subKey","existing","s","topic","StreamNamespace","config","stream","CandlesNamespace","toQueryTime","v","HistoryNamespace","qs","DEFAULT_BASE_URL","DEFAULT_STREAM_URL","DEFAULT_TIMEOUT_MS","SDK_VERSION","DEFAULT_QUEUE_MAX_MS","REPLAY_DELAYS_MS","sleep","ms","Tickerall","trimTrailingSlash","resolvedFetch","isRearmRetry","headers","controller","timedOut","response","requestId","body","safeReadErrorBody","generateIdempotencyKey","full","maxMs","job","isTransient","remaining","creds","id","text","c","fallbackUuid","bytes","i","hex","b"],"mappings":"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","file":"index.js","sourcesContent":["export interface TickerallErrorInit {\n status: number\n code: string\n message: string\n requestId?: string\n details?: unknown\n /**\n * Transient = the request failed because TickerAll was momentarily\n * unreachable (network blip, deploy, restart) rather than because the\n * request itself was bad. Safe to retry. Set automatically for\n * `TickerallServiceUnavailableError`; `false` for every other error.\n */\n transient?: boolean\n}\n\nexport class TickerallApiError extends Error {\n readonly status: number\n readonly code: string\n readonly requestId?: string\n readonly details?: unknown\n /**\n * `true` when the failure is a momentary connectivity issue that is safe\n * to retry (see {@link TickerallServiceUnavailableError}). `false` for\n * application errors (auth, validation, broker rejection, …) that won't\n * change on retry. Use it to decide whether to back off and try again.\n */\n readonly transient: boolean\n\n constructor(init: TickerallErrorInit) {\n super(init.message)\n this.name = 'TickerallApiError'\n this.status = init.status\n this.code = init.code\n this.requestId = init.requestId\n this.details = init.details\n this.transient = init.transient ?? false\n }\n}\n\nexport class TickerallAuthError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallAuthError'\n }\n}\n\nexport class TickerallForbiddenError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallForbiddenError'\n }\n}\n\nexport class TickerallValidationError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallValidationError'\n }\n}\n\nexport class TickerallNotFoundError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallNotFoundError'\n }\n}\n\nexport class TickerallBrokerError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallBrokerError'\n }\n}\n\n/**\n * TickerAll was momentarily unreachable — a network blip, a deploy, or the\n * service restarting. This is NOT your fault and NOT a broker rejection: the\n * request never reached a verdict, so it's safe to retry. `transient` is\n * always `true`.\n *\n * The SDK throws this for network failures, request timeouts, and bare\n * 502/503s (and `POOL_SHUTTING_DOWN`). By default a trade fails fast with\n * this error so you can re-decide with fresh prices; pass\n * `{ queueIfReconnecting: true }` to instead queue the call and replay it\n * (with its stable idempotency key, so it can't double-execute) once\n * connectivity returns.\n */\nexport class TickerallServiceUnavailableError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super({ ...init, transient: true })\n this.name = 'TickerallServiceUnavailableError'\n }\n}\n\nconst BROKER_CODES = new Set([\n 'BROKER_REJECTED',\n 'BROKER_AUTH_FAILED',\n 'BROKER_UNREACHABLE',\n 'BROKER_ACCOUNT_NOT_HOT',\n 'BROKER_ACCOUNT_ALREADY_LINKED',\n 'BROKER_ACCOUNT_NOT_FOUND',\n 'TICKET_NOT_FOUND',\n])\n\nexport function mapErrorResponse(init: TickerallErrorInit): TickerallApiError {\n // The pool draining for a deploy/restart is the canonical transient case —\n // a retry lands on the fresh instance, so surface it as service-unavailable\n // (retryable) rather than a broker error.\n if (init.code === 'POOL_SHUTTING_DOWN') return new TickerallServiceUnavailableError(init)\n if (BROKER_CODES.has(init.code)) return new TickerallBrokerError(init)\n if (init.status === 401) return new TickerallAuthError(init)\n if (init.status === 403) return new TickerallForbiddenError(init)\n if (init.status === 404) return new TickerallNotFoundError(init)\n if (init.status === 400 || init.status === 422) return new TickerallValidationError(init)\n // A bare 502/503 with no recognised broker code is the proxy/load-balancer\n // reporting TickerAll itself as momentarily down (e.g. mid-deploy) — that's\n // transient and retryable. Broker-coded 5xx were already caught above.\n if (init.status === 503 || init.status === 502) return new TickerallServiceUnavailableError(init)\n return new TickerallApiError(init)\n}\n","import type { Tickerall } from '../client'\nimport type {\n IdempotentRequestOptions,\n PendingRearmAccount,\n RequestOptions,\n SessionStartParams,\n SessionStartResult,\n} from '../types'\n\nexport class SessionsNamespace {\n constructor(private readonly client: Tickerall) {}\n\n start(params: SessionStartParams, options?: IdempotentRequestOptions): Promise<SessionStartResult> {\n return this.client.requestIdempotent<SessionStartResult>(\n { method: 'POST', path: '/v1/sessions', body: params },\n options,\n )\n }\n\n /**\n * Start a session AND keep it alive: the broker credentials are cached in\n * this process's memory (never persisted) so the client transparently\n * re-arms the account if it later goes cold — e.g. after an atlas restart.\n * Pair with an always-hot account for a connection that stays up with no\n * manual reconnect. Call {@link stopKeepAlive} (or {@link end}) to forget\n * the credentials.\n */\n async keepAlive(params: SessionStartParams, options?: IdempotentRequestOptions): Promise<SessionStartResult> {\n const result = await this.start(params, options)\n this.client.registerKeptSession(result.accountId, params)\n return result\n }\n\n /** Stop auto-re-arming an account and drop its cached credentials. */\n stopKeepAlive(accountId: string): void {\n this.client.unregisterKeptSession(accountId)\n }\n\n /**\n * Manually re-arm a kept account now (a fresh session.start with the cached\n * credentials). Normally unnecessary — the client re-arms on demand — but\n * useful to proactively recover accounts listed by `GET /v1/always-hot/pending`.\n */\n rearm(accountId: string): Promise<void> {\n return this.client.rearm(accountId)\n }\n\n /**\n * Always-hot accounts that currently have no live connection — they need a\n * credentials refresh (e.g. after a TickerAll restart). Poll this after a\n * suspected outage; the next call or stream reconnect also re-arms them\n * automatically.\n */\n async pendingRearm(options?: RequestOptions): Promise<PendingRearmAccount[]> {\n const res = await this.client.requestPlain<{ pending: PendingRearmAccount[] }>(\n { method: 'GET', path: '/v1/always-hot/pending' },\n options,\n )\n return res.pending\n }\n\n /**\n * Re-arm every pending account we hold kept credentials for (the ones we\n * actually can recover). Returns the account IDs that were re-armed.\n */\n async rearmPending(options?: RequestOptions): Promise<string[]> {\n const pending = await this.pendingRearm(options)\n const kept = new Set(this.client.keptSessionIds())\n const rearmed: string[] = []\n for (const p of pending) {\n if (!kept.has(p.id)) continue\n await this.client.rearm(p.id).catch(() => { /* best-effort */ })\n rearmed.push(p.id)\n }\n return rearmed\n }\n\n end(accountId: string, options?: RequestOptions): Promise<void> {\n // Ending a session also stops keeping it alive.\n this.client.unregisterKeptSession(accountId)\n return this.client.requestPlain<void>(\n {\n method: 'DELETE',\n path: `/v1/sessions/${encodeURIComponent(accountId)}`,\n expectNoContent: true,\n },\n options,\n )\n }\n}\n","import type { Tickerall } from '../client'\nimport type {\n AccountDetail,\n AccountListing,\n RequestOptions,\n SymbolSpec,\n SymbolSpecsResponse,\n SymbolsResponse,\n} from '../types'\n\nexport class AccountsNamespace {\n constructor(private readonly client: Tickerall) {}\n\n list(options?: RequestOptions): Promise<AccountListing[]> {\n return this.client.requestPlain<AccountListing[]>(\n { method: 'GET', path: '/v1/accounts' },\n options,\n )\n }\n\n get(accountId: string, options?: RequestOptions): Promise<AccountDetail> {\n return this.client.requestPlain<AccountDetail>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}`, accountId },\n options,\n )\n }\n\n async symbols(accountId: string, options?: RequestOptions): Promise<string[]> {\n const res = await this.client.requestPlain<SymbolsResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/symbols`, accountId },\n options,\n )\n return res.symbols\n }\n\n /**\n * Per-symbol volume specs (min / max / step) for this account's tradeable\n * symbols — use these to check an order volume before placing it. Each spec\n * carries `specSource`: `'broker'` (the broker pushed it, authoritative) or\n * `'derived'` (filled from category defaults — best-effort). MT5 only; an\n * MT4 account returns an empty list.\n */\n async symbolSpecs(accountId: string, options?: RequestOptions): Promise<SymbolSpec[]> {\n const res = await this.client.requestPlain<SymbolSpecsResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/symbol-specs`, accountId },\n options,\n )\n return res.specs\n }\n}\n","import type { Tickerall } from '../client'\nimport type {\n CancelPendingResult,\n IdempotentRequestOptions,\n ListPendingParams,\n ModifyPendingParams,\n ModifyPendingResult,\n PendingOrder,\n PendingOrdersResponse,\n PlaceOrderParams,\n PlaceOrderResult,\n RequestOptions,\n} from '../types'\n\nexport class OrdersNamespace {\n constructor(private readonly client: Tickerall) {}\n\n place(\n accountId: string,\n params: PlaceOrderParams,\n options?: IdempotentRequestOptions,\n ): Promise<PlaceOrderResult> {\n return this.client.requestIdempotent<PlaceOrderResult>(\n {\n method: 'POST',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders`,\n body: params,\n accountId,\n },\n options,\n )\n }\n\n /**\n * List the account's resting pending orders (LIMIT / STOP). MT5 only — an\n * MT4 account returns an empty list. `waitMs` lets a just-warmed connection's\n * pending snapshot settle; pass 0 on a hot poller to skip the wait.\n */\n async listPending(\n accountId: string,\n params: ListPendingParams = {},\n options?: RequestOptions,\n ): Promise<PendingOrder[]> {\n const query = params.waitMs !== undefined ? `?waitMs=${encodeURIComponent(String(params.waitMs))}` : ''\n const res = await this.client.requestPlain<PendingOrdersResponse>(\n {\n method: 'GET',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders/pending${query}`,\n accountId,\n },\n options,\n )\n return res.orders\n }\n\n /**\n * Cancel a resting pending order by its ticket. MT5 only.\n */\n cancelPending(\n accountId: string,\n ticket: number,\n options?: IdempotentRequestOptions,\n ): Promise<CancelPendingResult> {\n return this.client.requestIdempotent<CancelPendingResult>(\n {\n method: 'DELETE',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders/${ticket}`,\n accountId,\n },\n options,\n )\n }\n\n /**\n * Modify a resting pending order's trigger price / SL / TP. Any field you\n * omit is preserved at its current value. Provide at least one. MT5 only.\n */\n modifyPending(\n accountId: string,\n ticket: number,\n params: ModifyPendingParams,\n options?: IdempotentRequestOptions,\n ): Promise<ModifyPendingResult> {\n return this.client.requestIdempotent<ModifyPendingResult>(\n {\n method: 'PATCH',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders/${ticket}`,\n body: params,\n accountId,\n },\n options,\n )\n }\n}\n","import type { Tickerall } from '../client'\nimport type {\n ClosePositionParams,\n ClosePositionResult,\n IdempotentRequestOptions,\n ModifyPositionParams,\n ModifyPositionResult,\n} from '../types'\n\nexport class PositionsNamespace {\n constructor(private readonly client: Tickerall) {}\n\n close(\n accountId: string,\n ticket: number,\n params: ClosePositionParams = {},\n options?: IdempotentRequestOptions,\n ): Promise<ClosePositionResult> {\n return this.client.requestIdempotent<ClosePositionResult>(\n {\n method: 'DELETE',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/positions/${ticket}`,\n body: params,\n accountId,\n },\n options,\n )\n }\n\n modify(\n accountId: string,\n ticket: number,\n params: ModifyPositionParams,\n options?: IdempotentRequestOptions,\n ): Promise<ModifyPositionResult> {\n return this.client.requestIdempotent<ModifyPositionResult>(\n {\n method: 'PATCH',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/positions/${ticket}`,\n body: params,\n accountId,\n },\n options,\n )\n }\n}\n","import { EventEmitter } from 'node:events'\nimport WebSocket from 'ws'\nimport type { Tickerall } from '../client'\nimport type {\n AccountEvent,\n PositionEvent,\n StreamCloseEvent,\n StreamErrorEvent,\n StreamReconnectEvent,\n StreamState,\n TickEvent,\n} from '../types'\n\nexport interface StreamConfig {\n streamUrl: string\n apiKey: string\n userAgent: string\n}\n\nexport interface StreamConnectOptions {\n signal?: AbortSignal\n}\n\nconst HEARTBEAT_INTERVAL_MS = 25_000\nconst HEARTBEAT_TIMEOUT_MS = 10_000\nconst RECONNECT_DELAYS = [1_000, 2_000, 4_000, 8_000, 16_000, 30_000]\nconst RECONNECT_MAX_MS = 30_000\n\ninterface TickSubscription {\n kind: 'ticks'\n accountId: string\n symbols: Set<string>\n}\n\ninterface AccountTopicSubscription {\n kind: 'positions' | 'account'\n accountId: string\n}\n\ntype Subscription = TickSubscription | AccountTopicSubscription\n\n// Subscription channels — the server subscribes by `{ kind, accountId, ... }`\n// wrapped in a `channels` array (see the server's ws/protocol).\ntype ChannelFrame =\n | { kind: 'ticks'; accountId: string; symbols: string[] }\n | { kind: 'positions'; accountId: string }\n | { kind: 'account'; accountId: string }\n\ninterface SubscribeFrame {\n type: 'subscribe'\n channels: ChannelFrame[]\n correlationId?: string\n}\n\ninterface UnsubscribeFrame {\n type: 'unsubscribe'\n channels: ChannelFrame[]\n correlationId?: string\n}\n\ntype ClientFrame = SubscribeFrame | UnsubscribeFrame | { type: 'ping' }\n\ninterface IncomingTick {\n type: 'tick'\n accountId: string\n symbol: string\n bid: number\n ask: number\n ordinal?: number\n subtype?: number\n timestamp: string\n}\n\n// The server emits position events as `position_update` with an\n// opened/updated/closed phase, and account events as `account_update`.\ninterface IncomingPositionUpdate {\n type: 'position_update'\n accountId: string\n event: 'opened' | 'updated' | 'closed'\n position: PositionEvent['position']\n}\n\ninterface IncomingAccountUpdate {\n type: 'account_update'\n accountId: string\n snapshot: AccountEvent['snapshot']\n}\n\ninterface IncomingPong {\n type: 'pong'\n ts?: number\n}\n\ninterface IncomingSubscribed {\n type: 'subscribed'\n channels: unknown[]\n rejected: Array<{ channel: unknown; reason: string; code: string }>\n correlationId?: string\n}\n\ninterface IncomingError {\n type: 'error'\n code: string\n message: string\n correlationId?: string\n}\n\ntype IncomingFrame =\n | IncomingTick\n | IncomingPositionUpdate\n | IncomingAccountUpdate\n | IncomingPong\n | IncomingSubscribed\n | IncomingError\n\nconst POSITION_PHASE_MAP: Record<string, PositionEvent['event']> = {\n opened: 'position-opened',\n updated: 'position-updated',\n closed: 'position-closed',\n}\n\nexport interface TickerallStreamEvents {\n tick: (e: TickEvent) => void\n position: (e: PositionEvent) => void\n account: (e: AccountEvent) => void\n error: (e: StreamErrorEvent) => void\n close: (e: StreamCloseEvent) => void\n reconnect: (e: StreamReconnectEvent) => void\n open: () => void\n}\n\nexport class TickerallStream extends EventEmitter {\n private ws: WebSocket | null = null\n private closedByUser = false\n private state: StreamState = 'closed'\n private beforeResubscribe?: () => Promise<void>\n private reconnectAttempts = 0\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null\n private heartbeatTimeoutTimer: ReturnType<typeof setTimeout> | null = null\n private readonly subs: Map<string, Subscription> = new Map()\n private readonly url: string\n private readonly headers: Record<string, string>\n\n constructor(url: string, apiKey: string, userAgent: string) {\n super()\n this.url = url\n this.headers = {\n 'Authorization': `Bearer ${apiKey}`,\n 'User-Agent': userAgent,\n }\n // Swallow `error` events that have no listener; the SDK reports errors\n // via the `error` event and via promise rejection on `connect()`, so a\n // missing listener should not crash the process.\n this.on('error', () => { /* noop default */ })\n }\n\n override on<E extends keyof TickerallStreamEvents>(event: E, listener: TickerallStreamEvents[E]): this {\n return super.on(event, listener as (...args: unknown[]) => void)\n }\n\n override once<E extends keyof TickerallStreamEvents>(event: E, listener: TickerallStreamEvents[E]): this {\n return super.once(event, listener as (...args: unknown[]) => void)\n }\n\n override off<E extends keyof TickerallStreamEvents>(event: E, listener: TickerallStreamEvents[E]): this {\n return super.off(event, listener as (...args: unknown[]) => void)\n }\n\n async connect(): Promise<void> {\n this.closedByUser = false\n this.state = 'connecting'\n await this.openOnce()\n }\n\n /**\n * Internal: callback run after a RECONNECT (not the initial connect), before\n * subscriptions are re-sent. The SDK wires this to re-arm kept sessions so a\n * connection transparently survives an atlas restart.\n */\n setBeforeResubscribe(cb: () => Promise<void>): void {\n this.beforeResubscribe = cb\n }\n\n /**\n * Current connection state. `'open'` means live; `'reconnecting'` means the\n * SDK is silently re-establishing the link (idle apps need do nothing).\n * Queryable any time — never thrown at you.\n */\n getState(): StreamState {\n return this.state\n }\n\n /** `true` only when the stream is live and ready to receive. */\n isConnected(): boolean {\n return this.state === 'open' && this.ws?.readyState === WebSocket.OPEN\n }\n\n /**\n * Resolve once the stream is live (immediately if already open), or reject\n * after `timeoutMs`. Rejects right away if the stream was closed by the\n * caller. Handy to gate logic on a confirmed connection without polling.\n */\n waitUntilConnected(timeoutMs = 30_000): Promise<void> {\n if (this.isConnected()) return Promise.resolve()\n if (this.state === 'closed') return Promise.reject(new Error('Stream is closed'))\n return new Promise<void>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout>\n const onOpen = (): void => {\n clearTimeout(timer)\n resolve()\n }\n timer = setTimeout(() => {\n this.off('open', onOpen)\n reject(new Error(`waitUntilConnected: timed out after ${timeoutMs}ms`))\n }, timeoutMs)\n this.once('open', onOpen)\n })\n }\n\n private openOnce(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const ws = new WebSocket(this.url, { headers: this.headers })\n this.ws = ws\n let settled = false\n\n const onOpen = async (): Promise<void> => {\n if (settled) return\n settled = true\n const wasReconnect = this.reconnectAttempts > 0\n this.state = 'open'\n this.reconnectAttempts = 0\n this.startHeartbeat()\n // After a RECONNECT (atlas may have restarted and lost the broker\n // session), re-arm kept sessions BEFORE resubscribing so the account\n // is hot again on atlas. Skipped on the initial connect.\n if (wasReconnect && this.beforeResubscribe) {\n try { await this.beforeResubscribe() } catch { /* best-effort */ }\n }\n this.resendSubscriptions()\n this.emit('open')\n resolve()\n }\n\n const onMessage = (data: WebSocket.RawData): void => {\n try {\n const frame = JSON.parse(data.toString()) as IncomingFrame\n this.handleFrame(frame)\n } catch (err) {\n this.emit('error', { message: 'Failed to parse server frame', cause: err })\n }\n }\n\n const onError = (err: Error): void => {\n if (!settled) {\n settled = true\n reject(err)\n }\n this.emit('error', { message: err.message, cause: err })\n }\n\n const onClose = (code: number, reason: Buffer): void => {\n this.stopHeartbeat()\n this.ws = null\n const reasonStr = reason?.toString() ?? ''\n this.emit('close', { code, reason: reasonStr })\n if (!settled) {\n settled = true\n reject(new Error(`WebSocket closed before open (code=${code})`))\n }\n if (!this.closedByUser) {\n this.state = 'reconnecting'\n this.scheduleReconnect()\n }\n }\n\n ws.on('open', onOpen)\n ws.on('message', onMessage)\n ws.on('error', onError)\n ws.on('close', onClose)\n ws.on('pong', () => this.clearHeartbeatTimeout())\n })\n }\n\n private handleFrame(frame: IncomingFrame): void {\n switch (frame.type) {\n case 'tick':\n this.emit('tick', {\n type: 'tick',\n accountId: frame.accountId,\n symbol: frame.symbol,\n bid: frame.bid,\n ask: frame.ask,\n timestamp: frame.timestamp,\n })\n return\n case 'position_update':\n this.emit('position', {\n type: 'position',\n accountId: frame.accountId,\n event: POSITION_PHASE_MAP[frame.event] ?? 'position-updated',\n position: frame.position,\n })\n return\n case 'account_update':\n this.emit('account', {\n type: 'account',\n accountId: frame.accountId,\n snapshot: frame.snapshot,\n })\n return\n case 'subscribed':\n if (frame.rejected && frame.rejected.length > 0) {\n this.emit('error', {\n message: `Subscribe rejected: ${frame.rejected.map(r => `${r.code} (${r.reason})`).join(', ')}`,\n })\n }\n return\n case 'error':\n this.emit('error', { message: `${frame.code}: ${frame.message}` })\n return\n case 'pong':\n this.clearHeartbeatTimeout()\n return\n }\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat()\n this.heartbeatTimer = setInterval(() => {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return\n this.send({ type: 'ping' })\n try { this.ws.ping() } catch { /* noop */ }\n this.heartbeatTimeoutTimer = setTimeout(() => this.forceReconnect('heartbeat-timeout'), HEARTBEAT_TIMEOUT_MS)\n }, HEARTBEAT_INTERVAL_MS)\n }\n\n private clearHeartbeatTimeout(): void {\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer)\n this.heartbeatTimeoutTimer = null\n }\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) clearInterval(this.heartbeatTimer)\n if (this.heartbeatTimeoutTimer) clearTimeout(this.heartbeatTimeoutTimer)\n this.heartbeatTimer = null\n this.heartbeatTimeoutTimer = null\n }\n\n private forceReconnect(_reason: string): void {\n if (!this.ws) return\n try { this.ws.terminate() } catch { /* noop */ }\n }\n\n private scheduleReconnect(): void {\n if (this.closedByUser) return\n if (this.reconnectTimer) return\n const idx = Math.min(this.reconnectAttempts, RECONNECT_DELAYS.length - 1)\n const base = RECONNECT_DELAYS[idx] ?? RECONNECT_MAX_MS\n const jitter = Math.floor(Math.random() * Math.min(base, 1_000))\n const delay = Math.min(base + jitter, RECONNECT_MAX_MS + 1_000)\n this.reconnectAttempts += 1\n const attempt = this.reconnectAttempts\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null\n this.emit('reconnect', { attempt })\n this.openOnce().catch(err => {\n this.emit('error', { message: 'Reconnect failed', cause: err })\n this.scheduleReconnect()\n })\n }, delay)\n }\n\n private resendSubscriptions(): void {\n const channels: ChannelFrame[] = []\n for (const sub of this.subs.values()) {\n if (sub.kind === 'ticks') {\n channels.push({ kind: 'ticks', accountId: sub.accountId, symbols: [...sub.symbols] })\n } else {\n channels.push({ kind: sub.kind, accountId: sub.accountId })\n }\n }\n if (channels.length > 0) this.send({ type: 'subscribe', channels })\n }\n\n private send(frame: ClientFrame): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return\n try {\n this.ws.send(JSON.stringify(frame))\n } catch (err) {\n this.emit('error', { message: 'Failed to send frame', cause: err })\n }\n }\n\n async subscribeTicks(accountId: string, symbols: string[]): Promise<void> {\n const key = subKey('ticks', accountId)\n const existing = this.subs.get(key)\n if (existing && existing.kind === 'ticks') {\n for (const s of symbols) existing.symbols.add(s)\n } else {\n this.subs.set(key, { kind: 'ticks', accountId, symbols: new Set(symbols) })\n }\n this.send({ type: 'subscribe', channels: [{ kind: 'ticks', accountId, symbols }] })\n }\n\n async unsubscribeTicks(accountId: string, symbols: string[]): Promise<void> {\n const key = subKey('ticks', accountId)\n const existing = this.subs.get(key)\n if (existing && existing.kind === 'ticks') {\n for (const s of symbols) existing.symbols.delete(s)\n if (existing.symbols.size === 0) this.subs.delete(key)\n }\n this.send({ type: 'unsubscribe', channels: [{ kind: 'ticks', accountId, symbols }] })\n }\n\n async subscribePositions(accountId: string): Promise<void> {\n this.subs.set(subKey('positions', accountId), { kind: 'positions', accountId })\n this.send({ type: 'subscribe', channels: [{ kind: 'positions', accountId }] })\n }\n\n async subscribeAccount(accountId: string): Promise<void> {\n this.subs.set(subKey('account', accountId), { kind: 'account', accountId })\n this.send({ type: 'subscribe', channels: [{ kind: 'account', accountId }] })\n }\n\n async close(): Promise<void> {\n this.closedByUser = true\n this.state = 'closed'\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n this.stopHeartbeat()\n const ws = this.ws\n if (!ws) return\n if (ws.readyState === WebSocket.CLOSED) return\n return new Promise<void>(resolve => {\n const onClose = (): void => resolve()\n ws.once('close', onClose)\n try { ws.close() } catch { resolve() }\n })\n }\n}\n\nfunction subKey(topic: 'ticks' | 'positions' | 'account', accountId: string): string {\n return `${topic}:${accountId}`\n}\n\nexport class StreamNamespace {\n private readonly client: Tickerall\n private readonly streamUrl: string\n private readonly apiKey: string\n private readonly userAgent: string\n\n constructor(client: Tickerall, config: StreamConfig) {\n this.client = client\n this.streamUrl = config.streamUrl\n this.apiKey = config.apiKey\n this.userAgent = config.userAgent\n }\n\n async connect(): Promise<TickerallStream> {\n const stream = new TickerallStream(this.streamUrl, this.apiKey, this.userAgent)\n // On reconnect (atlas may have restarted), re-arm kept sessions before the\n // stream resubscribes, so subscriptions resume against a hot account.\n stream.setBeforeResubscribe(() => this.client.rearmAll())\n await stream.connect()\n return stream\n }\n}\n","import type { Tickerall } from '../client'\nimport type { Candle, CandlesParams, CandlesResponse, RequestOptions } from '../types'\n\nexport class CandlesNamespace {\n constructor(private readonly client: Tickerall) {}\n\n /**\n * Fetch historical OHLC candles for a symbol from one of your broker\n * accounts.\n *\n * Candles are read from the account's own live broker connection, so pass\n * the `accountId` of a connected account. Coarser timeframes reach further\n * back; a single request returns as much history as fits in a few seconds,\n * so pass a large `hours` and take what comes back. Deep look-backs are\n * served on an isolated history connection and won't disturb your live tick\n * stream.\n *\n * @example\n * const bars = await client.candles.get(accountId, { symbol: 'BTCUSDm', hours: 8760, timeframe: 'D1' })\n */\n async get(accountId: string, params: CandlesParams, options?: RequestOptions): Promise<Candle[]> {\n const query = new URLSearchParams({ symbol: params.symbol, hours: String(params.hours) })\n if (params.timeframe) query.set('timeframe', params.timeframe)\n const res = await this.client.requestPlain<CandlesResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/candles?${query.toString()}` },\n options,\n )\n return res.candles\n }\n}\n","import type { Tickerall } from '../client'\nimport type { HistoryParams, HistoryResponse, HistoryTrade, RequestOptions } from '../types'\n\nfunction toQueryTime(v: string | number | Date): string {\n return v instanceof Date ? v.toISOString() : String(v)\n}\n\nexport class HistoryNamespace {\n constructor(private readonly client: Tickerall) {}\n\n /**\n * Closed-trade history for one of your broker accounts — executed deals\n * paired into round-trips, read from the account's own live broker\n * connection (the equivalent of MT5's history_deals_get for the recent\n * window).\n *\n * `symbol`/`from`/`to`/`limit` FILTER the broker's recent deal log (a few\n * weeks deep, broker-controlled) plus any closes seen live this session —\n * they don't fetch deeper than the broker's window. Pass the `accountId` of\n * a connected account.\n *\n * @example\n * const trades = await client.history.get(accountId, { symbol: 'BTCUSDm', limit: 100 })\n */\n async get(accountId: string, params: HistoryParams = {}, options?: RequestOptions): Promise<HistoryTrade[]> {\n const query = new URLSearchParams()\n if (params.symbol) query.set('symbol', params.symbol)\n if (params.from !== undefined) query.set('from', toQueryTime(params.from))\n if (params.to !== undefined) query.set('to', toQueryTime(params.to))\n if (params.limit !== undefined) query.set('limit', String(params.limit))\n if (params.waitMs !== undefined) query.set('waitMs', String(params.waitMs))\n const qs = query.toString()\n const res = await this.client.requestPlain<HistoryResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/history${qs ? `?${qs}` : ''}` },\n options,\n )\n return res.trades\n }\n}\n","import { mapErrorResponse, TickerallApiError, TickerallServiceUnavailableError } from './errors'\nimport { SessionsNamespace } from './namespaces/sessions'\nimport { AccountsNamespace } from './namespaces/accounts'\nimport { OrdersNamespace } from './namespaces/orders'\nimport { PositionsNamespace } from './namespaces/positions'\nimport { StreamNamespace } from './namespaces/stream'\nimport { CandlesNamespace } from './namespaces/candles'\nimport { HistoryNamespace } from './namespaces/history'\nimport type {\n ErrorBody,\n FetchLike,\n IdempotentRequestOptions,\n RequestOptions,\n SessionStartParams,\n SessionStartResult,\n TickerallClientConfig,\n} from './types'\n\nconst DEFAULT_BASE_URL = 'https://api.tickerall.com'\nconst DEFAULT_STREAM_URL = 'wss://api.tickerall.com/v1/stream'\nconst DEFAULT_TIMEOUT_MS = 30_000\nconst SDK_VERSION = '0.1.3'\n\n// Default ceiling on how long a `queueIfReconnecting` call waits across\n// replays before giving up. Bounded on purpose — a queued trade that finally\n// fires minutes late is rarely what the caller wanted.\nconst DEFAULT_QUEUE_MAX_MS = 60_000\n// Backoff between replay attempts for a queued request (ms). Each value is\n// also clamped to the remaining time before the call's deadline.\nconst REPLAY_DELAYS_MS = [500, 1_000, 2_000, 4_000, 8_000]\n\ninterface ReplayJob {\n run: () => Promise<unknown>\n resolve: (value: unknown) => void\n reject: (err: unknown) => void\n deadline: number\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/** @internal */\nexport interface InternalRequestInit {\n method: 'GET' | 'POST' | 'DELETE' | 'PATCH' | 'PUT'\n path: string\n body?: unknown\n idempotencyKey?: string\n signal?: AbortSignal\n timeout?: number\n expectNoContent?: boolean\n // The broker account this request targets, if any. Set by account-scoped\n // namespace methods so the client can transparently re-arm a kept session\n // (re-supply credentials) when the account has gone cold, then retry.\n accountId?: string\n}\n\nexport class Tickerall {\n readonly sessions: SessionsNamespace\n readonly accounts: AccountsNamespace\n readonly orders: OrdersNamespace\n readonly positions: PositionsNamespace\n readonly stream: StreamNamespace\n readonly candles: CandlesNamespace\n readonly history: HistoryNamespace\n\n private readonly apiKey: string\n private readonly baseUrl: string\n private readonly streamUrl: string\n private readonly timeout: number\n private readonly fetchImpl: FetchLike\n private readonly userAgent: string\n\n // In-order replay queue for `queueIfReconnecting` calls. Only opted-in\n // requests ever enter it; everything else bypasses it entirely.\n private readonly replayQueue: ReplayJob[] = []\n private replayDraining = false\n\n // Kept-session credentials — RAM only, NEVER persisted. The broker creds for\n // sessions the customer asked us to keep alive (sessions.keepAlive), so the\n // client can transparently re-arm them when atlas reports the account cold\n // (e.g. after an atlas restart dropped its server-side credentials).\n private readonly keptCreds = new Map<string, SessionStartParams>()\n private readonly onRearm?: (accountId: string) => void\n\n constructor(config: TickerallClientConfig) {\n if (!config || !config.apiKey) {\n throw new TypeError('Tickerall: `apiKey` is required.')\n }\n this.apiKey = config.apiKey\n this.baseUrl = trimTrailingSlash(config.baseUrl ?? DEFAULT_BASE_URL)\n this.streamUrl = config.streamUrl ?? DEFAULT_STREAM_URL\n this.timeout = config.timeout ?? DEFAULT_TIMEOUT_MS\n const resolvedFetch = config.fetch ?? globalThis.fetch\n if (typeof resolvedFetch !== 'function') {\n throw new TypeError('Tickerall: no `fetch` available — pass `fetch` in the config (Node <18 needs an explicit fetch).')\n }\n this.fetchImpl = resolvedFetch.bind(globalThis)\n this.userAgent = config.userAgent\n ? `${config.userAgent} tickerall-js/${SDK_VERSION}`\n : `tickerall-js/${SDK_VERSION}`\n this.onRearm = config.onRearm\n\n this.sessions = new SessionsNamespace(this)\n this.accounts = new AccountsNamespace(this)\n this.orders = new OrdersNamespace(this)\n this.positions = new PositionsNamespace(this)\n this.candles = new CandlesNamespace(this)\n this.history = new HistoryNamespace(this)\n this.stream = new StreamNamespace(this, {\n streamUrl: this.streamUrl,\n apiKey: this.apiKey,\n userAgent: this.userAgent,\n })\n }\n\n // Public entry — runs the request, transparently re-arming a kept session\n // and retrying ONCE if the account has gone cold.\n /** @internal */\n request<T>(init: InternalRequestInit): Promise<T> {\n return this.requestWithRearm<T>(init, false)\n }\n\n private async requestWithRearm<T>(init: InternalRequestInit, isRearmRetry: boolean): Promise<T> {\n try {\n return await this.requestOnce<T>(init)\n } catch (err) {\n // If a kept session's account went cold (e.g. an atlas restart dropped\n // its credentials), refresh them and retry the original request once.\n if (\n !isRearmRetry &&\n init.accountId !== undefined &&\n this.keptCreds.has(init.accountId) &&\n err instanceof TickerallApiError &&\n err.code === 'BROKER_ACCOUNT_NOT_HOT'\n ) {\n await this.rearm(init.accountId)\n return this.requestWithRearm<T>(init, true)\n }\n throw err\n }\n }\n\n private async requestOnce<T>(init: InternalRequestInit): Promise<T> {\n const url = `${this.baseUrl}${init.path}`\n const headers: Record<string, string> = {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'User-Agent': this.userAgent,\n 'Accept': 'application/json',\n }\n if (init.body !== undefined) headers['Content-Type'] = 'application/json'\n if (init.idempotencyKey) headers['Idempotency-Key'] = init.idempotencyKey\n\n const timeoutMs = init.timeout ?? this.timeout\n const controller = new AbortController()\n // Track who aborted: our own timeout is a transient connectivity symptom\n // (retryable), whereas a caller-supplied signal is a deliberate cancel.\n let timedOut = false\n const timer = setTimeout(() => {\n timedOut = true\n controller.abort(new Error(`Request timed out after ${timeoutMs}ms`))\n }, timeoutMs)\n if (init.signal) {\n if (init.signal.aborted) controller.abort(init.signal.reason)\n else init.signal.addEventListener('abort', () => controller.abort(init.signal!.reason), { once: true })\n }\n\n let response: Response\n try {\n response = await this.fetchImpl(url, {\n method: init.method,\n headers,\n body: init.body !== undefined ? JSON.stringify(init.body) : undefined,\n signal: controller.signal,\n })\n } catch (err) {\n clearTimeout(timer)\n if (timedOut) {\n // Timed out waiting for TickerAll — transient, safe to retry.\n throw new TickerallServiceUnavailableError({\n status: 0,\n code: 'REQUEST_TIMEOUT',\n message: `Request timed out after ${timeoutMs}ms`,\n })\n }\n if (controller.signal.aborted) {\n // Caller cancelled via their AbortSignal — deliberate, not transient.\n const reason = (controller.signal.reason as Error | undefined)?.message ?? (err as Error).message ?? 'Request aborted'\n throw new TickerallApiError({\n status: 0,\n code: 'REQUEST_ABORTED',\n message: reason,\n })\n }\n // fetch threw before any response — TickerAll was unreachable. Transient.\n throw new TickerallServiceUnavailableError({\n status: 0,\n code: 'NETWORK_ERROR',\n message: (err as Error).message || 'Network request failed',\n details: err,\n })\n } finally {\n clearTimeout(timer)\n }\n\n const requestId = response.headers.get('x-request-id') ?? undefined\n\n if (init.expectNoContent && response.status === 204) {\n return undefined as T\n }\n\n if (!response.ok) {\n const body = await safeReadErrorBody(response)\n throw mapErrorResponse({\n status: response.status,\n code: body?.error ?? `HTTP_${response.status}`,\n message: body?.message ?? response.statusText ?? 'Request failed',\n details: body?.details,\n requestId,\n })\n }\n\n if (response.status === 204) return undefined as T\n const json = (await response.json()) as T\n return json\n }\n\n /** @internal */\n async requestIdempotent<T>(init: InternalRequestInit, options?: IdempotentRequestOptions): Promise<T> {\n // Fix the idempotency key ONCE so every replay attempt carries the same\n // key — the server then dedupes any attempt that already executed, which\n // is what makes queue-and-replay safe (no double trade).\n const key = options?.idempotencyKey ?? generateIdempotencyKey()\n const full: InternalRequestInit = {\n ...init,\n idempotencyKey: key,\n signal: options?.signal,\n timeout: options?.timeout,\n }\n if (options?.queueIfReconnecting) {\n return this.enqueueReplay<T>(full, options.queueMaxMs ?? DEFAULT_QUEUE_MAX_MS)\n }\n // Default: fail fast. A transient connectivity failure surfaces as\n // TickerallServiceUnavailableError for the caller to re-decide.\n return this.request<T>(full)\n }\n\n // Queue a request for in-order replay, retrying transient failures with\n // backoff until it succeeds or `maxMs` elapses.\n private enqueueReplay<T>(init: InternalRequestInit, maxMs: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n this.replayQueue.push({\n run: () => this.request<unknown>(init),\n resolve: resolve as (value: unknown) => void,\n reject,\n deadline: Date.now() + maxMs,\n })\n void this.drainReplayQueue()\n })\n }\n\n // Serial drain: the head job must settle (resolve, reject, or expire) before\n // the next is attempted, so queued writes replay in submission order.\n private async drainReplayQueue(): Promise<void> {\n if (this.replayDraining) return\n this.replayDraining = true\n try {\n while (this.replayQueue.length > 0) {\n const job = this.replayQueue[0]!\n // Reject up front if this job already expired while head-of-line\n // blocked behind an earlier one riding out a long outage.\n if (Date.now() >= job.deadline) {\n job.reject(new TickerallServiceUnavailableError({\n status: 0,\n code: 'QUEUE_TIMEOUT',\n message: 'Queued request expired before connectivity returned',\n }))\n this.replayQueue.shift()\n continue\n }\n let attempt = 0\n for (;;) {\n try {\n job.resolve(await job.run())\n this.replayQueue.shift()\n break\n } catch (err) {\n const isTransient = err instanceof TickerallApiError && err.transient\n const remaining = job.deadline - Date.now()\n if (!isTransient || remaining <= 0) {\n // Non-transient (bad request, broker rejection, …) never retries;\n // a transient failure past the deadline gives up.\n job.reject(err)\n this.replayQueue.shift()\n break\n }\n const base = REPLAY_DELAYS_MS[Math.min(attempt, REPLAY_DELAYS_MS.length - 1)]!\n attempt += 1\n await sleep(Math.min(base, remaining))\n }\n }\n }\n } finally {\n this.replayDraining = false\n }\n }\n\n /** @internal */\n requestPlain<T>(init: InternalRequestInit, options?: RequestOptions): Promise<T> {\n return this.request<T>({\n ...init,\n signal: options?.signal,\n timeout: options?.timeout,\n })\n }\n\n // ── Kept sessions (auto re-arm) ──────────────────────────────────────────\n // Credentials live in this process's memory only — nothing is persisted.\n\n /** Cache broker creds for an account so the client can auto re-arm it. @internal */\n registerKeptSession(accountId: string, params: SessionStartParams): void {\n this.keptCreds.set(accountId, params)\n }\n\n /** Stop auto-re-arming an account and drop its cached credentials. @internal */\n unregisterKeptSession(accountId: string): void {\n this.keptCreds.delete(accountId)\n }\n\n /** Account IDs currently kept alive (i.e. have cached re-arm credentials). @internal */\n keptSessionIds(): string[] {\n return [...this.keptCreds.keys()]\n }\n\n /**\n * Re-supply credentials for a kept account (a fresh `session.start`) to bring\n * a cold connection back. Throws if the account isn't being kept alive.\n * @internal\n */\n async rearm(accountId: string): Promise<void> {\n const creds = this.keptCreds.get(accountId)\n if (!creds) {\n throw new TickerallApiError({\n status: 0,\n code: 'NO_KEPT_CREDENTIALS',\n message: `No kept credentials for account ${accountId}; call sessions.keepAlive first.`,\n })\n }\n this.onRearm?.(accountId)\n // session.start carries no accountId, so this never recurses into re-arm.\n await this.requestIdempotent<SessionStartResult>({ method: 'POST', path: '/v1/sessions', body: creds })\n }\n\n /**\n * Re-arm every kept session — best-effort (one failure won't block the\n * others). Used after the stream reconnects (atlas may have restarted).\n * @internal\n */\n async rearmAll(): Promise<void> {\n await Promise.all([...this.keptCreds.keys()].map(id => this.rearm(id).catch(() => { /* best-effort */ })))\n }\n}\n\nfunction trimTrailingSlash(s: string): string {\n return s.endsWith('/') ? s.slice(0, -1) : s\n}\n\nasync function safeReadErrorBody(response: Response): Promise<ErrorBody | null> {\n try {\n const text = await response.text()\n if (!text) return null\n try {\n return JSON.parse(text) as ErrorBody\n } catch {\n return { error: 'PARSE_ERROR', message: text }\n }\n } catch {\n return null\n }\n}\n\nexport function generateIdempotencyKey(): string {\n const c: { randomUUID?: () => string } | undefined = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n if (c && typeof c.randomUUID === 'function') return c.randomUUID()\n return fallbackUuid()\n}\n\nfunction fallbackUuid(): string {\n const bytes = new Uint8Array(16)\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256)\n bytes[6] = (bytes[6]! & 0x0f) | 0x40\n bytes[8] = (bytes[8]! & 0x3f) | 0x80\n const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {EventEmitter}from'events';import p from'ws';var a=class extends Error{constructor(e){super(e.message),this.name="TickerallApiError",this.status=e.status,this.code=e.code,this.requestId=e.requestId,this.details=e.details,this.transient=e.transient??false;}},h=class extends a{constructor(e){super(e),this.name="TickerallAuthError";}},y=class extends a{constructor(e){super(e),this.name="TickerallForbiddenError";}},g=class extends a{constructor(e){super(e),this.name="TickerallValidationError";}},f=class extends a{constructor(e){super(e),this.name="TickerallNotFoundError";}},T=class extends a{constructor(e){super(e),this.name="TickerallBrokerError";}},d=class extends a{constructor(e){super({...e,transient:true}),this.name="TickerallServiceUnavailableError";}},$=new Set(["BROKER_REJECTED","BROKER_AUTH_FAILED","BROKER_UNREACHABLE","BROKER_ACCOUNT_NOT_HOT","BROKER_ACCOUNT_ALREADY_LINKED","BROKER_ACCOUNT_NOT_FOUND","TICKET_NOT_FOUND"]);function q(r){return r.code==="POOL_SHUTTING_DOWN"?new d(r):$.has(r.code)?new T(r):r.status===401?new h(r):r.status===403?new y(r):r.status===404?new f(r):r.status===400||r.status===422?new g(r):r.status===503||r.status===502?new d(r):new a(r)}var b=class{constructor(e){this.client=e;}start(e,t){return this.client.requestIdempotent({method:"POST",path:"/v1/sessions",body:e},t)}async keepAlive(e,t){let s=await this.start(e,t);return this.client.registerKeptSession(s.accountId,e),s}stopKeepAlive(e){this.client.unregisterKeptSession(e);}rearm(e){return this.client.rearm(e)}async pendingRearm(e){return (await this.client.requestPlain({method:"GET",path:"/v1/always-hot/pending"},e)).pending}async rearmPending(e){let t=await this.pendingRearm(e),s=new Set(this.client.keptSessionIds()),n=[];for(let i of t)s.has(i.id)&&(await this.client.rearm(i.id).catch(()=>{}),n.push(i.id));return n}end(e,t){return this.client.unregisterKeptSession(e),this.client.requestPlain({method:"DELETE",path:`/v1/sessions/${encodeURIComponent(e)}`,expectNoContent:true},t)}};var R=class{constructor(e){this.client=e;}list(e){return this.client.requestPlain({method:"GET",path:"/v1/accounts"},e)}get(e,t){return this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}`,accountId:e},t)}async symbols(e,t){return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/symbols`,accountId:e},t)).symbols}async symbolSpecs(e,t){return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/symbol-specs`,accountId:e},t)).specs}};var P=class{constructor(e){this.client=e;}place(e,t,s){return this.client.requestIdempotent({method:"POST",path:`/v1/accounts/${encodeURIComponent(e)}/orders`,body:t,accountId:e},s)}async listPending(e,t={},s){let n=t.waitMs!==void 0?`?waitMs=${encodeURIComponent(String(t.waitMs))}`:"";return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/orders/pending${n}`,accountId:e},s)).orders}cancelPending(e,t,s){return this.client.requestIdempotent({method:"DELETE",path:`/v1/accounts/${encodeURIComponent(e)}/orders/${t}`,accountId:e},s)}modifyPending(e,t,s,n){return this.client.requestIdempotent({method:"PATCH",path:`/v1/accounts/${encodeURIComponent(e)}/orders/${t}`,body:s,accountId:e},n)}};var v=class{constructor(e){this.client=e;}close(e,t,s={},n){return this.client.requestIdempotent({method:"DELETE",path:`/v1/accounts/${encodeURIComponent(e)}/positions/${t}`,body:s,accountId:e},n)}modify(e,t,s,n){return this.client.requestIdempotent({method:"PATCH",path:`/v1/accounts/${encodeURIComponent(e)}/positions/${t}`,body:s,accountId:e},n)}};var K=25e3,L=1e4,U=[1e3,2e3,4e3,8e3,16e3,3e4],_=3e4,H={opened:"position-opened",updated:"position-updated",closed:"position-closed"},S=class extends EventEmitter{constructor(t,s,n){super();this.ws=null;this.closedByUser=false;this.state="closed";this.reconnectAttempts=0;this.reconnectTimer=null;this.heartbeatTimer=null;this.heartbeatTimeoutTimer=null;this.subs=new Map;this.url=t,this.headers={Authorization:`Bearer ${s}`,"User-Agent":n},this.on("error",()=>{});}on(t,s){return super.on(t,s)}once(t,s){return super.once(t,s)}off(t,s){return super.off(t,s)}async connect(){this.closedByUser=false,this.state="connecting",await this.openOnce();}setBeforeResubscribe(t){this.beforeResubscribe=t;}getState(){return this.state}isConnected(){return this.state==="open"&&this.ws?.readyState===p.OPEN}waitUntilConnected(t=3e4){return this.isConnected()?Promise.resolve():this.state==="closed"?Promise.reject(new Error("Stream is closed")):new Promise((s,n)=>{let i,o=()=>{clearTimeout(i),s();};i=setTimeout(()=>{this.off("open",o),n(new Error(`waitUntilConnected: timed out after ${t}ms`));},t),this.once("open",o);})}openOnce(){return new Promise((t,s)=>{let n=new p(this.url,{headers:this.headers});this.ws=n;let i=false,o=async()=>{if(i)return;i=true;let u=this.reconnectAttempts>0;if(this.state="open",this.reconnectAttempts=0,this.startHeartbeat(),u&&this.beforeResubscribe)try{await this.beforeResubscribe();}catch{}this.resendSubscriptions(),this.emit("open"),t();},m=u=>{try{let c=JSON.parse(u.toString());this.handleFrame(c);}catch(c){this.emit("error",{message:"Failed to parse server frame",cause:c});}},l=u=>{i||(i=true,s(u)),this.emit("error",{message:u.message,cause:u});},O=(u,c)=>{this.stopHeartbeat(),this.ws=null;let A=c?.toString()??"";this.emit("close",{code:u,reason:A}),i||(i=true,s(new Error(`WebSocket closed before open (code=${u})`))),this.closedByUser||(this.state="reconnecting",this.scheduleReconnect());};n.on("open",o),n.on("message",m),n.on("error",l),n.on("close",O),n.on("pong",()=>this.clearHeartbeatTimeout());})}handleFrame(t){switch(t.type){case "tick":this.emit("tick",{type:"tick",accountId:t.accountId,symbol:t.symbol,bid:t.bid,ask:t.ask,timestamp:t.timestamp});return;case "position_update":this.emit("position",{type:"position",accountId:t.accountId,event:H[t.event]??"position-updated",position:t.position});return;case "account_update":this.emit("account",{type:"account",accountId:t.accountId,snapshot:t.snapshot});return;case "subscribed":t.rejected&&t.rejected.length>0&&this.emit("error",{message:`Subscribe rejected: ${t.rejected.map(s=>`${s.code} (${s.reason})`).join(", ")}`});return;case "error":this.emit("error",{message:`${t.code}: ${t.message}`});return;case "pong":this.clearHeartbeatTimeout();return}}startHeartbeat(){this.stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{if(!(!this.ws||this.ws.readyState!==p.OPEN)){this.send({type:"ping"});try{this.ws.ping();}catch{}this.heartbeatTimeoutTimer=setTimeout(()=>this.forceReconnect("heartbeat-timeout"),L);}},K);}clearHeartbeatTimeout(){this.heartbeatTimeoutTimer&&(clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimeoutTimer=null);}stopHeartbeat(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimeoutTimer&&clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimer=null,this.heartbeatTimeoutTimer=null;}forceReconnect(t){if(this.ws)try{this.ws.terminate();}catch{}}scheduleReconnect(){if(this.closedByUser||this.reconnectTimer)return;let t=Math.min(this.reconnectAttempts,U.length-1),s=U[t]??_,n=Math.floor(Math.random()*Math.min(s,1e3)),i=Math.min(s+n,_+1e3);this.reconnectAttempts+=1;let o=this.reconnectAttempts;this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.emit("reconnect",{attempt:o}),this.openOnce().catch(m=>{this.emit("error",{message:"Reconnect failed",cause:m}),this.scheduleReconnect();});},i);}resendSubscriptions(){let t=[];for(let s of this.subs.values())s.kind==="ticks"?t.push({kind:"ticks",accountId:s.accountId,symbols:[...s.symbols]}):t.push({kind:s.kind,accountId:s.accountId});t.length>0&&this.send({type:"subscribe",channels:t});}send(t){if(!(!this.ws||this.ws.readyState!==p.OPEN))try{this.ws.send(JSON.stringify(t));}catch(s){this.emit("error",{message:"Failed to send frame",cause:s});}}async subscribeTicks(t,s){let n=E("ticks",t),i=this.subs.get(n);if(i&&i.kind==="ticks")for(let o of s)i.symbols.add(o);else this.subs.set(n,{kind:"ticks",accountId:t,symbols:new Set(s)});this.send({type:"subscribe",channels:[{kind:"ticks",accountId:t,symbols:s}]});}async unsubscribeTicks(t,s){let n=E("ticks",t),i=this.subs.get(n);if(i&&i.kind==="ticks"){for(let o of s)i.symbols.delete(o);i.symbols.size===0&&this.subs.delete(n);}this.send({type:"unsubscribe",channels:[{kind:"ticks",accountId:t,symbols:s}]});}async subscribePositions(t){this.subs.set(E("positions",t),{kind:"positions",accountId:t}),this.send({type:"subscribe",channels:[{kind:"positions",accountId:t}]});}async subscribeAccount(t){this.subs.set(E("account",t),{kind:"account",accountId:t}),this.send({type:"subscribe",channels:[{kind:"account",accountId:t}]});}async close(){this.closedByUser=true,this.state="closed",this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.stopHeartbeat();let t=this.ws;if(t&&t.readyState!==p.CLOSED)return new Promise(s=>{let n=()=>s();t.once("close",n);try{t.close();}catch{s();}})}};function E(r,e){return `${r}:${e}`}var k=class{constructor(e,t){this.client=e,this.streamUrl=t.streamUrl,this.apiKey=t.apiKey,this.userAgent=t.userAgent;}async connect(){let e=new S(this.streamUrl,this.apiKey,this.userAgent);return e.setBeforeResubscribe(()=>this.client.rearmAll()),await e.connect(),e}};var I=class{constructor(e){this.client=e;}async get(e,t,s){let n=new URLSearchParams({symbol:t.symbol,hours:String(t.hours)});return t.timeframe&&n.set("timeframe",t.timeframe),(await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/candles?${n.toString()}`},s)).candles}};function x(r){return r instanceof Date?r.toISOString():String(r)}var w=class{constructor(e){this.client=e;}async get(e,t={},s){let n=new URLSearchParams;t.symbol&&n.set("symbol",t.symbol),t.from!==void 0&&n.set("from",x(t.from)),t.to!==void 0&&n.set("to",x(t.to)),t.limit!==void 0&&n.set("limit",String(t.limit)),t.waitMs!==void 0&&n.set("waitMs",String(t.waitMs));let i=n.toString();return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/history${i?`?${i}`:""}`},s)).trades}};var B="https://api.tickerall.com",F="wss://api.tickerall.com/v1/stream",j=3e4,M="0.1.2",Q=6e4,N=[500,1e3,2e3,4e3,8e3];function G(r){return new Promise(e=>setTimeout(e,r))}var C=class{constructor(e){this.replayQueue=[];this.replayDraining=false;this.keptCreds=new Map;if(!e||!e.apiKey)throw new TypeError("Tickerall: `apiKey` is required.");this.apiKey=e.apiKey,this.baseUrl=W(e.baseUrl??B),this.streamUrl=e.streamUrl??F,this.timeout=e.timeout??j;let t=e.fetch??globalThis.fetch;if(typeof t!="function")throw new TypeError("Tickerall: no `fetch` available \u2014 pass `fetch` in the config (Node <18 needs an explicit fetch).");this.fetchImpl=t.bind(globalThis),this.userAgent=e.userAgent?`${e.userAgent} tickerall-js/${M}`:`tickerall-js/${M}`,this.onRearm=e.onRearm,this.sessions=new b(this),this.accounts=new R(this),this.orders=new P(this),this.positions=new v(this),this.candles=new I(this),this.history=new w(this),this.stream=new k(this,{streamUrl:this.streamUrl,apiKey:this.apiKey,userAgent:this.userAgent});}request(e){return this.requestWithRearm(e,false)}async requestWithRearm(e,t){try{return await this.requestOnce(e)}catch(s){if(!t&&e.accountId!==void 0&&this.keptCreds.has(e.accountId)&&s instanceof a&&s.code==="BROKER_ACCOUNT_NOT_HOT")return await this.rearm(e.accountId),this.requestWithRearm(e,true);throw s}}async requestOnce(e){let t=`${this.baseUrl}${e.path}`,s={Authorization:`Bearer ${this.apiKey}`,"User-Agent":this.userAgent,Accept:"application/json"};e.body!==void 0&&(s["Content-Type"]="application/json"),e.idempotencyKey&&(s["Idempotency-Key"]=e.idempotencyKey);let n=e.timeout??this.timeout,i=new AbortController,o=false,m=setTimeout(()=>{o=true,i.abort(new Error(`Request timed out after ${n}ms`));},n);e.signal&&(e.signal.aborted?i.abort(e.signal.reason):e.signal.addEventListener("abort",()=>i.abort(e.signal.reason),{once:true}));let l;try{l=await this.fetchImpl(t,{method:e.method,headers:s,body:e.body!==void 0?JSON.stringify(e.body):void 0,signal:i.signal});}catch(c){if(clearTimeout(m),o)throw new d({status:0,code:"REQUEST_TIMEOUT",message:`Request timed out after ${n}ms`});if(i.signal.aborted){let A=i.signal.reason?.message??c.message??"Request aborted";throw new a({status:0,code:"REQUEST_ABORTED",message:A})}throw new d({status:0,code:"NETWORK_ERROR",message:c.message||"Network request failed",details:c})}finally{clearTimeout(m);}let O=l.headers.get("x-request-id")??void 0;if(e.expectNoContent&&l.status===204)return;if(!l.ok){let c=await J(l);throw q({status:l.status,code:c?.error??`HTTP_${l.status}`,message:c?.message??l.statusText??"Request failed",details:c?.details,requestId:O})}return l.status===204?void 0:await l.json()}async requestIdempotent(e,t){let s=t?.idempotencyKey??Y(),n={...e,idempotencyKey:s,signal:t?.signal,timeout:t?.timeout};return t?.queueIfReconnecting?this.enqueueReplay(n,t.queueMaxMs??Q):this.request(n)}enqueueReplay(e,t){return new Promise((s,n)=>{this.replayQueue.push({run:()=>this.request(e),resolve:s,reject:n,deadline:Date.now()+t}),this.drainReplayQueue();})}async drainReplayQueue(){if(!this.replayDraining){this.replayDraining=true;try{for(;this.replayQueue.length>0;){let e=this.replayQueue[0];if(Date.now()>=e.deadline){e.reject(new d({status:0,code:"QUEUE_TIMEOUT",message:"Queued request expired before connectivity returned"})),this.replayQueue.shift();continue}let t=0;for(;;)try{e.resolve(await e.run()),this.replayQueue.shift();break}catch(s){let n=s instanceof a&&s.transient,i=e.deadline-Date.now();if(!n||i<=0){e.reject(s),this.replayQueue.shift();break}let o=N[Math.min(t,N.length-1)];t+=1,await G(Math.min(o,i));}}}finally{this.replayDraining=false;}}}requestPlain(e,t){return this.request({...e,signal:t?.signal,timeout:t?.timeout})}registerKeptSession(e,t){this.keptCreds.set(e,t);}unregisterKeptSession(e){this.keptCreds.delete(e);}keptSessionIds(){return [...this.keptCreds.keys()]}async rearm(e){let t=this.keptCreds.get(e);if(!t)throw new a({status:0,code:"NO_KEPT_CREDENTIALS",message:`No kept credentials for account ${e}; call sessions.keepAlive first.`});this.onRearm?.(e),await this.requestIdempotent({method:"POST",path:"/v1/sessions",body:t});}async rearmAll(){await Promise.all([...this.keptCreds.keys()].map(e=>this.rearm(e).catch(()=>{})));}};function W(r){return r.endsWith("/")?r.slice(0,-1):r}async function J(r){try{let e=await r.text();if(!e)return null;try{return JSON.parse(e)}catch{return {error:"PARSE_ERROR",message:e}}}catch{return null}}function Y(){let r=globalThis.crypto;return r&&typeof r.randomUUID=="function"?r.randomUUID():z()}function z(){let r=new Uint8Array(16);for(let t=0;t<16;t++)r[t]=Math.floor(Math.random()*256);r[6]=r[6]&15|64,r[8]=r[8]&63|128;let e=Array.from(r,t=>t.toString(16).padStart(2,"0")).join("");return `${e.slice(0,8)}-${e.slice(8,12)}-${e.slice(12,16)}-${e.slice(16,20)}-${e.slice(20)}`}
|
|
1
|
+
import {EventEmitter}from'events';import p from'ws';var a=class extends Error{constructor(e){super(e.message),this.name="TickerallApiError",this.status=e.status,this.code=e.code,this.requestId=e.requestId,this.details=e.details,this.transient=e.transient??false;}},h=class extends a{constructor(e){super(e),this.name="TickerallAuthError";}},y=class extends a{constructor(e){super(e),this.name="TickerallForbiddenError";}},g=class extends a{constructor(e){super(e),this.name="TickerallValidationError";}},f=class extends a{constructor(e){super(e),this.name="TickerallNotFoundError";}},T=class extends a{constructor(e){super(e),this.name="TickerallBrokerError";}},d=class extends a{constructor(e){super({...e,transient:true}),this.name="TickerallServiceUnavailableError";}},$=new Set(["BROKER_REJECTED","BROKER_AUTH_FAILED","BROKER_UNREACHABLE","BROKER_ACCOUNT_NOT_HOT","BROKER_ACCOUNT_ALREADY_LINKED","BROKER_ACCOUNT_NOT_FOUND","TICKET_NOT_FOUND"]);function q(r){return r.code==="POOL_SHUTTING_DOWN"?new d(r):$.has(r.code)?new T(r):r.status===401?new h(r):r.status===403?new y(r):r.status===404?new f(r):r.status===400||r.status===422?new g(r):r.status===503||r.status===502?new d(r):new a(r)}var b=class{constructor(e){this.client=e;}start(e,t){return this.client.requestIdempotent({method:"POST",path:"/v1/sessions",body:e},t)}async keepAlive(e,t){let s=await this.start(e,t);return this.client.registerKeptSession(s.accountId,e),s}stopKeepAlive(e){this.client.unregisterKeptSession(e);}rearm(e){return this.client.rearm(e)}async pendingRearm(e){return (await this.client.requestPlain({method:"GET",path:"/v1/always-hot/pending"},e)).pending}async rearmPending(e){let t=await this.pendingRearm(e),s=new Set(this.client.keptSessionIds()),n=[];for(let i of t)s.has(i.id)&&(await this.client.rearm(i.id).catch(()=>{}),n.push(i.id));return n}end(e,t){return this.client.unregisterKeptSession(e),this.client.requestPlain({method:"DELETE",path:`/v1/sessions/${encodeURIComponent(e)}`,expectNoContent:true},t)}};var R=class{constructor(e){this.client=e;}list(e){return this.client.requestPlain({method:"GET",path:"/v1/accounts"},e)}get(e,t){return this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}`,accountId:e},t)}async symbols(e,t){return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/symbols`,accountId:e},t)).symbols}async symbolSpecs(e,t){return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/symbol-specs`,accountId:e},t)).specs}};var P=class{constructor(e){this.client=e;}place(e,t,s){return this.client.requestIdempotent({method:"POST",path:`/v1/accounts/${encodeURIComponent(e)}/orders`,body:t,accountId:e},s)}async listPending(e,t={},s){let n=t.waitMs!==void 0?`?waitMs=${encodeURIComponent(String(t.waitMs))}`:"";return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/orders/pending${n}`,accountId:e},s)).orders}cancelPending(e,t,s){return this.client.requestIdempotent({method:"DELETE",path:`/v1/accounts/${encodeURIComponent(e)}/orders/${t}`,accountId:e},s)}modifyPending(e,t,s,n){return this.client.requestIdempotent({method:"PATCH",path:`/v1/accounts/${encodeURIComponent(e)}/orders/${t}`,body:s,accountId:e},n)}};var v=class{constructor(e){this.client=e;}close(e,t,s={},n){return this.client.requestIdempotent({method:"DELETE",path:`/v1/accounts/${encodeURIComponent(e)}/positions/${t}`,body:s,accountId:e},n)}modify(e,t,s,n){return this.client.requestIdempotent({method:"PATCH",path:`/v1/accounts/${encodeURIComponent(e)}/positions/${t}`,body:s,accountId:e},n)}};var K=25e3,L=1e4,U=[1e3,2e3,4e3,8e3,16e3,3e4],_=3e4,H={opened:"position-opened",updated:"position-updated",closed:"position-closed"},S=class extends EventEmitter{constructor(t,s,n){super();this.ws=null;this.closedByUser=false;this.state="closed";this.reconnectAttempts=0;this.reconnectTimer=null;this.heartbeatTimer=null;this.heartbeatTimeoutTimer=null;this.subs=new Map;this.url=t,this.headers={Authorization:`Bearer ${s}`,"User-Agent":n},this.on("error",()=>{});}on(t,s){return super.on(t,s)}once(t,s){return super.once(t,s)}off(t,s){return super.off(t,s)}async connect(){this.closedByUser=false,this.state="connecting",await this.openOnce();}setBeforeResubscribe(t){this.beforeResubscribe=t;}getState(){return this.state}isConnected(){return this.state==="open"&&this.ws?.readyState===p.OPEN}waitUntilConnected(t=3e4){return this.isConnected()?Promise.resolve():this.state==="closed"?Promise.reject(new Error("Stream is closed")):new Promise((s,n)=>{let i,o=()=>{clearTimeout(i),s();};i=setTimeout(()=>{this.off("open",o),n(new Error(`waitUntilConnected: timed out after ${t}ms`));},t),this.once("open",o);})}openOnce(){return new Promise((t,s)=>{let n=new p(this.url,{headers:this.headers});this.ws=n;let i=false,o=async()=>{if(i)return;i=true;let u=this.reconnectAttempts>0;if(this.state="open",this.reconnectAttempts=0,this.startHeartbeat(),u&&this.beforeResubscribe)try{await this.beforeResubscribe();}catch{}this.resendSubscriptions(),this.emit("open"),t();},m=u=>{try{let c=JSON.parse(u.toString());this.handleFrame(c);}catch(c){this.emit("error",{message:"Failed to parse server frame",cause:c});}},l=u=>{i||(i=true,s(u)),this.emit("error",{message:u.message,cause:u});},O=(u,c)=>{this.stopHeartbeat(),this.ws=null;let A=c?.toString()??"";this.emit("close",{code:u,reason:A}),i||(i=true,s(new Error(`WebSocket closed before open (code=${u})`))),this.closedByUser||(this.state="reconnecting",this.scheduleReconnect());};n.on("open",o),n.on("message",m),n.on("error",l),n.on("close",O),n.on("pong",()=>this.clearHeartbeatTimeout());})}handleFrame(t){switch(t.type){case "tick":this.emit("tick",{type:"tick",accountId:t.accountId,symbol:t.symbol,bid:t.bid,ask:t.ask,timestamp:t.timestamp});return;case "position_update":this.emit("position",{type:"position",accountId:t.accountId,event:H[t.event]??"position-updated",position:t.position});return;case "account_update":this.emit("account",{type:"account",accountId:t.accountId,snapshot:t.snapshot});return;case "subscribed":t.rejected&&t.rejected.length>0&&this.emit("error",{message:`Subscribe rejected: ${t.rejected.map(s=>`${s.code} (${s.reason})`).join(", ")}`});return;case "error":this.emit("error",{message:`${t.code}: ${t.message}`});return;case "pong":this.clearHeartbeatTimeout();return}}startHeartbeat(){this.stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{if(!(!this.ws||this.ws.readyState!==p.OPEN)){this.send({type:"ping"});try{this.ws.ping();}catch{}this.heartbeatTimeoutTimer=setTimeout(()=>this.forceReconnect("heartbeat-timeout"),L);}},K);}clearHeartbeatTimeout(){this.heartbeatTimeoutTimer&&(clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimeoutTimer=null);}stopHeartbeat(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimeoutTimer&&clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimer=null,this.heartbeatTimeoutTimer=null;}forceReconnect(t){if(this.ws)try{this.ws.terminate();}catch{}}scheduleReconnect(){if(this.closedByUser||this.reconnectTimer)return;let t=Math.min(this.reconnectAttempts,U.length-1),s=U[t]??_,n=Math.floor(Math.random()*Math.min(s,1e3)),i=Math.min(s+n,_+1e3);this.reconnectAttempts+=1;let o=this.reconnectAttempts;this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.emit("reconnect",{attempt:o}),this.openOnce().catch(m=>{this.emit("error",{message:"Reconnect failed",cause:m}),this.scheduleReconnect();});},i);}resendSubscriptions(){let t=[];for(let s of this.subs.values())s.kind==="ticks"?t.push({kind:"ticks",accountId:s.accountId,symbols:[...s.symbols]}):t.push({kind:s.kind,accountId:s.accountId});t.length>0&&this.send({type:"subscribe",channels:t});}send(t){if(!(!this.ws||this.ws.readyState!==p.OPEN))try{this.ws.send(JSON.stringify(t));}catch(s){this.emit("error",{message:"Failed to send frame",cause:s});}}async subscribeTicks(t,s){let n=E("ticks",t),i=this.subs.get(n);if(i&&i.kind==="ticks")for(let o of s)i.symbols.add(o);else this.subs.set(n,{kind:"ticks",accountId:t,symbols:new Set(s)});this.send({type:"subscribe",channels:[{kind:"ticks",accountId:t,symbols:s}]});}async unsubscribeTicks(t,s){let n=E("ticks",t),i=this.subs.get(n);if(i&&i.kind==="ticks"){for(let o of s)i.symbols.delete(o);i.symbols.size===0&&this.subs.delete(n);}this.send({type:"unsubscribe",channels:[{kind:"ticks",accountId:t,symbols:s}]});}async subscribePositions(t){this.subs.set(E("positions",t),{kind:"positions",accountId:t}),this.send({type:"subscribe",channels:[{kind:"positions",accountId:t}]});}async subscribeAccount(t){this.subs.set(E("account",t),{kind:"account",accountId:t}),this.send({type:"subscribe",channels:[{kind:"account",accountId:t}]});}async close(){this.closedByUser=true,this.state="closed",this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.stopHeartbeat();let t=this.ws;if(t&&t.readyState!==p.CLOSED)return new Promise(s=>{let n=()=>s();t.once("close",n);try{t.close();}catch{s();}})}};function E(r,e){return `${r}:${e}`}var k=class{constructor(e,t){this.client=e,this.streamUrl=t.streamUrl,this.apiKey=t.apiKey,this.userAgent=t.userAgent;}async connect(){let e=new S(this.streamUrl,this.apiKey,this.userAgent);return e.setBeforeResubscribe(()=>this.client.rearmAll()),await e.connect(),e}};var I=class{constructor(e){this.client=e;}async get(e,t,s){let n=new URLSearchParams({symbol:t.symbol,hours:String(t.hours)});return t.timeframe&&n.set("timeframe",t.timeframe),(await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/candles?${n.toString()}`},s)).candles}};function x(r){return r instanceof Date?r.toISOString():String(r)}var w=class{constructor(e){this.client=e;}async get(e,t={},s){let n=new URLSearchParams;t.symbol&&n.set("symbol",t.symbol),t.from!==void 0&&n.set("from",x(t.from)),t.to!==void 0&&n.set("to",x(t.to)),t.limit!==void 0&&n.set("limit",String(t.limit)),t.waitMs!==void 0&&n.set("waitMs",String(t.waitMs));let i=n.toString();return (await this.client.requestPlain({method:"GET",path:`/v1/accounts/${encodeURIComponent(e)}/history${i?`?${i}`:""}`},s)).trades}};var B="https://api.tickerall.com",F="wss://api.tickerall.com/v1/stream",j=3e4,M="0.1.3",Q=6e4,N=[500,1e3,2e3,4e3,8e3];function G(r){return new Promise(e=>setTimeout(e,r))}var C=class{constructor(e){this.replayQueue=[];this.replayDraining=false;this.keptCreds=new Map;if(!e||!e.apiKey)throw new TypeError("Tickerall: `apiKey` is required.");this.apiKey=e.apiKey,this.baseUrl=W(e.baseUrl??B),this.streamUrl=e.streamUrl??F,this.timeout=e.timeout??j;let t=e.fetch??globalThis.fetch;if(typeof t!="function")throw new TypeError("Tickerall: no `fetch` available \u2014 pass `fetch` in the config (Node <18 needs an explicit fetch).");this.fetchImpl=t.bind(globalThis),this.userAgent=e.userAgent?`${e.userAgent} tickerall-js/${M}`:`tickerall-js/${M}`,this.onRearm=e.onRearm,this.sessions=new b(this),this.accounts=new R(this),this.orders=new P(this),this.positions=new v(this),this.candles=new I(this),this.history=new w(this),this.stream=new k(this,{streamUrl:this.streamUrl,apiKey:this.apiKey,userAgent:this.userAgent});}request(e){return this.requestWithRearm(e,false)}async requestWithRearm(e,t){try{return await this.requestOnce(e)}catch(s){if(!t&&e.accountId!==void 0&&this.keptCreds.has(e.accountId)&&s instanceof a&&s.code==="BROKER_ACCOUNT_NOT_HOT")return await this.rearm(e.accountId),this.requestWithRearm(e,true);throw s}}async requestOnce(e){let t=`${this.baseUrl}${e.path}`,s={Authorization:`Bearer ${this.apiKey}`,"User-Agent":this.userAgent,Accept:"application/json"};e.body!==void 0&&(s["Content-Type"]="application/json"),e.idempotencyKey&&(s["Idempotency-Key"]=e.idempotencyKey);let n=e.timeout??this.timeout,i=new AbortController,o=false,m=setTimeout(()=>{o=true,i.abort(new Error(`Request timed out after ${n}ms`));},n);e.signal&&(e.signal.aborted?i.abort(e.signal.reason):e.signal.addEventListener("abort",()=>i.abort(e.signal.reason),{once:true}));let l;try{l=await this.fetchImpl(t,{method:e.method,headers:s,body:e.body!==void 0?JSON.stringify(e.body):void 0,signal:i.signal});}catch(c){if(clearTimeout(m),o)throw new d({status:0,code:"REQUEST_TIMEOUT",message:`Request timed out after ${n}ms`});if(i.signal.aborted){let A=i.signal.reason?.message??c.message??"Request aborted";throw new a({status:0,code:"REQUEST_ABORTED",message:A})}throw new d({status:0,code:"NETWORK_ERROR",message:c.message||"Network request failed",details:c})}finally{clearTimeout(m);}let O=l.headers.get("x-request-id")??void 0;if(e.expectNoContent&&l.status===204)return;if(!l.ok){let c=await J(l);throw q({status:l.status,code:c?.error??`HTTP_${l.status}`,message:c?.message??l.statusText??"Request failed",details:c?.details,requestId:O})}return l.status===204?void 0:await l.json()}async requestIdempotent(e,t){let s=t?.idempotencyKey??Y(),n={...e,idempotencyKey:s,signal:t?.signal,timeout:t?.timeout};return t?.queueIfReconnecting?this.enqueueReplay(n,t.queueMaxMs??Q):this.request(n)}enqueueReplay(e,t){return new Promise((s,n)=>{this.replayQueue.push({run:()=>this.request(e),resolve:s,reject:n,deadline:Date.now()+t}),this.drainReplayQueue();})}async drainReplayQueue(){if(!this.replayDraining){this.replayDraining=true;try{for(;this.replayQueue.length>0;){let e=this.replayQueue[0];if(Date.now()>=e.deadline){e.reject(new d({status:0,code:"QUEUE_TIMEOUT",message:"Queued request expired before connectivity returned"})),this.replayQueue.shift();continue}let t=0;for(;;)try{e.resolve(await e.run()),this.replayQueue.shift();break}catch(s){let n=s instanceof a&&s.transient,i=e.deadline-Date.now();if(!n||i<=0){e.reject(s),this.replayQueue.shift();break}let o=N[Math.min(t,N.length-1)];t+=1,await G(Math.min(o,i));}}}finally{this.replayDraining=false;}}}requestPlain(e,t){return this.request({...e,signal:t?.signal,timeout:t?.timeout})}registerKeptSession(e,t){this.keptCreds.set(e,t);}unregisterKeptSession(e){this.keptCreds.delete(e);}keptSessionIds(){return [...this.keptCreds.keys()]}async rearm(e){let t=this.keptCreds.get(e);if(!t)throw new a({status:0,code:"NO_KEPT_CREDENTIALS",message:`No kept credentials for account ${e}; call sessions.keepAlive first.`});this.onRearm?.(e),await this.requestIdempotent({method:"POST",path:"/v1/sessions",body:t});}async rearmAll(){await Promise.all([...this.keptCreds.keys()].map(e=>this.rearm(e).catch(()=>{})));}};function W(r){return r.endsWith("/")?r.slice(0,-1):r}async function J(r){try{let e=await r.text();if(!e)return null;try{return JSON.parse(e)}catch{return {error:"PARSE_ERROR",message:e}}}catch{return null}}function Y(){let r=globalThis.crypto;return r&&typeof r.randomUUID=="function"?r.randomUUID():z()}function z(){let r=new Uint8Array(16);for(let t=0;t<16;t++)r[t]=Math.floor(Math.random()*256);r[6]=r[6]&15|64,r[8]=r[8]&63|128;let e=Array.from(r,t=>t.toString(16).padStart(2,"0")).join("");return `${e.slice(0,8)}-${e.slice(8,12)}-${e.slice(12,16)}-${e.slice(16,20)}-${e.slice(20)}`}
|
|
2
2
|
export{C as Tickerall,a as TickerallApiError,h as TickerallAuthError,T as TickerallBrokerError,y as TickerallForbiddenError,f as TickerallNotFoundError,d as TickerallServiceUnavailableError,S as TickerallStream,g as TickerallValidationError};//# sourceMappingURL=index.mjs.map
|
|
3
3
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/namespaces/sessions.ts","../src/namespaces/accounts.ts","../src/namespaces/orders.ts","../src/namespaces/positions.ts","../src/namespaces/stream.ts","../src/namespaces/candles.ts","../src/namespaces/history.ts","../src/client.ts"],"names":["TickerallApiError","init","TickerallAuthError","TickerallForbiddenError","TickerallValidationError","TickerallNotFoundError","TickerallBrokerError","TickerallServiceUnavailableError","BROKER_CODES","mapErrorResponse","SessionsNamespace","client","params","options","result","accountId","pending","kept","rearmed","p","AccountsNamespace","OrdersNamespace","query","ticket","PositionsNamespace","HEARTBEAT_INTERVAL_MS","HEARTBEAT_TIMEOUT_MS","RECONNECT_DELAYS","RECONNECT_MAX_MS","POSITION_PHASE_MAP","TickerallStream","EventEmitter","url","apiKey","userAgent","event","listener","cb","WebSocket","timeoutMs","resolve","reject","timer","onOpen","ws","settled","wasReconnect","onMessage","data","frame","err","onError","onClose","code","reason","reasonStr","r","_reason","idx","base","jitter","delay","attempt","channels","sub","symbols","key","subKey","existing","s","topic","StreamNamespace","config","stream","CandlesNamespace","toQueryTime","v","HistoryNamespace","qs","DEFAULT_BASE_URL","DEFAULT_STREAM_URL","DEFAULT_TIMEOUT_MS","SDK_VERSION","DEFAULT_QUEUE_MAX_MS","REPLAY_DELAYS_MS","sleep","ms","Tickerall","trimTrailingSlash","resolvedFetch","isRearmRetry","headers","controller","timedOut","response","requestId","body","safeReadErrorBody","generateIdempotencyKey","full","maxMs","job","isTransient","remaining","creds","id","text","c","fallbackUuid","bytes","i","hex","b"],"mappings":"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","file":"index.mjs","sourcesContent":["export interface TickerallErrorInit {\n status: number\n code: string\n message: string\n requestId?: string\n details?: unknown\n /**\n * Transient = the request failed because TickerAll was momentarily\n * unreachable (network blip, deploy, restart) rather than because the\n * request itself was bad. Safe to retry. Set automatically for\n * `TickerallServiceUnavailableError`; `false` for every other error.\n */\n transient?: boolean\n}\n\nexport class TickerallApiError extends Error {\n readonly status: number\n readonly code: string\n readonly requestId?: string\n readonly details?: unknown\n /**\n * `true` when the failure is a momentary connectivity issue that is safe\n * to retry (see {@link TickerallServiceUnavailableError}). `false` for\n * application errors (auth, validation, broker rejection, …) that won't\n * change on retry. Use it to decide whether to back off and try again.\n */\n readonly transient: boolean\n\n constructor(init: TickerallErrorInit) {\n super(init.message)\n this.name = 'TickerallApiError'\n this.status = init.status\n this.code = init.code\n this.requestId = init.requestId\n this.details = init.details\n this.transient = init.transient ?? false\n }\n}\n\nexport class TickerallAuthError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallAuthError'\n }\n}\n\nexport class TickerallForbiddenError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallForbiddenError'\n }\n}\n\nexport class TickerallValidationError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallValidationError'\n }\n}\n\nexport class TickerallNotFoundError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallNotFoundError'\n }\n}\n\nexport class TickerallBrokerError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallBrokerError'\n }\n}\n\n/**\n * TickerAll was momentarily unreachable — a network blip, a deploy, or the\n * service restarting. This is NOT your fault and NOT a broker rejection: the\n * request never reached a verdict, so it's safe to retry. `transient` is\n * always `true`.\n *\n * The SDK throws this for network failures, request timeouts, and bare\n * 502/503s (and `POOL_SHUTTING_DOWN`). By default a trade fails fast with\n * this error so you can re-decide with fresh prices; pass\n * `{ queueIfReconnecting: true }` to instead queue the call and replay it\n * (with its stable idempotency key, so it can't double-execute) once\n * connectivity returns.\n */\nexport class TickerallServiceUnavailableError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super({ ...init, transient: true })\n this.name = 'TickerallServiceUnavailableError'\n }\n}\n\nconst BROKER_CODES = new Set([\n 'BROKER_REJECTED',\n 'BROKER_AUTH_FAILED',\n 'BROKER_UNREACHABLE',\n 'BROKER_ACCOUNT_NOT_HOT',\n 'BROKER_ACCOUNT_ALREADY_LINKED',\n 'BROKER_ACCOUNT_NOT_FOUND',\n 'TICKET_NOT_FOUND',\n])\n\nexport function mapErrorResponse(init: TickerallErrorInit): TickerallApiError {\n // The pool draining for a deploy/restart is the canonical transient case —\n // a retry lands on the fresh instance, so surface it as service-unavailable\n // (retryable) rather than a broker error.\n if (init.code === 'POOL_SHUTTING_DOWN') return new TickerallServiceUnavailableError(init)\n if (BROKER_CODES.has(init.code)) return new TickerallBrokerError(init)\n if (init.status === 401) return new TickerallAuthError(init)\n if (init.status === 403) return new TickerallForbiddenError(init)\n if (init.status === 404) return new TickerallNotFoundError(init)\n if (init.status === 400 || init.status === 422) return new TickerallValidationError(init)\n // A bare 502/503 with no recognised broker code is the proxy/load-balancer\n // reporting TickerAll itself as momentarily down (e.g. mid-deploy) — that's\n // transient and retryable. Broker-coded 5xx were already caught above.\n if (init.status === 503 || init.status === 502) return new TickerallServiceUnavailableError(init)\n return new TickerallApiError(init)\n}\n","import type { Tickerall } from '../client'\nimport type {\n IdempotentRequestOptions,\n PendingRearmAccount,\n RequestOptions,\n SessionStartParams,\n SessionStartResult,\n} from '../types'\n\nexport class SessionsNamespace {\n constructor(private readonly client: Tickerall) {}\n\n start(params: SessionStartParams, options?: IdempotentRequestOptions): Promise<SessionStartResult> {\n return this.client.requestIdempotent<SessionStartResult>(\n { method: 'POST', path: '/v1/sessions', body: params },\n options,\n )\n }\n\n /**\n * Start a session AND keep it alive: the broker credentials are cached in\n * this process's memory (never persisted) so the client transparently\n * re-arms the account if it later goes cold — e.g. after an atlas restart.\n * Pair with an always-hot account for a connection that stays up with no\n * manual reconnect. Call {@link stopKeepAlive} (or {@link end}) to forget\n * the credentials.\n */\n async keepAlive(params: SessionStartParams, options?: IdempotentRequestOptions): Promise<SessionStartResult> {\n const result = await this.start(params, options)\n this.client.registerKeptSession(result.accountId, params)\n return result\n }\n\n /** Stop auto-re-arming an account and drop its cached credentials. */\n stopKeepAlive(accountId: string): void {\n this.client.unregisterKeptSession(accountId)\n }\n\n /**\n * Manually re-arm a kept account now (a fresh session.start with the cached\n * credentials). Normally unnecessary — the client re-arms on demand — but\n * useful to proactively recover accounts listed by `GET /v1/always-hot/pending`.\n */\n rearm(accountId: string): Promise<void> {\n return this.client.rearm(accountId)\n }\n\n /**\n * Always-hot accounts that currently have no live connection — they need a\n * credentials refresh (e.g. after a TickerAll restart). Poll this after a\n * suspected outage; the next call or stream reconnect also re-arms them\n * automatically.\n */\n async pendingRearm(options?: RequestOptions): Promise<PendingRearmAccount[]> {\n const res = await this.client.requestPlain<{ pending: PendingRearmAccount[] }>(\n { method: 'GET', path: '/v1/always-hot/pending' },\n options,\n )\n return res.pending\n }\n\n /**\n * Re-arm every pending account we hold kept credentials for (the ones we\n * actually can recover). Returns the account IDs that were re-armed.\n */\n async rearmPending(options?: RequestOptions): Promise<string[]> {\n const pending = await this.pendingRearm(options)\n const kept = new Set(this.client.keptSessionIds())\n const rearmed: string[] = []\n for (const p of pending) {\n if (!kept.has(p.id)) continue\n await this.client.rearm(p.id).catch(() => { /* best-effort */ })\n rearmed.push(p.id)\n }\n return rearmed\n }\n\n end(accountId: string, options?: RequestOptions): Promise<void> {\n // Ending a session also stops keeping it alive.\n this.client.unregisterKeptSession(accountId)\n return this.client.requestPlain<void>(\n {\n method: 'DELETE',\n path: `/v1/sessions/${encodeURIComponent(accountId)}`,\n expectNoContent: true,\n },\n options,\n )\n }\n}\n","import type { Tickerall } from '../client'\nimport type {\n AccountDetail,\n AccountListing,\n RequestOptions,\n SymbolSpec,\n SymbolSpecsResponse,\n SymbolsResponse,\n} from '../types'\n\nexport class AccountsNamespace {\n constructor(private readonly client: Tickerall) {}\n\n list(options?: RequestOptions): Promise<AccountListing[]> {\n return this.client.requestPlain<AccountListing[]>(\n { method: 'GET', path: '/v1/accounts' },\n options,\n )\n }\n\n get(accountId: string, options?: RequestOptions): Promise<AccountDetail> {\n return this.client.requestPlain<AccountDetail>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}`, accountId },\n options,\n )\n }\n\n async symbols(accountId: string, options?: RequestOptions): Promise<string[]> {\n const res = await this.client.requestPlain<SymbolsResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/symbols`, accountId },\n options,\n )\n return res.symbols\n }\n\n /**\n * Per-symbol volume specs (min / max / step) for this account's tradeable\n * symbols — use these to check an order volume before placing it. Each spec\n * carries `specSource`: `'broker'` (the broker pushed it, authoritative) or\n * `'derived'` (filled from category defaults — best-effort). MT5 only; an\n * MT4 account returns an empty list.\n */\n async symbolSpecs(accountId: string, options?: RequestOptions): Promise<SymbolSpec[]> {\n const res = await this.client.requestPlain<SymbolSpecsResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/symbol-specs`, accountId },\n options,\n )\n return res.specs\n }\n}\n","import type { Tickerall } from '../client'\nimport type {\n CancelPendingResult,\n IdempotentRequestOptions,\n ListPendingParams,\n ModifyPendingParams,\n ModifyPendingResult,\n PendingOrder,\n PendingOrdersResponse,\n PlaceOrderParams,\n PlaceOrderResult,\n RequestOptions,\n} from '../types'\n\nexport class OrdersNamespace {\n constructor(private readonly client: Tickerall) {}\n\n place(\n accountId: string,\n params: PlaceOrderParams,\n options?: IdempotentRequestOptions,\n ): Promise<PlaceOrderResult> {\n return this.client.requestIdempotent<PlaceOrderResult>(\n {\n method: 'POST',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders`,\n body: params,\n accountId,\n },\n options,\n )\n }\n\n /**\n * List the account's resting pending orders (LIMIT / STOP). MT5 only — an\n * MT4 account returns an empty list. `waitMs` lets a just-warmed connection's\n * pending snapshot settle; pass 0 on a hot poller to skip the wait.\n */\n async listPending(\n accountId: string,\n params: ListPendingParams = {},\n options?: RequestOptions,\n ): Promise<PendingOrder[]> {\n const query = params.waitMs !== undefined ? `?waitMs=${encodeURIComponent(String(params.waitMs))}` : ''\n const res = await this.client.requestPlain<PendingOrdersResponse>(\n {\n method: 'GET',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders/pending${query}`,\n accountId,\n },\n options,\n )\n return res.orders\n }\n\n /**\n * Cancel a resting pending order by its ticket. MT5 only.\n */\n cancelPending(\n accountId: string,\n ticket: number,\n options?: IdempotentRequestOptions,\n ): Promise<CancelPendingResult> {\n return this.client.requestIdempotent<CancelPendingResult>(\n {\n method: 'DELETE',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders/${ticket}`,\n accountId,\n },\n options,\n )\n }\n\n /**\n * Modify a resting pending order's trigger price / SL / TP. Any field you\n * omit is preserved at its current value. Provide at least one. MT5 only.\n */\n modifyPending(\n accountId: string,\n ticket: number,\n params: ModifyPendingParams,\n options?: IdempotentRequestOptions,\n ): Promise<ModifyPendingResult> {\n return this.client.requestIdempotent<ModifyPendingResult>(\n {\n method: 'PATCH',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders/${ticket}`,\n body: params,\n accountId,\n },\n options,\n )\n }\n}\n","import type { Tickerall } from '../client'\nimport type {\n ClosePositionParams,\n ClosePositionResult,\n IdempotentRequestOptions,\n ModifyPositionParams,\n ModifyPositionResult,\n} from '../types'\n\nexport class PositionsNamespace {\n constructor(private readonly client: Tickerall) {}\n\n close(\n accountId: string,\n ticket: number,\n params: ClosePositionParams = {},\n options?: IdempotentRequestOptions,\n ): Promise<ClosePositionResult> {\n return this.client.requestIdempotent<ClosePositionResult>(\n {\n method: 'DELETE',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/positions/${ticket}`,\n body: params,\n accountId,\n },\n options,\n )\n }\n\n modify(\n accountId: string,\n ticket: number,\n params: ModifyPositionParams,\n options?: IdempotentRequestOptions,\n ): Promise<ModifyPositionResult> {\n return this.client.requestIdempotent<ModifyPositionResult>(\n {\n method: 'PATCH',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/positions/${ticket}`,\n body: params,\n accountId,\n },\n options,\n )\n }\n}\n","import { EventEmitter } from 'node:events'\nimport WebSocket from 'ws'\nimport type { Tickerall } from '../client'\nimport type {\n AccountEvent,\n PositionEvent,\n StreamCloseEvent,\n StreamErrorEvent,\n StreamReconnectEvent,\n StreamState,\n TickEvent,\n} from '../types'\n\nexport interface StreamConfig {\n streamUrl: string\n apiKey: string\n userAgent: string\n}\n\nexport interface StreamConnectOptions {\n signal?: AbortSignal\n}\n\nconst HEARTBEAT_INTERVAL_MS = 25_000\nconst HEARTBEAT_TIMEOUT_MS = 10_000\nconst RECONNECT_DELAYS = [1_000, 2_000, 4_000, 8_000, 16_000, 30_000]\nconst RECONNECT_MAX_MS = 30_000\n\ninterface TickSubscription {\n kind: 'ticks'\n accountId: string\n symbols: Set<string>\n}\n\ninterface AccountTopicSubscription {\n kind: 'positions' | 'account'\n accountId: string\n}\n\ntype Subscription = TickSubscription | AccountTopicSubscription\n\n// Subscription channels — the server subscribes by `{ kind, accountId, ... }`\n// wrapped in a `channels` array (see the server's ws/protocol).\ntype ChannelFrame =\n | { kind: 'ticks'; accountId: string; symbols: string[] }\n | { kind: 'positions'; accountId: string }\n | { kind: 'account'; accountId: string }\n\ninterface SubscribeFrame {\n type: 'subscribe'\n channels: ChannelFrame[]\n correlationId?: string\n}\n\ninterface UnsubscribeFrame {\n type: 'unsubscribe'\n channels: ChannelFrame[]\n correlationId?: string\n}\n\ntype ClientFrame = SubscribeFrame | UnsubscribeFrame | { type: 'ping' }\n\ninterface IncomingTick {\n type: 'tick'\n accountId: string\n symbol: string\n bid: number\n ask: number\n ordinal?: number\n subtype?: number\n timestamp: string\n}\n\n// The server emits position events as `position_update` with an\n// opened/updated/closed phase, and account events as `account_update`.\ninterface IncomingPositionUpdate {\n type: 'position_update'\n accountId: string\n event: 'opened' | 'updated' | 'closed'\n position: PositionEvent['position']\n}\n\ninterface IncomingAccountUpdate {\n type: 'account_update'\n accountId: string\n snapshot: AccountEvent['snapshot']\n}\n\ninterface IncomingPong {\n type: 'pong'\n ts?: number\n}\n\ninterface IncomingSubscribed {\n type: 'subscribed'\n channels: unknown[]\n rejected: Array<{ channel: unknown; reason: string; code: string }>\n correlationId?: string\n}\n\ninterface IncomingError {\n type: 'error'\n code: string\n message: string\n correlationId?: string\n}\n\ntype IncomingFrame =\n | IncomingTick\n | IncomingPositionUpdate\n | IncomingAccountUpdate\n | IncomingPong\n | IncomingSubscribed\n | IncomingError\n\nconst POSITION_PHASE_MAP: Record<string, PositionEvent['event']> = {\n opened: 'position-opened',\n updated: 'position-updated',\n closed: 'position-closed',\n}\n\nexport interface TickerallStreamEvents {\n tick: (e: TickEvent) => void\n position: (e: PositionEvent) => void\n account: (e: AccountEvent) => void\n error: (e: StreamErrorEvent) => void\n close: (e: StreamCloseEvent) => void\n reconnect: (e: StreamReconnectEvent) => void\n open: () => void\n}\n\nexport class TickerallStream extends EventEmitter {\n private ws: WebSocket | null = null\n private closedByUser = false\n private state: StreamState = 'closed'\n private beforeResubscribe?: () => Promise<void>\n private reconnectAttempts = 0\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null\n private heartbeatTimeoutTimer: ReturnType<typeof setTimeout> | null = null\n private readonly subs: Map<string, Subscription> = new Map()\n private readonly url: string\n private readonly headers: Record<string, string>\n\n constructor(url: string, apiKey: string, userAgent: string) {\n super()\n this.url = url\n this.headers = {\n 'Authorization': `Bearer ${apiKey}`,\n 'User-Agent': userAgent,\n }\n // Swallow `error` events that have no listener; the SDK reports errors\n // via the `error` event and via promise rejection on `connect()`, so a\n // missing listener should not crash the process.\n this.on('error', () => { /* noop default */ })\n }\n\n override on<E extends keyof TickerallStreamEvents>(event: E, listener: TickerallStreamEvents[E]): this {\n return super.on(event, listener as (...args: unknown[]) => void)\n }\n\n override once<E extends keyof TickerallStreamEvents>(event: E, listener: TickerallStreamEvents[E]): this {\n return super.once(event, listener as (...args: unknown[]) => void)\n }\n\n override off<E extends keyof TickerallStreamEvents>(event: E, listener: TickerallStreamEvents[E]): this {\n return super.off(event, listener as (...args: unknown[]) => void)\n }\n\n async connect(): Promise<void> {\n this.closedByUser = false\n this.state = 'connecting'\n await this.openOnce()\n }\n\n /**\n * Internal: callback run after a RECONNECT (not the initial connect), before\n * subscriptions are re-sent. The SDK wires this to re-arm kept sessions so a\n * connection transparently survives an atlas restart.\n */\n setBeforeResubscribe(cb: () => Promise<void>): void {\n this.beforeResubscribe = cb\n }\n\n /**\n * Current connection state. `'open'` means live; `'reconnecting'` means the\n * SDK is silently re-establishing the link (idle apps need do nothing).\n * Queryable any time — never thrown at you.\n */\n getState(): StreamState {\n return this.state\n }\n\n /** `true` only when the stream is live and ready to receive. */\n isConnected(): boolean {\n return this.state === 'open' && this.ws?.readyState === WebSocket.OPEN\n }\n\n /**\n * Resolve once the stream is live (immediately if already open), or reject\n * after `timeoutMs`. Rejects right away if the stream was closed by the\n * caller. Handy to gate logic on a confirmed connection without polling.\n */\n waitUntilConnected(timeoutMs = 30_000): Promise<void> {\n if (this.isConnected()) return Promise.resolve()\n if (this.state === 'closed') return Promise.reject(new Error('Stream is closed'))\n return new Promise<void>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout>\n const onOpen = (): void => {\n clearTimeout(timer)\n resolve()\n }\n timer = setTimeout(() => {\n this.off('open', onOpen)\n reject(new Error(`waitUntilConnected: timed out after ${timeoutMs}ms`))\n }, timeoutMs)\n this.once('open', onOpen)\n })\n }\n\n private openOnce(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const ws = new WebSocket(this.url, { headers: this.headers })\n this.ws = ws\n let settled = false\n\n const onOpen = async (): Promise<void> => {\n if (settled) return\n settled = true\n const wasReconnect = this.reconnectAttempts > 0\n this.state = 'open'\n this.reconnectAttempts = 0\n this.startHeartbeat()\n // After a RECONNECT (atlas may have restarted and lost the broker\n // session), re-arm kept sessions BEFORE resubscribing so the account\n // is hot again on atlas. Skipped on the initial connect.\n if (wasReconnect && this.beforeResubscribe) {\n try { await this.beforeResubscribe() } catch { /* best-effort */ }\n }\n this.resendSubscriptions()\n this.emit('open')\n resolve()\n }\n\n const onMessage = (data: WebSocket.RawData): void => {\n try {\n const frame = JSON.parse(data.toString()) as IncomingFrame\n this.handleFrame(frame)\n } catch (err) {\n this.emit('error', { message: 'Failed to parse server frame', cause: err })\n }\n }\n\n const onError = (err: Error): void => {\n if (!settled) {\n settled = true\n reject(err)\n }\n this.emit('error', { message: err.message, cause: err })\n }\n\n const onClose = (code: number, reason: Buffer): void => {\n this.stopHeartbeat()\n this.ws = null\n const reasonStr = reason?.toString() ?? ''\n this.emit('close', { code, reason: reasonStr })\n if (!settled) {\n settled = true\n reject(new Error(`WebSocket closed before open (code=${code})`))\n }\n if (!this.closedByUser) {\n this.state = 'reconnecting'\n this.scheduleReconnect()\n }\n }\n\n ws.on('open', onOpen)\n ws.on('message', onMessage)\n ws.on('error', onError)\n ws.on('close', onClose)\n ws.on('pong', () => this.clearHeartbeatTimeout())\n })\n }\n\n private handleFrame(frame: IncomingFrame): void {\n switch (frame.type) {\n case 'tick':\n this.emit('tick', {\n type: 'tick',\n accountId: frame.accountId,\n symbol: frame.symbol,\n bid: frame.bid,\n ask: frame.ask,\n timestamp: frame.timestamp,\n })\n return\n case 'position_update':\n this.emit('position', {\n type: 'position',\n accountId: frame.accountId,\n event: POSITION_PHASE_MAP[frame.event] ?? 'position-updated',\n position: frame.position,\n })\n return\n case 'account_update':\n this.emit('account', {\n type: 'account',\n accountId: frame.accountId,\n snapshot: frame.snapshot,\n })\n return\n case 'subscribed':\n if (frame.rejected && frame.rejected.length > 0) {\n this.emit('error', {\n message: `Subscribe rejected: ${frame.rejected.map(r => `${r.code} (${r.reason})`).join(', ')}`,\n })\n }\n return\n case 'error':\n this.emit('error', { message: `${frame.code}: ${frame.message}` })\n return\n case 'pong':\n this.clearHeartbeatTimeout()\n return\n }\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat()\n this.heartbeatTimer = setInterval(() => {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return\n this.send({ type: 'ping' })\n try { this.ws.ping() } catch { /* noop */ }\n this.heartbeatTimeoutTimer = setTimeout(() => this.forceReconnect('heartbeat-timeout'), HEARTBEAT_TIMEOUT_MS)\n }, HEARTBEAT_INTERVAL_MS)\n }\n\n private clearHeartbeatTimeout(): void {\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer)\n this.heartbeatTimeoutTimer = null\n }\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) clearInterval(this.heartbeatTimer)\n if (this.heartbeatTimeoutTimer) clearTimeout(this.heartbeatTimeoutTimer)\n this.heartbeatTimer = null\n this.heartbeatTimeoutTimer = null\n }\n\n private forceReconnect(_reason: string): void {\n if (!this.ws) return\n try { this.ws.terminate() } catch { /* noop */ }\n }\n\n private scheduleReconnect(): void {\n if (this.closedByUser) return\n if (this.reconnectTimer) return\n const idx = Math.min(this.reconnectAttempts, RECONNECT_DELAYS.length - 1)\n const base = RECONNECT_DELAYS[idx] ?? RECONNECT_MAX_MS\n const jitter = Math.floor(Math.random() * Math.min(base, 1_000))\n const delay = Math.min(base + jitter, RECONNECT_MAX_MS + 1_000)\n this.reconnectAttempts += 1\n const attempt = this.reconnectAttempts\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null\n this.emit('reconnect', { attempt })\n this.openOnce().catch(err => {\n this.emit('error', { message: 'Reconnect failed', cause: err })\n this.scheduleReconnect()\n })\n }, delay)\n }\n\n private resendSubscriptions(): void {\n const channels: ChannelFrame[] = []\n for (const sub of this.subs.values()) {\n if (sub.kind === 'ticks') {\n channels.push({ kind: 'ticks', accountId: sub.accountId, symbols: [...sub.symbols] })\n } else {\n channels.push({ kind: sub.kind, accountId: sub.accountId })\n }\n }\n if (channels.length > 0) this.send({ type: 'subscribe', channels })\n }\n\n private send(frame: ClientFrame): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return\n try {\n this.ws.send(JSON.stringify(frame))\n } catch (err) {\n this.emit('error', { message: 'Failed to send frame', cause: err })\n }\n }\n\n async subscribeTicks(accountId: string, symbols: string[]): Promise<void> {\n const key = subKey('ticks', accountId)\n const existing = this.subs.get(key)\n if (existing && existing.kind === 'ticks') {\n for (const s of symbols) existing.symbols.add(s)\n } else {\n this.subs.set(key, { kind: 'ticks', accountId, symbols: new Set(symbols) })\n }\n this.send({ type: 'subscribe', channels: [{ kind: 'ticks', accountId, symbols }] })\n }\n\n async unsubscribeTicks(accountId: string, symbols: string[]): Promise<void> {\n const key = subKey('ticks', accountId)\n const existing = this.subs.get(key)\n if (existing && existing.kind === 'ticks') {\n for (const s of symbols) existing.symbols.delete(s)\n if (existing.symbols.size === 0) this.subs.delete(key)\n }\n this.send({ type: 'unsubscribe', channels: [{ kind: 'ticks', accountId, symbols }] })\n }\n\n async subscribePositions(accountId: string): Promise<void> {\n this.subs.set(subKey('positions', accountId), { kind: 'positions', accountId })\n this.send({ type: 'subscribe', channels: [{ kind: 'positions', accountId }] })\n }\n\n async subscribeAccount(accountId: string): Promise<void> {\n this.subs.set(subKey('account', accountId), { kind: 'account', accountId })\n this.send({ type: 'subscribe', channels: [{ kind: 'account', accountId }] })\n }\n\n async close(): Promise<void> {\n this.closedByUser = true\n this.state = 'closed'\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n this.stopHeartbeat()\n const ws = this.ws\n if (!ws) return\n if (ws.readyState === WebSocket.CLOSED) return\n return new Promise<void>(resolve => {\n const onClose = (): void => resolve()\n ws.once('close', onClose)\n try { ws.close() } catch { resolve() }\n })\n }\n}\n\nfunction subKey(topic: 'ticks' | 'positions' | 'account', accountId: string): string {\n return `${topic}:${accountId}`\n}\n\nexport class StreamNamespace {\n private readonly client: Tickerall\n private readonly streamUrl: string\n private readonly apiKey: string\n private readonly userAgent: string\n\n constructor(client: Tickerall, config: StreamConfig) {\n this.client = client\n this.streamUrl = config.streamUrl\n this.apiKey = config.apiKey\n this.userAgent = config.userAgent\n }\n\n async connect(): Promise<TickerallStream> {\n const stream = new TickerallStream(this.streamUrl, this.apiKey, this.userAgent)\n // On reconnect (atlas may have restarted), re-arm kept sessions before the\n // stream resubscribes, so subscriptions resume against a hot account.\n stream.setBeforeResubscribe(() => this.client.rearmAll())\n await stream.connect()\n return stream\n }\n}\n","import type { Tickerall } from '../client'\nimport type { Candle, CandlesParams, CandlesResponse, RequestOptions } from '../types'\n\nexport class CandlesNamespace {\n constructor(private readonly client: Tickerall) {}\n\n /**\n * Fetch historical OHLC candles for a symbol from one of your broker\n * accounts.\n *\n * Candles are read from the account's own live broker connection, so pass\n * the `accountId` of a connected account. Coarser timeframes reach further\n * back; a single request returns as much history as fits in a few seconds,\n * so pass a large `hours` and take what comes back. Deep look-backs are\n * served on an isolated history connection and won't disturb your live tick\n * stream.\n *\n * @example\n * const bars = await client.candles.get(accountId, { symbol: 'BTCUSDm', hours: 8760, timeframe: 'D1' })\n */\n async get(accountId: string, params: CandlesParams, options?: RequestOptions): Promise<Candle[]> {\n const query = new URLSearchParams({ symbol: params.symbol, hours: String(params.hours) })\n if (params.timeframe) query.set('timeframe', params.timeframe)\n const res = await this.client.requestPlain<CandlesResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/candles?${query.toString()}` },\n options,\n )\n return res.candles\n }\n}\n","import type { Tickerall } from '../client'\nimport type { HistoryParams, HistoryResponse, HistoryTrade, RequestOptions } from '../types'\n\nfunction toQueryTime(v: string | number | Date): string {\n return v instanceof Date ? v.toISOString() : String(v)\n}\n\nexport class HistoryNamespace {\n constructor(private readonly client: Tickerall) {}\n\n /**\n * Closed-trade history for one of your broker accounts — executed deals\n * paired into round-trips, read from the account's own live broker\n * connection (the equivalent of MT5's history_deals_get for the recent\n * window).\n *\n * `symbol`/`from`/`to`/`limit` FILTER the broker's recent deal log (a few\n * weeks deep, broker-controlled) plus any closes seen live this session —\n * they don't fetch deeper than the broker's window. Pass the `accountId` of\n * a connected account.\n *\n * @example\n * const trades = await client.history.get(accountId, { symbol: 'BTCUSDm', limit: 100 })\n */\n async get(accountId: string, params: HistoryParams = {}, options?: RequestOptions): Promise<HistoryTrade[]> {\n const query = new URLSearchParams()\n if (params.symbol) query.set('symbol', params.symbol)\n if (params.from !== undefined) query.set('from', toQueryTime(params.from))\n if (params.to !== undefined) query.set('to', toQueryTime(params.to))\n if (params.limit !== undefined) query.set('limit', String(params.limit))\n if (params.waitMs !== undefined) query.set('waitMs', String(params.waitMs))\n const qs = query.toString()\n const res = await this.client.requestPlain<HistoryResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/history${qs ? `?${qs}` : ''}` },\n options,\n )\n return res.trades\n }\n}\n","import { mapErrorResponse, TickerallApiError, TickerallServiceUnavailableError } from './errors'\nimport { SessionsNamespace } from './namespaces/sessions'\nimport { AccountsNamespace } from './namespaces/accounts'\nimport { OrdersNamespace } from './namespaces/orders'\nimport { PositionsNamespace } from './namespaces/positions'\nimport { StreamNamespace } from './namespaces/stream'\nimport { CandlesNamespace } from './namespaces/candles'\nimport { HistoryNamespace } from './namespaces/history'\nimport type {\n ErrorBody,\n FetchLike,\n IdempotentRequestOptions,\n RequestOptions,\n SessionStartParams,\n SessionStartResult,\n TickerallClientConfig,\n} from './types'\n\nconst DEFAULT_BASE_URL = 'https://api.tickerall.com'\nconst DEFAULT_STREAM_URL = 'wss://api.tickerall.com/v1/stream'\nconst DEFAULT_TIMEOUT_MS = 30_000\nconst SDK_VERSION = '0.1.2'\n\n// Default ceiling on how long a `queueIfReconnecting` call waits across\n// replays before giving up. Bounded on purpose — a queued trade that finally\n// fires minutes late is rarely what the caller wanted.\nconst DEFAULT_QUEUE_MAX_MS = 60_000\n// Backoff between replay attempts for a queued request (ms). Each value is\n// also clamped to the remaining time before the call's deadline.\nconst REPLAY_DELAYS_MS = [500, 1_000, 2_000, 4_000, 8_000]\n\ninterface ReplayJob {\n run: () => Promise<unknown>\n resolve: (value: unknown) => void\n reject: (err: unknown) => void\n deadline: number\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/** @internal */\nexport interface InternalRequestInit {\n method: 'GET' | 'POST' | 'DELETE' | 'PATCH' | 'PUT'\n path: string\n body?: unknown\n idempotencyKey?: string\n signal?: AbortSignal\n timeout?: number\n expectNoContent?: boolean\n // The broker account this request targets, if any. Set by account-scoped\n // namespace methods so the client can transparently re-arm a kept session\n // (re-supply credentials) when the account has gone cold, then retry.\n accountId?: string\n}\n\nexport class Tickerall {\n readonly sessions: SessionsNamespace\n readonly accounts: AccountsNamespace\n readonly orders: OrdersNamespace\n readonly positions: PositionsNamespace\n readonly stream: StreamNamespace\n readonly candles: CandlesNamespace\n readonly history: HistoryNamespace\n\n private readonly apiKey: string\n private readonly baseUrl: string\n private readonly streamUrl: string\n private readonly timeout: number\n private readonly fetchImpl: FetchLike\n private readonly userAgent: string\n\n // In-order replay queue for `queueIfReconnecting` calls. Only opted-in\n // requests ever enter it; everything else bypasses it entirely.\n private readonly replayQueue: ReplayJob[] = []\n private replayDraining = false\n\n // Kept-session credentials — RAM only, NEVER persisted. The broker creds for\n // sessions the customer asked us to keep alive (sessions.keepAlive), so the\n // client can transparently re-arm them when atlas reports the account cold\n // (e.g. after an atlas restart dropped its server-side credentials).\n private readonly keptCreds = new Map<string, SessionStartParams>()\n private readonly onRearm?: (accountId: string) => void\n\n constructor(config: TickerallClientConfig) {\n if (!config || !config.apiKey) {\n throw new TypeError('Tickerall: `apiKey` is required.')\n }\n this.apiKey = config.apiKey\n this.baseUrl = trimTrailingSlash(config.baseUrl ?? DEFAULT_BASE_URL)\n this.streamUrl = config.streamUrl ?? DEFAULT_STREAM_URL\n this.timeout = config.timeout ?? DEFAULT_TIMEOUT_MS\n const resolvedFetch = config.fetch ?? globalThis.fetch\n if (typeof resolvedFetch !== 'function') {\n throw new TypeError('Tickerall: no `fetch` available — pass `fetch` in the config (Node <18 needs an explicit fetch).')\n }\n this.fetchImpl = resolvedFetch.bind(globalThis)\n this.userAgent = config.userAgent\n ? `${config.userAgent} tickerall-js/${SDK_VERSION}`\n : `tickerall-js/${SDK_VERSION}`\n this.onRearm = config.onRearm\n\n this.sessions = new SessionsNamespace(this)\n this.accounts = new AccountsNamespace(this)\n this.orders = new OrdersNamespace(this)\n this.positions = new PositionsNamespace(this)\n this.candles = new CandlesNamespace(this)\n this.history = new HistoryNamespace(this)\n this.stream = new StreamNamespace(this, {\n streamUrl: this.streamUrl,\n apiKey: this.apiKey,\n userAgent: this.userAgent,\n })\n }\n\n // Public entry — runs the request, transparently re-arming a kept session\n // and retrying ONCE if the account has gone cold.\n /** @internal */\n request<T>(init: InternalRequestInit): Promise<T> {\n return this.requestWithRearm<T>(init, false)\n }\n\n private async requestWithRearm<T>(init: InternalRequestInit, isRearmRetry: boolean): Promise<T> {\n try {\n return await this.requestOnce<T>(init)\n } catch (err) {\n // If a kept session's account went cold (e.g. an atlas restart dropped\n // its credentials), refresh them and retry the original request once.\n if (\n !isRearmRetry &&\n init.accountId !== undefined &&\n this.keptCreds.has(init.accountId) &&\n err instanceof TickerallApiError &&\n err.code === 'BROKER_ACCOUNT_NOT_HOT'\n ) {\n await this.rearm(init.accountId)\n return this.requestWithRearm<T>(init, true)\n }\n throw err\n }\n }\n\n private async requestOnce<T>(init: InternalRequestInit): Promise<T> {\n const url = `${this.baseUrl}${init.path}`\n const headers: Record<string, string> = {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'User-Agent': this.userAgent,\n 'Accept': 'application/json',\n }\n if (init.body !== undefined) headers['Content-Type'] = 'application/json'\n if (init.idempotencyKey) headers['Idempotency-Key'] = init.idempotencyKey\n\n const timeoutMs = init.timeout ?? this.timeout\n const controller = new AbortController()\n // Track who aborted: our own timeout is a transient connectivity symptom\n // (retryable), whereas a caller-supplied signal is a deliberate cancel.\n let timedOut = false\n const timer = setTimeout(() => {\n timedOut = true\n controller.abort(new Error(`Request timed out after ${timeoutMs}ms`))\n }, timeoutMs)\n if (init.signal) {\n if (init.signal.aborted) controller.abort(init.signal.reason)\n else init.signal.addEventListener('abort', () => controller.abort(init.signal!.reason), { once: true })\n }\n\n let response: Response\n try {\n response = await this.fetchImpl(url, {\n method: init.method,\n headers,\n body: init.body !== undefined ? JSON.stringify(init.body) : undefined,\n signal: controller.signal,\n })\n } catch (err) {\n clearTimeout(timer)\n if (timedOut) {\n // Timed out waiting for TickerAll — transient, safe to retry.\n throw new TickerallServiceUnavailableError({\n status: 0,\n code: 'REQUEST_TIMEOUT',\n message: `Request timed out after ${timeoutMs}ms`,\n })\n }\n if (controller.signal.aborted) {\n // Caller cancelled via their AbortSignal — deliberate, not transient.\n const reason = (controller.signal.reason as Error | undefined)?.message ?? (err as Error).message ?? 'Request aborted'\n throw new TickerallApiError({\n status: 0,\n code: 'REQUEST_ABORTED',\n message: reason,\n })\n }\n // fetch threw before any response — TickerAll was unreachable. Transient.\n throw new TickerallServiceUnavailableError({\n status: 0,\n code: 'NETWORK_ERROR',\n message: (err as Error).message || 'Network request failed',\n details: err,\n })\n } finally {\n clearTimeout(timer)\n }\n\n const requestId = response.headers.get('x-request-id') ?? undefined\n\n if (init.expectNoContent && response.status === 204) {\n return undefined as T\n }\n\n if (!response.ok) {\n const body = await safeReadErrorBody(response)\n throw mapErrorResponse({\n status: response.status,\n code: body?.error ?? `HTTP_${response.status}`,\n message: body?.message ?? response.statusText ?? 'Request failed',\n details: body?.details,\n requestId,\n })\n }\n\n if (response.status === 204) return undefined as T\n const json = (await response.json()) as T\n return json\n }\n\n /** @internal */\n async requestIdempotent<T>(init: InternalRequestInit, options?: IdempotentRequestOptions): Promise<T> {\n // Fix the idempotency key ONCE so every replay attempt carries the same\n // key — the server then dedupes any attempt that already executed, which\n // is what makes queue-and-replay safe (no double trade).\n const key = options?.idempotencyKey ?? generateIdempotencyKey()\n const full: InternalRequestInit = {\n ...init,\n idempotencyKey: key,\n signal: options?.signal,\n timeout: options?.timeout,\n }\n if (options?.queueIfReconnecting) {\n return this.enqueueReplay<T>(full, options.queueMaxMs ?? DEFAULT_QUEUE_MAX_MS)\n }\n // Default: fail fast. A transient connectivity failure surfaces as\n // TickerallServiceUnavailableError for the caller to re-decide.\n return this.request<T>(full)\n }\n\n // Queue a request for in-order replay, retrying transient failures with\n // backoff until it succeeds or `maxMs` elapses.\n private enqueueReplay<T>(init: InternalRequestInit, maxMs: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n this.replayQueue.push({\n run: () => this.request<unknown>(init),\n resolve: resolve as (value: unknown) => void,\n reject,\n deadline: Date.now() + maxMs,\n })\n void this.drainReplayQueue()\n })\n }\n\n // Serial drain: the head job must settle (resolve, reject, or expire) before\n // the next is attempted, so queued writes replay in submission order.\n private async drainReplayQueue(): Promise<void> {\n if (this.replayDraining) return\n this.replayDraining = true\n try {\n while (this.replayQueue.length > 0) {\n const job = this.replayQueue[0]!\n // Reject up front if this job already expired while head-of-line\n // blocked behind an earlier one riding out a long outage.\n if (Date.now() >= job.deadline) {\n job.reject(new TickerallServiceUnavailableError({\n status: 0,\n code: 'QUEUE_TIMEOUT',\n message: 'Queued request expired before connectivity returned',\n }))\n this.replayQueue.shift()\n continue\n }\n let attempt = 0\n for (;;) {\n try {\n job.resolve(await job.run())\n this.replayQueue.shift()\n break\n } catch (err) {\n const isTransient = err instanceof TickerallApiError && err.transient\n const remaining = job.deadline - Date.now()\n if (!isTransient || remaining <= 0) {\n // Non-transient (bad request, broker rejection, …) never retries;\n // a transient failure past the deadline gives up.\n job.reject(err)\n this.replayQueue.shift()\n break\n }\n const base = REPLAY_DELAYS_MS[Math.min(attempt, REPLAY_DELAYS_MS.length - 1)]!\n attempt += 1\n await sleep(Math.min(base, remaining))\n }\n }\n }\n } finally {\n this.replayDraining = false\n }\n }\n\n /** @internal */\n requestPlain<T>(init: InternalRequestInit, options?: RequestOptions): Promise<T> {\n return this.request<T>({\n ...init,\n signal: options?.signal,\n timeout: options?.timeout,\n })\n }\n\n // ── Kept sessions (auto re-arm) ──────────────────────────────────────────\n // Credentials live in this process's memory only — nothing is persisted.\n\n /** Cache broker creds for an account so the client can auto re-arm it. @internal */\n registerKeptSession(accountId: string, params: SessionStartParams): void {\n this.keptCreds.set(accountId, params)\n }\n\n /** Stop auto-re-arming an account and drop its cached credentials. @internal */\n unregisterKeptSession(accountId: string): void {\n this.keptCreds.delete(accountId)\n }\n\n /** Account IDs currently kept alive (i.e. have cached re-arm credentials). @internal */\n keptSessionIds(): string[] {\n return [...this.keptCreds.keys()]\n }\n\n /**\n * Re-supply credentials for a kept account (a fresh `session.start`) to bring\n * a cold connection back. Throws if the account isn't being kept alive.\n * @internal\n */\n async rearm(accountId: string): Promise<void> {\n const creds = this.keptCreds.get(accountId)\n if (!creds) {\n throw new TickerallApiError({\n status: 0,\n code: 'NO_KEPT_CREDENTIALS',\n message: `No kept credentials for account ${accountId}; call sessions.keepAlive first.`,\n })\n }\n this.onRearm?.(accountId)\n // session.start carries no accountId, so this never recurses into re-arm.\n await this.requestIdempotent<SessionStartResult>({ method: 'POST', path: '/v1/sessions', body: creds })\n }\n\n /**\n * Re-arm every kept session — best-effort (one failure won't block the\n * others). Used after the stream reconnects (atlas may have restarted).\n * @internal\n */\n async rearmAll(): Promise<void> {\n await Promise.all([...this.keptCreds.keys()].map(id => this.rearm(id).catch(() => { /* best-effort */ })))\n }\n}\n\nfunction trimTrailingSlash(s: string): string {\n return s.endsWith('/') ? s.slice(0, -1) : s\n}\n\nasync function safeReadErrorBody(response: Response): Promise<ErrorBody | null> {\n try {\n const text = await response.text()\n if (!text) return null\n try {\n return JSON.parse(text) as ErrorBody\n } catch {\n return { error: 'PARSE_ERROR', message: text }\n }\n } catch {\n return null\n }\n}\n\nexport function generateIdempotencyKey(): string {\n const c: { randomUUID?: () => string } | undefined = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n if (c && typeof c.randomUUID === 'function') return c.randomUUID()\n return fallbackUuid()\n}\n\nfunction fallbackUuid(): string {\n const bytes = new Uint8Array(16)\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256)\n bytes[6] = (bytes[6]! & 0x0f) | 0x40\n bytes[8] = (bytes[8]! & 0x3f) | 0x80\n const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/namespaces/sessions.ts","../src/namespaces/accounts.ts","../src/namespaces/orders.ts","../src/namespaces/positions.ts","../src/namespaces/stream.ts","../src/namespaces/candles.ts","../src/namespaces/history.ts","../src/client.ts"],"names":["TickerallApiError","init","TickerallAuthError","TickerallForbiddenError","TickerallValidationError","TickerallNotFoundError","TickerallBrokerError","TickerallServiceUnavailableError","BROKER_CODES","mapErrorResponse","SessionsNamespace","client","params","options","result","accountId","pending","kept","rearmed","p","AccountsNamespace","OrdersNamespace","query","ticket","PositionsNamespace","HEARTBEAT_INTERVAL_MS","HEARTBEAT_TIMEOUT_MS","RECONNECT_DELAYS","RECONNECT_MAX_MS","POSITION_PHASE_MAP","TickerallStream","EventEmitter","url","apiKey","userAgent","event","listener","cb","WebSocket","timeoutMs","resolve","reject","timer","onOpen","ws","settled","wasReconnect","onMessage","data","frame","err","onError","onClose","code","reason","reasonStr","r","_reason","idx","base","jitter","delay","attempt","channels","sub","symbols","key","subKey","existing","s","topic","StreamNamespace","config","stream","CandlesNamespace","toQueryTime","v","HistoryNamespace","qs","DEFAULT_BASE_URL","DEFAULT_STREAM_URL","DEFAULT_TIMEOUT_MS","SDK_VERSION","DEFAULT_QUEUE_MAX_MS","REPLAY_DELAYS_MS","sleep","ms","Tickerall","trimTrailingSlash","resolvedFetch","isRearmRetry","headers","controller","timedOut","response","requestId","body","safeReadErrorBody","generateIdempotencyKey","full","maxMs","job","isTransient","remaining","creds","id","text","c","fallbackUuid","bytes","i","hex","b"],"mappings":"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","file":"index.mjs","sourcesContent":["export interface TickerallErrorInit {\n status: number\n code: string\n message: string\n requestId?: string\n details?: unknown\n /**\n * Transient = the request failed because TickerAll was momentarily\n * unreachable (network blip, deploy, restart) rather than because the\n * request itself was bad. Safe to retry. Set automatically for\n * `TickerallServiceUnavailableError`; `false` for every other error.\n */\n transient?: boolean\n}\n\nexport class TickerallApiError extends Error {\n readonly status: number\n readonly code: string\n readonly requestId?: string\n readonly details?: unknown\n /**\n * `true` when the failure is a momentary connectivity issue that is safe\n * to retry (see {@link TickerallServiceUnavailableError}). `false` for\n * application errors (auth, validation, broker rejection, …) that won't\n * change on retry. Use it to decide whether to back off and try again.\n */\n readonly transient: boolean\n\n constructor(init: TickerallErrorInit) {\n super(init.message)\n this.name = 'TickerallApiError'\n this.status = init.status\n this.code = init.code\n this.requestId = init.requestId\n this.details = init.details\n this.transient = init.transient ?? false\n }\n}\n\nexport class TickerallAuthError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallAuthError'\n }\n}\n\nexport class TickerallForbiddenError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallForbiddenError'\n }\n}\n\nexport class TickerallValidationError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallValidationError'\n }\n}\n\nexport class TickerallNotFoundError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallNotFoundError'\n }\n}\n\nexport class TickerallBrokerError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super(init)\n this.name = 'TickerallBrokerError'\n }\n}\n\n/**\n * TickerAll was momentarily unreachable — a network blip, a deploy, or the\n * service restarting. This is NOT your fault and NOT a broker rejection: the\n * request never reached a verdict, so it's safe to retry. `transient` is\n * always `true`.\n *\n * The SDK throws this for network failures, request timeouts, and bare\n * 502/503s (and `POOL_SHUTTING_DOWN`). By default a trade fails fast with\n * this error so you can re-decide with fresh prices; pass\n * `{ queueIfReconnecting: true }` to instead queue the call and replay it\n * (with its stable idempotency key, so it can't double-execute) once\n * connectivity returns.\n */\nexport class TickerallServiceUnavailableError extends TickerallApiError {\n constructor(init: TickerallErrorInit) {\n super({ ...init, transient: true })\n this.name = 'TickerallServiceUnavailableError'\n }\n}\n\nconst BROKER_CODES = new Set([\n 'BROKER_REJECTED',\n 'BROKER_AUTH_FAILED',\n 'BROKER_UNREACHABLE',\n 'BROKER_ACCOUNT_NOT_HOT',\n 'BROKER_ACCOUNT_ALREADY_LINKED',\n 'BROKER_ACCOUNT_NOT_FOUND',\n 'TICKET_NOT_FOUND',\n])\n\nexport function mapErrorResponse(init: TickerallErrorInit): TickerallApiError {\n // The pool draining for a deploy/restart is the canonical transient case —\n // a retry lands on the fresh instance, so surface it as service-unavailable\n // (retryable) rather than a broker error.\n if (init.code === 'POOL_SHUTTING_DOWN') return new TickerallServiceUnavailableError(init)\n if (BROKER_CODES.has(init.code)) return new TickerallBrokerError(init)\n if (init.status === 401) return new TickerallAuthError(init)\n if (init.status === 403) return new TickerallForbiddenError(init)\n if (init.status === 404) return new TickerallNotFoundError(init)\n if (init.status === 400 || init.status === 422) return new TickerallValidationError(init)\n // A bare 502/503 with no recognised broker code is the proxy/load-balancer\n // reporting TickerAll itself as momentarily down (e.g. mid-deploy) — that's\n // transient and retryable. Broker-coded 5xx were already caught above.\n if (init.status === 503 || init.status === 502) return new TickerallServiceUnavailableError(init)\n return new TickerallApiError(init)\n}\n","import type { Tickerall } from '../client'\nimport type {\n IdempotentRequestOptions,\n PendingRearmAccount,\n RequestOptions,\n SessionStartParams,\n SessionStartResult,\n} from '../types'\n\nexport class SessionsNamespace {\n constructor(private readonly client: Tickerall) {}\n\n start(params: SessionStartParams, options?: IdempotentRequestOptions): Promise<SessionStartResult> {\n return this.client.requestIdempotent<SessionStartResult>(\n { method: 'POST', path: '/v1/sessions', body: params },\n options,\n )\n }\n\n /**\n * Start a session AND keep it alive: the broker credentials are cached in\n * this process's memory (never persisted) so the client transparently\n * re-arms the account if it later goes cold — e.g. after an atlas restart.\n * Pair with an always-hot account for a connection that stays up with no\n * manual reconnect. Call {@link stopKeepAlive} (or {@link end}) to forget\n * the credentials.\n */\n async keepAlive(params: SessionStartParams, options?: IdempotentRequestOptions): Promise<SessionStartResult> {\n const result = await this.start(params, options)\n this.client.registerKeptSession(result.accountId, params)\n return result\n }\n\n /** Stop auto-re-arming an account and drop its cached credentials. */\n stopKeepAlive(accountId: string): void {\n this.client.unregisterKeptSession(accountId)\n }\n\n /**\n * Manually re-arm a kept account now (a fresh session.start with the cached\n * credentials). Normally unnecessary — the client re-arms on demand — but\n * useful to proactively recover accounts listed by `GET /v1/always-hot/pending`.\n */\n rearm(accountId: string): Promise<void> {\n return this.client.rearm(accountId)\n }\n\n /**\n * Always-hot accounts that currently have no live connection — they need a\n * credentials refresh (e.g. after a TickerAll restart). Poll this after a\n * suspected outage; the next call or stream reconnect also re-arms them\n * automatically.\n */\n async pendingRearm(options?: RequestOptions): Promise<PendingRearmAccount[]> {\n const res = await this.client.requestPlain<{ pending: PendingRearmAccount[] }>(\n { method: 'GET', path: '/v1/always-hot/pending' },\n options,\n )\n return res.pending\n }\n\n /**\n * Re-arm every pending account we hold kept credentials for (the ones we\n * actually can recover). Returns the account IDs that were re-armed.\n */\n async rearmPending(options?: RequestOptions): Promise<string[]> {\n const pending = await this.pendingRearm(options)\n const kept = new Set(this.client.keptSessionIds())\n const rearmed: string[] = []\n for (const p of pending) {\n if (!kept.has(p.id)) continue\n await this.client.rearm(p.id).catch(() => { /* best-effort */ })\n rearmed.push(p.id)\n }\n return rearmed\n }\n\n end(accountId: string, options?: RequestOptions): Promise<void> {\n // Ending a session also stops keeping it alive.\n this.client.unregisterKeptSession(accountId)\n return this.client.requestPlain<void>(\n {\n method: 'DELETE',\n path: `/v1/sessions/${encodeURIComponent(accountId)}`,\n expectNoContent: true,\n },\n options,\n )\n }\n}\n","import type { Tickerall } from '../client'\nimport type {\n AccountDetail,\n AccountListing,\n RequestOptions,\n SymbolSpec,\n SymbolSpecsResponse,\n SymbolsResponse,\n} from '../types'\n\nexport class AccountsNamespace {\n constructor(private readonly client: Tickerall) {}\n\n list(options?: RequestOptions): Promise<AccountListing[]> {\n return this.client.requestPlain<AccountListing[]>(\n { method: 'GET', path: '/v1/accounts' },\n options,\n )\n }\n\n get(accountId: string, options?: RequestOptions): Promise<AccountDetail> {\n return this.client.requestPlain<AccountDetail>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}`, accountId },\n options,\n )\n }\n\n async symbols(accountId: string, options?: RequestOptions): Promise<string[]> {\n const res = await this.client.requestPlain<SymbolsResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/symbols`, accountId },\n options,\n )\n return res.symbols\n }\n\n /**\n * Per-symbol volume specs (min / max / step) for this account's tradeable\n * symbols — use these to check an order volume before placing it. Each spec\n * carries `specSource`: `'broker'` (the broker pushed it, authoritative) or\n * `'derived'` (filled from category defaults — best-effort). MT5 only; an\n * MT4 account returns an empty list.\n */\n async symbolSpecs(accountId: string, options?: RequestOptions): Promise<SymbolSpec[]> {\n const res = await this.client.requestPlain<SymbolSpecsResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/symbol-specs`, accountId },\n options,\n )\n return res.specs\n }\n}\n","import type { Tickerall } from '../client'\nimport type {\n CancelPendingResult,\n IdempotentRequestOptions,\n ListPendingParams,\n ModifyPendingParams,\n ModifyPendingResult,\n PendingOrder,\n PendingOrdersResponse,\n PlaceOrderParams,\n PlaceOrderResult,\n RequestOptions,\n} from '../types'\n\nexport class OrdersNamespace {\n constructor(private readonly client: Tickerall) {}\n\n place(\n accountId: string,\n params: PlaceOrderParams,\n options?: IdempotentRequestOptions,\n ): Promise<PlaceOrderResult> {\n return this.client.requestIdempotent<PlaceOrderResult>(\n {\n method: 'POST',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders`,\n body: params,\n accountId,\n },\n options,\n )\n }\n\n /**\n * List the account's resting pending orders (LIMIT / STOP). MT5 only — an\n * MT4 account returns an empty list. `waitMs` lets a just-warmed connection's\n * pending snapshot settle; pass 0 on a hot poller to skip the wait.\n */\n async listPending(\n accountId: string,\n params: ListPendingParams = {},\n options?: RequestOptions,\n ): Promise<PendingOrder[]> {\n const query = params.waitMs !== undefined ? `?waitMs=${encodeURIComponent(String(params.waitMs))}` : ''\n const res = await this.client.requestPlain<PendingOrdersResponse>(\n {\n method: 'GET',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders/pending${query}`,\n accountId,\n },\n options,\n )\n return res.orders\n }\n\n /**\n * Cancel a resting pending order by its ticket. MT5 only.\n */\n cancelPending(\n accountId: string,\n ticket: number,\n options?: IdempotentRequestOptions,\n ): Promise<CancelPendingResult> {\n return this.client.requestIdempotent<CancelPendingResult>(\n {\n method: 'DELETE',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders/${ticket}`,\n accountId,\n },\n options,\n )\n }\n\n /**\n * Modify a resting pending order's trigger price / SL / TP. Any field you\n * omit is preserved at its current value. Provide at least one. MT5 only.\n */\n modifyPending(\n accountId: string,\n ticket: number,\n params: ModifyPendingParams,\n options?: IdempotentRequestOptions,\n ): Promise<ModifyPendingResult> {\n return this.client.requestIdempotent<ModifyPendingResult>(\n {\n method: 'PATCH',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/orders/${ticket}`,\n body: params,\n accountId,\n },\n options,\n )\n }\n}\n","import type { Tickerall } from '../client'\nimport type {\n ClosePositionParams,\n ClosePositionResult,\n IdempotentRequestOptions,\n ModifyPositionParams,\n ModifyPositionResult,\n} from '../types'\n\nexport class PositionsNamespace {\n constructor(private readonly client: Tickerall) {}\n\n close(\n accountId: string,\n ticket: number,\n params: ClosePositionParams = {},\n options?: IdempotentRequestOptions,\n ): Promise<ClosePositionResult> {\n return this.client.requestIdempotent<ClosePositionResult>(\n {\n method: 'DELETE',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/positions/${ticket}`,\n body: params,\n accountId,\n },\n options,\n )\n }\n\n modify(\n accountId: string,\n ticket: number,\n params: ModifyPositionParams,\n options?: IdempotentRequestOptions,\n ): Promise<ModifyPositionResult> {\n return this.client.requestIdempotent<ModifyPositionResult>(\n {\n method: 'PATCH',\n path: `/v1/accounts/${encodeURIComponent(accountId)}/positions/${ticket}`,\n body: params,\n accountId,\n },\n options,\n )\n }\n}\n","import { EventEmitter } from 'node:events'\nimport WebSocket from 'ws'\nimport type { Tickerall } from '../client'\nimport type {\n AccountEvent,\n PositionEvent,\n StreamCloseEvent,\n StreamErrorEvent,\n StreamReconnectEvent,\n StreamState,\n TickEvent,\n} from '../types'\n\nexport interface StreamConfig {\n streamUrl: string\n apiKey: string\n userAgent: string\n}\n\nexport interface StreamConnectOptions {\n signal?: AbortSignal\n}\n\nconst HEARTBEAT_INTERVAL_MS = 25_000\nconst HEARTBEAT_TIMEOUT_MS = 10_000\nconst RECONNECT_DELAYS = [1_000, 2_000, 4_000, 8_000, 16_000, 30_000]\nconst RECONNECT_MAX_MS = 30_000\n\ninterface TickSubscription {\n kind: 'ticks'\n accountId: string\n symbols: Set<string>\n}\n\ninterface AccountTopicSubscription {\n kind: 'positions' | 'account'\n accountId: string\n}\n\ntype Subscription = TickSubscription | AccountTopicSubscription\n\n// Subscription channels — the server subscribes by `{ kind, accountId, ... }`\n// wrapped in a `channels` array (see the server's ws/protocol).\ntype ChannelFrame =\n | { kind: 'ticks'; accountId: string; symbols: string[] }\n | { kind: 'positions'; accountId: string }\n | { kind: 'account'; accountId: string }\n\ninterface SubscribeFrame {\n type: 'subscribe'\n channels: ChannelFrame[]\n correlationId?: string\n}\n\ninterface UnsubscribeFrame {\n type: 'unsubscribe'\n channels: ChannelFrame[]\n correlationId?: string\n}\n\ntype ClientFrame = SubscribeFrame | UnsubscribeFrame | { type: 'ping' }\n\ninterface IncomingTick {\n type: 'tick'\n accountId: string\n symbol: string\n bid: number\n ask: number\n ordinal?: number\n subtype?: number\n timestamp: string\n}\n\n// The server emits position events as `position_update` with an\n// opened/updated/closed phase, and account events as `account_update`.\ninterface IncomingPositionUpdate {\n type: 'position_update'\n accountId: string\n event: 'opened' | 'updated' | 'closed'\n position: PositionEvent['position']\n}\n\ninterface IncomingAccountUpdate {\n type: 'account_update'\n accountId: string\n snapshot: AccountEvent['snapshot']\n}\n\ninterface IncomingPong {\n type: 'pong'\n ts?: number\n}\n\ninterface IncomingSubscribed {\n type: 'subscribed'\n channels: unknown[]\n rejected: Array<{ channel: unknown; reason: string; code: string }>\n correlationId?: string\n}\n\ninterface IncomingError {\n type: 'error'\n code: string\n message: string\n correlationId?: string\n}\n\ntype IncomingFrame =\n | IncomingTick\n | IncomingPositionUpdate\n | IncomingAccountUpdate\n | IncomingPong\n | IncomingSubscribed\n | IncomingError\n\nconst POSITION_PHASE_MAP: Record<string, PositionEvent['event']> = {\n opened: 'position-opened',\n updated: 'position-updated',\n closed: 'position-closed',\n}\n\nexport interface TickerallStreamEvents {\n tick: (e: TickEvent) => void\n position: (e: PositionEvent) => void\n account: (e: AccountEvent) => void\n error: (e: StreamErrorEvent) => void\n close: (e: StreamCloseEvent) => void\n reconnect: (e: StreamReconnectEvent) => void\n open: () => void\n}\n\nexport class TickerallStream extends EventEmitter {\n private ws: WebSocket | null = null\n private closedByUser = false\n private state: StreamState = 'closed'\n private beforeResubscribe?: () => Promise<void>\n private reconnectAttempts = 0\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null\n private heartbeatTimeoutTimer: ReturnType<typeof setTimeout> | null = null\n private readonly subs: Map<string, Subscription> = new Map()\n private readonly url: string\n private readonly headers: Record<string, string>\n\n constructor(url: string, apiKey: string, userAgent: string) {\n super()\n this.url = url\n this.headers = {\n 'Authorization': `Bearer ${apiKey}`,\n 'User-Agent': userAgent,\n }\n // Swallow `error` events that have no listener; the SDK reports errors\n // via the `error` event and via promise rejection on `connect()`, so a\n // missing listener should not crash the process.\n this.on('error', () => { /* noop default */ })\n }\n\n override on<E extends keyof TickerallStreamEvents>(event: E, listener: TickerallStreamEvents[E]): this {\n return super.on(event, listener as (...args: unknown[]) => void)\n }\n\n override once<E extends keyof TickerallStreamEvents>(event: E, listener: TickerallStreamEvents[E]): this {\n return super.once(event, listener as (...args: unknown[]) => void)\n }\n\n override off<E extends keyof TickerallStreamEvents>(event: E, listener: TickerallStreamEvents[E]): this {\n return super.off(event, listener as (...args: unknown[]) => void)\n }\n\n async connect(): Promise<void> {\n this.closedByUser = false\n this.state = 'connecting'\n await this.openOnce()\n }\n\n /**\n * Internal: callback run after a RECONNECT (not the initial connect), before\n * subscriptions are re-sent. The SDK wires this to re-arm kept sessions so a\n * connection transparently survives an atlas restart.\n */\n setBeforeResubscribe(cb: () => Promise<void>): void {\n this.beforeResubscribe = cb\n }\n\n /**\n * Current connection state. `'open'` means live; `'reconnecting'` means the\n * SDK is silently re-establishing the link (idle apps need do nothing).\n * Queryable any time — never thrown at you.\n */\n getState(): StreamState {\n return this.state\n }\n\n /** `true` only when the stream is live and ready to receive. */\n isConnected(): boolean {\n return this.state === 'open' && this.ws?.readyState === WebSocket.OPEN\n }\n\n /**\n * Resolve once the stream is live (immediately if already open), or reject\n * after `timeoutMs`. Rejects right away if the stream was closed by the\n * caller. Handy to gate logic on a confirmed connection without polling.\n */\n waitUntilConnected(timeoutMs = 30_000): Promise<void> {\n if (this.isConnected()) return Promise.resolve()\n if (this.state === 'closed') return Promise.reject(new Error('Stream is closed'))\n return new Promise<void>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout>\n const onOpen = (): void => {\n clearTimeout(timer)\n resolve()\n }\n timer = setTimeout(() => {\n this.off('open', onOpen)\n reject(new Error(`waitUntilConnected: timed out after ${timeoutMs}ms`))\n }, timeoutMs)\n this.once('open', onOpen)\n })\n }\n\n private openOnce(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const ws = new WebSocket(this.url, { headers: this.headers })\n this.ws = ws\n let settled = false\n\n const onOpen = async (): Promise<void> => {\n if (settled) return\n settled = true\n const wasReconnect = this.reconnectAttempts > 0\n this.state = 'open'\n this.reconnectAttempts = 0\n this.startHeartbeat()\n // After a RECONNECT (atlas may have restarted and lost the broker\n // session), re-arm kept sessions BEFORE resubscribing so the account\n // is hot again on atlas. Skipped on the initial connect.\n if (wasReconnect && this.beforeResubscribe) {\n try { await this.beforeResubscribe() } catch { /* best-effort */ }\n }\n this.resendSubscriptions()\n this.emit('open')\n resolve()\n }\n\n const onMessage = (data: WebSocket.RawData): void => {\n try {\n const frame = JSON.parse(data.toString()) as IncomingFrame\n this.handleFrame(frame)\n } catch (err) {\n this.emit('error', { message: 'Failed to parse server frame', cause: err })\n }\n }\n\n const onError = (err: Error): void => {\n if (!settled) {\n settled = true\n reject(err)\n }\n this.emit('error', { message: err.message, cause: err })\n }\n\n const onClose = (code: number, reason: Buffer): void => {\n this.stopHeartbeat()\n this.ws = null\n const reasonStr = reason?.toString() ?? ''\n this.emit('close', { code, reason: reasonStr })\n if (!settled) {\n settled = true\n reject(new Error(`WebSocket closed before open (code=${code})`))\n }\n if (!this.closedByUser) {\n this.state = 'reconnecting'\n this.scheduleReconnect()\n }\n }\n\n ws.on('open', onOpen)\n ws.on('message', onMessage)\n ws.on('error', onError)\n ws.on('close', onClose)\n ws.on('pong', () => this.clearHeartbeatTimeout())\n })\n }\n\n private handleFrame(frame: IncomingFrame): void {\n switch (frame.type) {\n case 'tick':\n this.emit('tick', {\n type: 'tick',\n accountId: frame.accountId,\n symbol: frame.symbol,\n bid: frame.bid,\n ask: frame.ask,\n timestamp: frame.timestamp,\n })\n return\n case 'position_update':\n this.emit('position', {\n type: 'position',\n accountId: frame.accountId,\n event: POSITION_PHASE_MAP[frame.event] ?? 'position-updated',\n position: frame.position,\n })\n return\n case 'account_update':\n this.emit('account', {\n type: 'account',\n accountId: frame.accountId,\n snapshot: frame.snapshot,\n })\n return\n case 'subscribed':\n if (frame.rejected && frame.rejected.length > 0) {\n this.emit('error', {\n message: `Subscribe rejected: ${frame.rejected.map(r => `${r.code} (${r.reason})`).join(', ')}`,\n })\n }\n return\n case 'error':\n this.emit('error', { message: `${frame.code}: ${frame.message}` })\n return\n case 'pong':\n this.clearHeartbeatTimeout()\n return\n }\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat()\n this.heartbeatTimer = setInterval(() => {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return\n this.send({ type: 'ping' })\n try { this.ws.ping() } catch { /* noop */ }\n this.heartbeatTimeoutTimer = setTimeout(() => this.forceReconnect('heartbeat-timeout'), HEARTBEAT_TIMEOUT_MS)\n }, HEARTBEAT_INTERVAL_MS)\n }\n\n private clearHeartbeatTimeout(): void {\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer)\n this.heartbeatTimeoutTimer = null\n }\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) clearInterval(this.heartbeatTimer)\n if (this.heartbeatTimeoutTimer) clearTimeout(this.heartbeatTimeoutTimer)\n this.heartbeatTimer = null\n this.heartbeatTimeoutTimer = null\n }\n\n private forceReconnect(_reason: string): void {\n if (!this.ws) return\n try { this.ws.terminate() } catch { /* noop */ }\n }\n\n private scheduleReconnect(): void {\n if (this.closedByUser) return\n if (this.reconnectTimer) return\n const idx = Math.min(this.reconnectAttempts, RECONNECT_DELAYS.length - 1)\n const base = RECONNECT_DELAYS[idx] ?? RECONNECT_MAX_MS\n const jitter = Math.floor(Math.random() * Math.min(base, 1_000))\n const delay = Math.min(base + jitter, RECONNECT_MAX_MS + 1_000)\n this.reconnectAttempts += 1\n const attempt = this.reconnectAttempts\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null\n this.emit('reconnect', { attempt })\n this.openOnce().catch(err => {\n this.emit('error', { message: 'Reconnect failed', cause: err })\n this.scheduleReconnect()\n })\n }, delay)\n }\n\n private resendSubscriptions(): void {\n const channels: ChannelFrame[] = []\n for (const sub of this.subs.values()) {\n if (sub.kind === 'ticks') {\n channels.push({ kind: 'ticks', accountId: sub.accountId, symbols: [...sub.symbols] })\n } else {\n channels.push({ kind: sub.kind, accountId: sub.accountId })\n }\n }\n if (channels.length > 0) this.send({ type: 'subscribe', channels })\n }\n\n private send(frame: ClientFrame): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return\n try {\n this.ws.send(JSON.stringify(frame))\n } catch (err) {\n this.emit('error', { message: 'Failed to send frame', cause: err })\n }\n }\n\n async subscribeTicks(accountId: string, symbols: string[]): Promise<void> {\n const key = subKey('ticks', accountId)\n const existing = this.subs.get(key)\n if (existing && existing.kind === 'ticks') {\n for (const s of symbols) existing.symbols.add(s)\n } else {\n this.subs.set(key, { kind: 'ticks', accountId, symbols: new Set(symbols) })\n }\n this.send({ type: 'subscribe', channels: [{ kind: 'ticks', accountId, symbols }] })\n }\n\n async unsubscribeTicks(accountId: string, symbols: string[]): Promise<void> {\n const key = subKey('ticks', accountId)\n const existing = this.subs.get(key)\n if (existing && existing.kind === 'ticks') {\n for (const s of symbols) existing.symbols.delete(s)\n if (existing.symbols.size === 0) this.subs.delete(key)\n }\n this.send({ type: 'unsubscribe', channels: [{ kind: 'ticks', accountId, symbols }] })\n }\n\n async subscribePositions(accountId: string): Promise<void> {\n this.subs.set(subKey('positions', accountId), { kind: 'positions', accountId })\n this.send({ type: 'subscribe', channels: [{ kind: 'positions', accountId }] })\n }\n\n async subscribeAccount(accountId: string): Promise<void> {\n this.subs.set(subKey('account', accountId), { kind: 'account', accountId })\n this.send({ type: 'subscribe', channels: [{ kind: 'account', accountId }] })\n }\n\n async close(): Promise<void> {\n this.closedByUser = true\n this.state = 'closed'\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n this.stopHeartbeat()\n const ws = this.ws\n if (!ws) return\n if (ws.readyState === WebSocket.CLOSED) return\n return new Promise<void>(resolve => {\n const onClose = (): void => resolve()\n ws.once('close', onClose)\n try { ws.close() } catch { resolve() }\n })\n }\n}\n\nfunction subKey(topic: 'ticks' | 'positions' | 'account', accountId: string): string {\n return `${topic}:${accountId}`\n}\n\nexport class StreamNamespace {\n private readonly client: Tickerall\n private readonly streamUrl: string\n private readonly apiKey: string\n private readonly userAgent: string\n\n constructor(client: Tickerall, config: StreamConfig) {\n this.client = client\n this.streamUrl = config.streamUrl\n this.apiKey = config.apiKey\n this.userAgent = config.userAgent\n }\n\n async connect(): Promise<TickerallStream> {\n const stream = new TickerallStream(this.streamUrl, this.apiKey, this.userAgent)\n // On reconnect (atlas may have restarted), re-arm kept sessions before the\n // stream resubscribes, so subscriptions resume against a hot account.\n stream.setBeforeResubscribe(() => this.client.rearmAll())\n await stream.connect()\n return stream\n }\n}\n","import type { Tickerall } from '../client'\nimport type { Candle, CandlesParams, CandlesResponse, RequestOptions } from '../types'\n\nexport class CandlesNamespace {\n constructor(private readonly client: Tickerall) {}\n\n /**\n * Fetch historical OHLC candles for a symbol from one of your broker\n * accounts.\n *\n * Candles are read from the account's own live broker connection, so pass\n * the `accountId` of a connected account. Coarser timeframes reach further\n * back; a single request returns as much history as fits in a few seconds,\n * so pass a large `hours` and take what comes back. Deep look-backs are\n * served on an isolated history connection and won't disturb your live tick\n * stream.\n *\n * @example\n * const bars = await client.candles.get(accountId, { symbol: 'BTCUSDm', hours: 8760, timeframe: 'D1' })\n */\n async get(accountId: string, params: CandlesParams, options?: RequestOptions): Promise<Candle[]> {\n const query = new URLSearchParams({ symbol: params.symbol, hours: String(params.hours) })\n if (params.timeframe) query.set('timeframe', params.timeframe)\n const res = await this.client.requestPlain<CandlesResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/candles?${query.toString()}` },\n options,\n )\n return res.candles\n }\n}\n","import type { Tickerall } from '../client'\nimport type { HistoryParams, HistoryResponse, HistoryTrade, RequestOptions } from '../types'\n\nfunction toQueryTime(v: string | number | Date): string {\n return v instanceof Date ? v.toISOString() : String(v)\n}\n\nexport class HistoryNamespace {\n constructor(private readonly client: Tickerall) {}\n\n /**\n * Closed-trade history for one of your broker accounts — executed deals\n * paired into round-trips, read from the account's own live broker\n * connection (the equivalent of MT5's history_deals_get for the recent\n * window).\n *\n * `symbol`/`from`/`to`/`limit` FILTER the broker's recent deal log (a few\n * weeks deep, broker-controlled) plus any closes seen live this session —\n * they don't fetch deeper than the broker's window. Pass the `accountId` of\n * a connected account.\n *\n * @example\n * const trades = await client.history.get(accountId, { symbol: 'BTCUSDm', limit: 100 })\n */\n async get(accountId: string, params: HistoryParams = {}, options?: RequestOptions): Promise<HistoryTrade[]> {\n const query = new URLSearchParams()\n if (params.symbol) query.set('symbol', params.symbol)\n if (params.from !== undefined) query.set('from', toQueryTime(params.from))\n if (params.to !== undefined) query.set('to', toQueryTime(params.to))\n if (params.limit !== undefined) query.set('limit', String(params.limit))\n if (params.waitMs !== undefined) query.set('waitMs', String(params.waitMs))\n const qs = query.toString()\n const res = await this.client.requestPlain<HistoryResponse>(\n { method: 'GET', path: `/v1/accounts/${encodeURIComponent(accountId)}/history${qs ? `?${qs}` : ''}` },\n options,\n )\n return res.trades\n }\n}\n","import { mapErrorResponse, TickerallApiError, TickerallServiceUnavailableError } from './errors'\nimport { SessionsNamespace } from './namespaces/sessions'\nimport { AccountsNamespace } from './namespaces/accounts'\nimport { OrdersNamespace } from './namespaces/orders'\nimport { PositionsNamespace } from './namespaces/positions'\nimport { StreamNamespace } from './namespaces/stream'\nimport { CandlesNamespace } from './namespaces/candles'\nimport { HistoryNamespace } from './namespaces/history'\nimport type {\n ErrorBody,\n FetchLike,\n IdempotentRequestOptions,\n RequestOptions,\n SessionStartParams,\n SessionStartResult,\n TickerallClientConfig,\n} from './types'\n\nconst DEFAULT_BASE_URL = 'https://api.tickerall.com'\nconst DEFAULT_STREAM_URL = 'wss://api.tickerall.com/v1/stream'\nconst DEFAULT_TIMEOUT_MS = 30_000\nconst SDK_VERSION = '0.1.3'\n\n// Default ceiling on how long a `queueIfReconnecting` call waits across\n// replays before giving up. Bounded on purpose — a queued trade that finally\n// fires minutes late is rarely what the caller wanted.\nconst DEFAULT_QUEUE_MAX_MS = 60_000\n// Backoff between replay attempts for a queued request (ms). Each value is\n// also clamped to the remaining time before the call's deadline.\nconst REPLAY_DELAYS_MS = [500, 1_000, 2_000, 4_000, 8_000]\n\ninterface ReplayJob {\n run: () => Promise<unknown>\n resolve: (value: unknown) => void\n reject: (err: unknown) => void\n deadline: number\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/** @internal */\nexport interface InternalRequestInit {\n method: 'GET' | 'POST' | 'DELETE' | 'PATCH' | 'PUT'\n path: string\n body?: unknown\n idempotencyKey?: string\n signal?: AbortSignal\n timeout?: number\n expectNoContent?: boolean\n // The broker account this request targets, if any. Set by account-scoped\n // namespace methods so the client can transparently re-arm a kept session\n // (re-supply credentials) when the account has gone cold, then retry.\n accountId?: string\n}\n\nexport class Tickerall {\n readonly sessions: SessionsNamespace\n readonly accounts: AccountsNamespace\n readonly orders: OrdersNamespace\n readonly positions: PositionsNamespace\n readonly stream: StreamNamespace\n readonly candles: CandlesNamespace\n readonly history: HistoryNamespace\n\n private readonly apiKey: string\n private readonly baseUrl: string\n private readonly streamUrl: string\n private readonly timeout: number\n private readonly fetchImpl: FetchLike\n private readonly userAgent: string\n\n // In-order replay queue for `queueIfReconnecting` calls. Only opted-in\n // requests ever enter it; everything else bypasses it entirely.\n private readonly replayQueue: ReplayJob[] = []\n private replayDraining = false\n\n // Kept-session credentials — RAM only, NEVER persisted. The broker creds for\n // sessions the customer asked us to keep alive (sessions.keepAlive), so the\n // client can transparently re-arm them when atlas reports the account cold\n // (e.g. after an atlas restart dropped its server-side credentials).\n private readonly keptCreds = new Map<string, SessionStartParams>()\n private readonly onRearm?: (accountId: string) => void\n\n constructor(config: TickerallClientConfig) {\n if (!config || !config.apiKey) {\n throw new TypeError('Tickerall: `apiKey` is required.')\n }\n this.apiKey = config.apiKey\n this.baseUrl = trimTrailingSlash(config.baseUrl ?? DEFAULT_BASE_URL)\n this.streamUrl = config.streamUrl ?? DEFAULT_STREAM_URL\n this.timeout = config.timeout ?? DEFAULT_TIMEOUT_MS\n const resolvedFetch = config.fetch ?? globalThis.fetch\n if (typeof resolvedFetch !== 'function') {\n throw new TypeError('Tickerall: no `fetch` available — pass `fetch` in the config (Node <18 needs an explicit fetch).')\n }\n this.fetchImpl = resolvedFetch.bind(globalThis)\n this.userAgent = config.userAgent\n ? `${config.userAgent} tickerall-js/${SDK_VERSION}`\n : `tickerall-js/${SDK_VERSION}`\n this.onRearm = config.onRearm\n\n this.sessions = new SessionsNamespace(this)\n this.accounts = new AccountsNamespace(this)\n this.orders = new OrdersNamespace(this)\n this.positions = new PositionsNamespace(this)\n this.candles = new CandlesNamespace(this)\n this.history = new HistoryNamespace(this)\n this.stream = new StreamNamespace(this, {\n streamUrl: this.streamUrl,\n apiKey: this.apiKey,\n userAgent: this.userAgent,\n })\n }\n\n // Public entry — runs the request, transparently re-arming a kept session\n // and retrying ONCE if the account has gone cold.\n /** @internal */\n request<T>(init: InternalRequestInit): Promise<T> {\n return this.requestWithRearm<T>(init, false)\n }\n\n private async requestWithRearm<T>(init: InternalRequestInit, isRearmRetry: boolean): Promise<T> {\n try {\n return await this.requestOnce<T>(init)\n } catch (err) {\n // If a kept session's account went cold (e.g. an atlas restart dropped\n // its credentials), refresh them and retry the original request once.\n if (\n !isRearmRetry &&\n init.accountId !== undefined &&\n this.keptCreds.has(init.accountId) &&\n err instanceof TickerallApiError &&\n err.code === 'BROKER_ACCOUNT_NOT_HOT'\n ) {\n await this.rearm(init.accountId)\n return this.requestWithRearm<T>(init, true)\n }\n throw err\n }\n }\n\n private async requestOnce<T>(init: InternalRequestInit): Promise<T> {\n const url = `${this.baseUrl}${init.path}`\n const headers: Record<string, string> = {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'User-Agent': this.userAgent,\n 'Accept': 'application/json',\n }\n if (init.body !== undefined) headers['Content-Type'] = 'application/json'\n if (init.idempotencyKey) headers['Idempotency-Key'] = init.idempotencyKey\n\n const timeoutMs = init.timeout ?? this.timeout\n const controller = new AbortController()\n // Track who aborted: our own timeout is a transient connectivity symptom\n // (retryable), whereas a caller-supplied signal is a deliberate cancel.\n let timedOut = false\n const timer = setTimeout(() => {\n timedOut = true\n controller.abort(new Error(`Request timed out after ${timeoutMs}ms`))\n }, timeoutMs)\n if (init.signal) {\n if (init.signal.aborted) controller.abort(init.signal.reason)\n else init.signal.addEventListener('abort', () => controller.abort(init.signal!.reason), { once: true })\n }\n\n let response: Response\n try {\n response = await this.fetchImpl(url, {\n method: init.method,\n headers,\n body: init.body !== undefined ? JSON.stringify(init.body) : undefined,\n signal: controller.signal,\n })\n } catch (err) {\n clearTimeout(timer)\n if (timedOut) {\n // Timed out waiting for TickerAll — transient, safe to retry.\n throw new TickerallServiceUnavailableError({\n status: 0,\n code: 'REQUEST_TIMEOUT',\n message: `Request timed out after ${timeoutMs}ms`,\n })\n }\n if (controller.signal.aborted) {\n // Caller cancelled via their AbortSignal — deliberate, not transient.\n const reason = (controller.signal.reason as Error | undefined)?.message ?? (err as Error).message ?? 'Request aborted'\n throw new TickerallApiError({\n status: 0,\n code: 'REQUEST_ABORTED',\n message: reason,\n })\n }\n // fetch threw before any response — TickerAll was unreachable. Transient.\n throw new TickerallServiceUnavailableError({\n status: 0,\n code: 'NETWORK_ERROR',\n message: (err as Error).message || 'Network request failed',\n details: err,\n })\n } finally {\n clearTimeout(timer)\n }\n\n const requestId = response.headers.get('x-request-id') ?? undefined\n\n if (init.expectNoContent && response.status === 204) {\n return undefined as T\n }\n\n if (!response.ok) {\n const body = await safeReadErrorBody(response)\n throw mapErrorResponse({\n status: response.status,\n code: body?.error ?? `HTTP_${response.status}`,\n message: body?.message ?? response.statusText ?? 'Request failed',\n details: body?.details,\n requestId,\n })\n }\n\n if (response.status === 204) return undefined as T\n const json = (await response.json()) as T\n return json\n }\n\n /** @internal */\n async requestIdempotent<T>(init: InternalRequestInit, options?: IdempotentRequestOptions): Promise<T> {\n // Fix the idempotency key ONCE so every replay attempt carries the same\n // key — the server then dedupes any attempt that already executed, which\n // is what makes queue-and-replay safe (no double trade).\n const key = options?.idempotencyKey ?? generateIdempotencyKey()\n const full: InternalRequestInit = {\n ...init,\n idempotencyKey: key,\n signal: options?.signal,\n timeout: options?.timeout,\n }\n if (options?.queueIfReconnecting) {\n return this.enqueueReplay<T>(full, options.queueMaxMs ?? DEFAULT_QUEUE_MAX_MS)\n }\n // Default: fail fast. A transient connectivity failure surfaces as\n // TickerallServiceUnavailableError for the caller to re-decide.\n return this.request<T>(full)\n }\n\n // Queue a request for in-order replay, retrying transient failures with\n // backoff until it succeeds or `maxMs` elapses.\n private enqueueReplay<T>(init: InternalRequestInit, maxMs: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n this.replayQueue.push({\n run: () => this.request<unknown>(init),\n resolve: resolve as (value: unknown) => void,\n reject,\n deadline: Date.now() + maxMs,\n })\n void this.drainReplayQueue()\n })\n }\n\n // Serial drain: the head job must settle (resolve, reject, or expire) before\n // the next is attempted, so queued writes replay in submission order.\n private async drainReplayQueue(): Promise<void> {\n if (this.replayDraining) return\n this.replayDraining = true\n try {\n while (this.replayQueue.length > 0) {\n const job = this.replayQueue[0]!\n // Reject up front if this job already expired while head-of-line\n // blocked behind an earlier one riding out a long outage.\n if (Date.now() >= job.deadline) {\n job.reject(new TickerallServiceUnavailableError({\n status: 0,\n code: 'QUEUE_TIMEOUT',\n message: 'Queued request expired before connectivity returned',\n }))\n this.replayQueue.shift()\n continue\n }\n let attempt = 0\n for (;;) {\n try {\n job.resolve(await job.run())\n this.replayQueue.shift()\n break\n } catch (err) {\n const isTransient = err instanceof TickerallApiError && err.transient\n const remaining = job.deadline - Date.now()\n if (!isTransient || remaining <= 0) {\n // Non-transient (bad request, broker rejection, …) never retries;\n // a transient failure past the deadline gives up.\n job.reject(err)\n this.replayQueue.shift()\n break\n }\n const base = REPLAY_DELAYS_MS[Math.min(attempt, REPLAY_DELAYS_MS.length - 1)]!\n attempt += 1\n await sleep(Math.min(base, remaining))\n }\n }\n }\n } finally {\n this.replayDraining = false\n }\n }\n\n /** @internal */\n requestPlain<T>(init: InternalRequestInit, options?: RequestOptions): Promise<T> {\n return this.request<T>({\n ...init,\n signal: options?.signal,\n timeout: options?.timeout,\n })\n }\n\n // ── Kept sessions (auto re-arm) ──────────────────────────────────────────\n // Credentials live in this process's memory only — nothing is persisted.\n\n /** Cache broker creds for an account so the client can auto re-arm it. @internal */\n registerKeptSession(accountId: string, params: SessionStartParams): void {\n this.keptCreds.set(accountId, params)\n }\n\n /** Stop auto-re-arming an account and drop its cached credentials. @internal */\n unregisterKeptSession(accountId: string): void {\n this.keptCreds.delete(accountId)\n }\n\n /** Account IDs currently kept alive (i.e. have cached re-arm credentials). @internal */\n keptSessionIds(): string[] {\n return [...this.keptCreds.keys()]\n }\n\n /**\n * Re-supply credentials for a kept account (a fresh `session.start`) to bring\n * a cold connection back. Throws if the account isn't being kept alive.\n * @internal\n */\n async rearm(accountId: string): Promise<void> {\n const creds = this.keptCreds.get(accountId)\n if (!creds) {\n throw new TickerallApiError({\n status: 0,\n code: 'NO_KEPT_CREDENTIALS',\n message: `No kept credentials for account ${accountId}; call sessions.keepAlive first.`,\n })\n }\n this.onRearm?.(accountId)\n // session.start carries no accountId, so this never recurses into re-arm.\n await this.requestIdempotent<SessionStartResult>({ method: 'POST', path: '/v1/sessions', body: creds })\n }\n\n /**\n * Re-arm every kept session — best-effort (one failure won't block the\n * others). Used after the stream reconnects (atlas may have restarted).\n * @internal\n */\n async rearmAll(): Promise<void> {\n await Promise.all([...this.keptCreds.keys()].map(id => this.rearm(id).catch(() => { /* best-effort */ })))\n }\n}\n\nfunction trimTrailingSlash(s: string): string {\n return s.endsWith('/') ? s.slice(0, -1) : s\n}\n\nasync function safeReadErrorBody(response: Response): Promise<ErrorBody | null> {\n try {\n const text = await response.text()\n if (!text) return null\n try {\n return JSON.parse(text) as ErrorBody\n } catch {\n return { error: 'PARSE_ERROR', message: text }\n }\n } catch {\n return null\n }\n}\n\nexport function generateIdempotencyKey(): string {\n const c: { randomUUID?: () => string } | undefined = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n if (c && typeof c.randomUUID === 'function') return c.randomUUID()\n return fallbackUuid()\n}\n\nfunction fallbackUuid(): string {\n const bytes = new Uint8Array(16)\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256)\n bytes[6] = (bytes[6]! & 0x0f) | 0x40\n bytes[8] = (bytes[8]! & 0x3f) | 0x80\n const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\n"]}
|