dritan-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # dritan-sdk
2
+
3
+ TypeScript SDK for Dritan's data plane REST API and websocket streams.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm i dritan-sdk
9
+ ```
10
+
11
+ ## Quickstart
12
+
13
+ ```ts
14
+ import { DritanClient } from "dritan-sdk";
15
+
16
+ const client = new DritanClient({
17
+ apiKey: process.env.DRITAN_API_KEY!,
18
+ baseUrl: "https://us-east.dritan.dev"
19
+ });
20
+
21
+ const price = await client.getTokenPrice("So11111111111111111111111111111111111111112");
22
+ console.log(price);
23
+ ```
24
+
25
+ ## REST
26
+
27
+ ### Token price
28
+
29
+ ```ts
30
+ const price = await client.getTokenPrice("So11111111111111111111111111111111111111112");
31
+ console.log(price.priceUsd);
32
+ ```
33
+
34
+ ### Token metadata
35
+
36
+ ```ts
37
+ const md = await client.getTokenMetadata("So11111111111111111111111111111111111111112");
38
+ console.log(md.name, md.symbol, md.decimals);
39
+ ```
40
+
41
+ ### Token risk
42
+
43
+ ```ts
44
+ const risk = await client.getTokenRisk("So11111111111111111111111111111111111111112");
45
+ console.log(risk.globalFeesPaid, risk.top10);
46
+ ```
47
+
48
+ ### First buyers (up to 100)
49
+
50
+ ```ts
51
+ const res = await client.getFirstBuyers("So11111111111111111111111111111111111111112");
52
+ console.log(res.buyers);
53
+ ```
54
+
55
+ ### Aggregated token data
56
+
57
+ ```ts
58
+ const agg = await client.getTokenAggregated("So11111111111111111111111111111111111111112");
59
+ console.log(agg.price.priceUsd, agg.metadata?.name, agg.risk?.top10, agg.bondingCurvePercent);
60
+ ```
61
+
62
+ ## Swap
63
+
64
+ Dritan can build an unsigned swap transaction (base64) for you to sign, then you broadcast the signed transaction.
65
+
66
+ ```ts
67
+ import { Connection, VersionedTransaction } from "@solana/web3.js";
68
+
69
+ const build = await client.buildSwap({
70
+ userPublicKey: wallet.publicKey.toBase58(),
71
+ inputMint: "So11111111111111111111111111111111111111112",
72
+ outputMint: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
73
+ amount: 100_000_000, // lamports
74
+ slippageBps: 500,
75
+ swapType: "buy",
76
+ // Optional: monetize swaps for your own users
77
+ feeWallet: "YourFeeWalletPubkeyHere",
78
+ feePercent: 0.5
79
+ });
80
+
81
+ const tx = VersionedTransaction.deserialize(Buffer.from(build.transactionBase64, "base64"));
82
+ const signed = await wallet.signTransaction(tx);
83
+ const signedBase64 = Buffer.from(signed.serialize()).toString("base64");
84
+
85
+ const sent = await client.broadcastSwap(signedBase64);
86
+ console.log(sent.signature);
87
+ ```
88
+
89
+ ## Websocket streams
90
+
91
+ Connect to a dex stream (for example `pumpamm`, `pumpfun`, `launchlab`, `dbc`, `dlmm`, `damm2`, `damm1`).
92
+
93
+ ```ts
94
+ const stream = client.streamDex("pumpamm", {
95
+ onMessage: (event) => {
96
+ // `event` is parsed JSON when possible, otherwise raw string.
97
+ console.log(event);
98
+ }
99
+ });
100
+
101
+ setTimeout(() => stream.close(), 10_000);
102
+ ```
103
+
104
+ Note: browser websockets cannot send custom headers. If you use this SDK in the browser, pass `sendApiKeyInQuery: true` (this puts your API key in the websocket URL).
105
+
106
+ ## Configuration
107
+
108
+ `DritanClient` options:
109
+
110
+ - `apiKey` (required): API key to send as `x-api-key`
111
+ - `baseUrl` (optional): REST base URL (default `https://us-east.dritan.dev`)
112
+ - `wsBaseUrl` (optional): WS base URL (default `wss://us-east.dritan.dev`)
113
+
114
+ ## Meteora THS (No API Key)
115
+
116
+ Meteora THS is a public REST API hosted at `https://ths.dritan.dev`.
117
+
118
+ ```ts
119
+ import { MeteoraThsClient } from "dritan-sdk";
120
+
121
+ const ths = new MeteoraThsClient();
122
+
123
+ const score = await ths.getThsScore("7Y...Wallet");
124
+ console.log(score.score, score.realizedPnLUsd);
125
+
126
+ const tokensOnly = await ths.getThsScoreForTokens("7Y...Wallet", [
127
+ "So11111111111111111111111111111111111111112",
128
+ "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
129
+ ]);
130
+ console.log(tokensOnly.score);
131
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,255 @@
1
+ 'use strict';
2
+
3
+ var WebSocketImpl = require('isomorphic-ws');
4
+
5
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
+
7
+ var WebSocketImpl__default = /*#__PURE__*/_interopDefault(WebSocketImpl);
8
+
9
+ // src/index.ts
10
+ function buildUrl(baseUrl, path) {
11
+ return `${baseUrl.replace(/\/+$/, "")}${path.startsWith("/") ? "" : "/"}${path}`;
12
+ }
13
+ function buildWsUrl(wsBaseUrl, path, query) {
14
+ const url = new URL(buildUrl(wsBaseUrl, path));
15
+ if (query) {
16
+ for (const [k, v] of Object.entries(query)) {
17
+ if (v === void 0 || v === null) continue;
18
+ url.searchParams.set(k, String(v));
19
+ }
20
+ }
21
+ return url.toString();
22
+ }
23
+ function safeJsonParse(payload) {
24
+ try {
25
+ return JSON.parse(payload);
26
+ } catch {
27
+ return payload;
28
+ }
29
+ }
30
+ function isNodeRuntime() {
31
+ return typeof process !== "undefined" && typeof process.versions?.node === "string";
32
+ }
33
+ function messageToString(data) {
34
+ if (typeof data === "string") return data;
35
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
36
+ return data.toString("utf8");
37
+ }
38
+ if (data instanceof ArrayBuffer) {
39
+ return new TextDecoder().decode(new Uint8Array(data));
40
+ }
41
+ return null;
42
+ }
43
+ var DritanClient = class {
44
+ apiKey;
45
+ baseUrl;
46
+ wsBaseUrl;
47
+ fetchImpl;
48
+ WebSocketCtor;
49
+ constructor(options) {
50
+ this.apiKey = options.apiKey;
51
+ this.baseUrl = options.baseUrl ?? "https://us-east.dritan.dev";
52
+ this.wsBaseUrl = options.wsBaseUrl ?? "wss://us-east.dritan.dev";
53
+ this.fetchImpl = options.fetch ?? fetch;
54
+ this.WebSocketCtor = options.WebSocket ?? WebSocketImpl__default.default;
55
+ }
56
+ async getTokenPrice(mint) {
57
+ const url = buildUrl(this.baseUrl, `/token/price/${encodeURIComponent(mint)}`);
58
+ const res = await this.fetchImpl(url, {
59
+ method: "GET",
60
+ headers: {
61
+ "x-api-key": this.apiKey
62
+ }
63
+ });
64
+ if (!res.ok) {
65
+ const text = await res.text().catch(() => "");
66
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
67
+ }
68
+ return await res.json();
69
+ }
70
+ async getTokenMetadata(mint) {
71
+ const url = buildUrl(this.baseUrl, `/token/metadata/${encodeURIComponent(mint)}`);
72
+ const res = await this.fetchImpl(url, {
73
+ method: "GET",
74
+ headers: {
75
+ "x-api-key": this.apiKey
76
+ }
77
+ });
78
+ if (!res.ok) {
79
+ const text = await res.text().catch(() => "");
80
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
81
+ }
82
+ return await res.json();
83
+ }
84
+ async getTokenRisk(mint) {
85
+ const url = buildUrl(this.baseUrl, `/token/risk/${encodeURIComponent(mint)}`);
86
+ const res = await this.fetchImpl(url, {
87
+ method: "GET",
88
+ headers: {
89
+ "x-api-key": this.apiKey
90
+ }
91
+ });
92
+ if (!res.ok) {
93
+ const text = await res.text().catch(() => "");
94
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
95
+ }
96
+ return await res.json();
97
+ }
98
+ async getFirstBuyers(mint) {
99
+ const url = buildUrl(this.baseUrl, `/token/first-buyers/${encodeURIComponent(mint)}`);
100
+ const res = await this.fetchImpl(url, {
101
+ method: "GET",
102
+ headers: {
103
+ "x-api-key": this.apiKey
104
+ }
105
+ });
106
+ if (!res.ok) {
107
+ const text = await res.text().catch(() => "");
108
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
109
+ }
110
+ return await res.json();
111
+ }
112
+ async getTokenAggregated(mint) {
113
+ const url = buildUrl(this.baseUrl, `/token/aggregated/${encodeURIComponent(mint)}`);
114
+ const res = await this.fetchImpl(url, {
115
+ method: "GET",
116
+ headers: {
117
+ "x-api-key": this.apiKey
118
+ }
119
+ });
120
+ if (!res.ok) {
121
+ const text = await res.text().catch(() => "");
122
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
123
+ }
124
+ const raw = await res.json();
125
+ return {
126
+ mint: String(raw?.mint ?? mint),
127
+ price: raw?.price,
128
+ metadata: raw?.metadata ?? null,
129
+ risk: raw?.risk ?? null,
130
+ bondingCurvePercent: raw?.bondingCurvePercent === void 0 ? null : raw?.bondingCurvePercent ?? null
131
+ };
132
+ }
133
+ async buildSwap(body) {
134
+ const url = buildUrl(this.baseUrl, "/swap/build");
135
+ const res = await this.fetchImpl(url, {
136
+ method: "POST",
137
+ headers: {
138
+ "x-api-key": this.apiKey,
139
+ "content-type": "application/json"
140
+ },
141
+ body: JSON.stringify(body ?? {})
142
+ });
143
+ if (!res.ok) {
144
+ const text = await res.text().catch(() => "");
145
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
146
+ }
147
+ return await res.json();
148
+ }
149
+ async broadcastSwap(signedTransactionBase64) {
150
+ const url = buildUrl(this.baseUrl, "/swap/broadcast");
151
+ const res = await this.fetchImpl(url, {
152
+ method: "POST",
153
+ headers: {
154
+ "x-api-key": this.apiKey,
155
+ "content-type": "application/json"
156
+ },
157
+ body: JSON.stringify({ signedTransactionBase64 })
158
+ });
159
+ if (!res.ok) {
160
+ const text = await res.text().catch(() => "");
161
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
162
+ }
163
+ return await res.json();
164
+ }
165
+ streamDex(dex, options = {}) {
166
+ const shouldSendKeyInQuery = options.sendApiKeyInQuery ?? !isNodeRuntime();
167
+ const query = { ...options.query ?? {} };
168
+ if (shouldSendKeyInQuery && query.apiKey == null) {
169
+ query.apiKey = this.apiKey;
170
+ }
171
+ const url = buildWsUrl(this.wsBaseUrl, `/${dex}`, query);
172
+ const ws = shouldSendKeyInQuery ? new this.WebSocketCtor(url) : new this.WebSocketCtor(
173
+ url,
174
+ {
175
+ headers: {
176
+ "x-api-key": this.apiKey
177
+ }
178
+ }
179
+ );
180
+ ws.onopen = () => options.onOpen?.();
181
+ ws.onclose = (ev) => options.onClose?.(ev);
182
+ ws.onerror = (ev) => options.onError?.(ev);
183
+ ws.onmessage = (msg) => {
184
+ const raw = messageToString(msg.data);
185
+ const data = raw ? safeJsonParse(raw) : msg.data;
186
+ options.onMessage?.(data);
187
+ };
188
+ return {
189
+ socket: ws,
190
+ close: () => ws.close()
191
+ };
192
+ }
193
+ };
194
+ var createClient = (options) => new DritanClient(options);
195
+ var MeteoraThsClient = class {
196
+ baseUrl;
197
+ fetchImpl;
198
+ constructor(options = {}) {
199
+ this.baseUrl = options.baseUrl ?? "https://ths.dritan.dev";
200
+ this.fetchImpl = options.fetch ?? fetch;
201
+ }
202
+ async health() {
203
+ const url = buildUrl(this.baseUrl, "/health");
204
+ const res = await this.fetchImpl(url, { method: "GET" });
205
+ return res.ok;
206
+ }
207
+ async getThsScore(wallet, options = {}) {
208
+ const url = new URL(buildUrl(this.baseUrl, `/ths/${encodeURIComponent(wallet)}`));
209
+ if (options.debug) url.searchParams.set("debug", "1");
210
+ if (options.breakdown) url.searchParams.set("breakdown", "1");
211
+ const res = await this.fetchImpl(url.toString(), { method: "GET" });
212
+ if (!res.ok) {
213
+ const text = await res.text().catch(() => "");
214
+ throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);
215
+ }
216
+ return await res.json();
217
+ }
218
+ async getThsScoreForTokens(wallet, tokenMints, options = {}) {
219
+ const url = new URL(buildUrl(this.baseUrl, `/ths/${encodeURIComponent(wallet)}/tokens`));
220
+ for (const mint of tokenMints ?? []) {
221
+ url.searchParams.append("tokenMints", mint);
222
+ }
223
+ if (options.debug) url.searchParams.set("debug", "1");
224
+ if (options.breakdown) url.searchParams.set("breakdown", "1");
225
+ const res = await this.fetchImpl(url.toString(), { method: "GET" });
226
+ if (!res.ok) {
227
+ const text = await res.text().catch(() => "");
228
+ throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);
229
+ }
230
+ return await res.json();
231
+ }
232
+ async postThsScoreForTokens(wallet, tokenMints, options = {}) {
233
+ const url = new URL(buildUrl(this.baseUrl, `/ths/${encodeURIComponent(wallet)}/tokens`));
234
+ if (options.debug) url.searchParams.set("debug", "1");
235
+ if (options.breakdown) url.searchParams.set("breakdown", "1");
236
+ const res = await this.fetchImpl(url.toString(), {
237
+ method: "POST",
238
+ headers: { "content-type": "application/json" },
239
+ body: JSON.stringify({ tokenMints: tokenMints ?? [] })
240
+ });
241
+ if (!res.ok) {
242
+ const text = await res.text().catch(() => "");
243
+ throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);
244
+ }
245
+ return await res.json();
246
+ }
247
+ };
248
+ var createMeteoraThsClient = (options) => new MeteoraThsClient(options);
249
+
250
+ exports.DritanClient = DritanClient;
251
+ exports.MeteoraThsClient = MeteoraThsClient;
252
+ exports.createClient = createClient;
253
+ exports.createMeteoraThsClient = createMeteoraThsClient;
254
+ //# sourceMappingURL=index.cjs.map
255
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["WebSocketImpl"],"mappings":";;;;;;;;;AA2IA,SAAS,QAAA,CAAS,SAAiB,IAAA,EAAsB;AACvD,EAAA,OAAO,CAAA,EAAG,OAAA,CAAQ,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAC,CAAA,EAAG,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,GAAI,EAAA,GAAK,GAAG,GAAG,IAAI,CAAA,CAAA;AAChF;AAEA,SAAS,UAAA,CACP,SAAA,EACA,IAAA,EACA,KAAA,EACQ;AACR,EAAA,MAAM,MAAM,IAAI,GAAA,CAAI,QAAA,CAAS,SAAA,EAAW,IAAI,CAAC,CAAA;AAC7C,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC1C,MAAA,IAAI,CAAA,KAAM,MAAA,IAAa,CAAA,KAAM,IAAA,EAAM;AACnC,MAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,IACnC;AAAA,EACF;AACA,EAAA,OAAO,IAAI,QAAA,EAAS;AACtB;AAEA,SAAS,cAAc,OAAA,EAA0B;AAC/C,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,EAC3B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,OAAA;AAAA,EACT;AACF;AAEA,SAAS,aAAA,GAAyB;AAChC,EAAA,OACE,OAAO,OAAA,KAAY,WAAA,IACnB,OAAQ,OAAA,CAAgB,UAAU,IAAA,KAAS,QAAA;AAE/C;AAEA,SAAS,gBAAgB,IAAA,EAA8B;AACrD,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AAGrC,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,MAAA,CAAO,QAAA,CAAS,IAAI,CAAA,EAAG;AAC1D,IAAA,OAAO,IAAA,CAAK,SAAS,MAAM,CAAA;AAAA,EAC7B;AAGA,EAAA,IAAI,gBAAgB,WAAA,EAAa;AAC/B,IAAA,OAAO,IAAI,WAAA,EAAY,CAAE,OAAO,IAAI,UAAA,CAAW,IAAI,CAAC,CAAA;AAAA,EACtD;AAEA,EAAA,OAAO,IAAA;AACT;AAEO,IAAM,eAAN,MAAmB;AAAA,EACf,MAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACQ,SAAA;AAAA,EACA,aAAA;AAAA,EAEjB,YAAY,OAAA,EAA8B;AACxC,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AACtB,IAAA,IAAA,CAAK,OAAA,GAAU,QAAQ,OAAA,IAAW,4BAAA;AAClC,IAAA,IAAA,CAAK,SAAA,GAAY,QAAQ,SAAA,IAAa,0BAAA;AACtC,IAAA,IAAA,CAAK,SAAA,GAAY,QAAQ,KAAA,IAAS,KAAA;AAClC,IAAA,IAAA,CAAK,aAAA,GAAgB,QAAQ,SAAA,IAAaA,8BAAA;AAAA,EAC5C;AAAA,EAEA,MAAM,cAAc,IAAA,EAA2C;AAC7D,IAAA,MAAM,GAAA,GAAM,SAAS,IAAA,CAAK,OAAA,EAAS,gBAAgB,kBAAA,CAAmB,IAAI,CAAC,CAAA,CAAE,CAAA;AAC7E,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAU,GAAA,EAAK;AAAA,MACpC,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,aAAa,IAAA,CAAK;AAAA;AACpB,KACD,CAAA;AAED,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,MAAA,MAAM,IAAI,MAAM,CAAA,uBAAA,EAA0B,GAAA,CAAI,MAAM,CAAA,GAAA,EAAM,IAAA,IAAQ,GAAA,CAAI,UAAU,CAAA,CAAE,CAAA;AAAA,IACpF;AAEA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB;AAAA,EAEA,MAAM,iBAAiB,IAAA,EAA8C;AACnE,IAAA,MAAM,GAAA,GAAM,SAAS,IAAA,CAAK,OAAA,EAAS,mBAAmB,kBAAA,CAAmB,IAAI,CAAC,CAAA,CAAE,CAAA;AAChF,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAU,GAAA,EAAK;AAAA,MACpC,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,aAAa,IAAA,CAAK;AAAA;AACpB,KACD,CAAA;AAED,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,MAAA,MAAM,IAAI,MAAM,CAAA,uBAAA,EAA0B,GAAA,CAAI,MAAM,CAAA,GAAA,EAAM,IAAA,IAAQ,GAAA,CAAI,UAAU,CAAA,CAAE,CAAA;AAAA,IACpF;AAEA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB;AAAA,EAEA,MAAM,aAAa,IAAA,EAA0C;AAC3D,IAAA,MAAM,GAAA,GAAM,SAAS,IAAA,CAAK,OAAA,EAAS,eAAe,kBAAA,CAAmB,IAAI,CAAC,CAAA,CAAE,CAAA;AAC5E,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAU,GAAA,EAAK;AAAA,MACpC,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,aAAa,IAAA,CAAK;AAAA;AACpB,KACD,CAAA;AAED,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,MAAA,MAAM,IAAI,MAAM,CAAA,uBAAA,EAA0B,GAAA,CAAI,MAAM,CAAA,GAAA,EAAM,IAAA,IAAQ,GAAA,CAAI,UAAU,CAAA,CAAE,CAAA;AAAA,IACpF;AAEA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB;AAAA,EAEA,MAAM,eAAe,IAAA,EAAiD;AACpE,IAAA,MAAM,GAAA,GAAM,SAAS,IAAA,CAAK,OAAA,EAAS,uBAAuB,kBAAA,CAAmB,IAAI,CAAC,CAAA,CAAE,CAAA;AACpF,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAU,GAAA,EAAK;AAAA,MACpC,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,aAAa,IAAA,CAAK;AAAA;AACpB,KACD,CAAA;AAED,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,MAAA,MAAM,IAAI,MAAM,CAAA,uBAAA,EAA0B,GAAA,CAAI,MAAM,CAAA,GAAA,EAAM,IAAA,IAAQ,GAAA,CAAI,UAAU,CAAA,CAAE,CAAA;AAAA,IACpF;AAEA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB;AAAA,EAEA,MAAM,mBAAmB,IAAA,EAAgD;AACvE,IAAA,MAAM,GAAA,GAAM,SAAS,IAAA,CAAK,OAAA,EAAS,qBAAqB,kBAAA,CAAmB,IAAI,CAAC,CAAA,CAAE,CAAA;AAClF,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAU,GAAA,EAAK;AAAA,MACpC,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,aAAa,IAAA,CAAK;AAAA;AACpB,KACD,CAAA;AAED,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,MAAA,MAAM,IAAI,MAAM,CAAA,uBAAA,EAA0B,GAAA,CAAI,MAAM,CAAA,GAAA,EAAM,IAAA,IAAQ,GAAA,CAAI,UAAU,CAAA,CAAE,CAAA;AAAA,IACpF;AAEA,IAAA,MAAM,GAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,MAAA,CAAO,GAAA,EAAK,IAAA,IAAQ,IAAI,CAAA;AAAA,MAC9B,OAAO,GAAA,EAAK,KAAA;AAAA,MACZ,QAAA,EAAU,KAAK,QAAA,IAAY,IAAA;AAAA,MAC3B,IAAA,EAAM,KAAK,IAAA,IAAQ,IAAA;AAAA,MACnB,qBACE,GAAA,EAAK,mBAAA,KAAwB,MAAA,GAAY,IAAA,GAAQ,KAAK,mBAAA,IAAuB;AAAA,KACjF;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,IAAA,EAAoD;AAClE,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,IAAA,CAAK,OAAA,EAAS,aAAa,CAAA;AAChD,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAU,GAAA,EAAK;AAAA,MACpC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,aAAa,IAAA,CAAK,MAAA;AAAA,QAClB,cAAA,EAAgB;AAAA,OAClB;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAA,IAAQ,EAAE;AAAA,KAChC,CAAA;AAED,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,MAAA,MAAM,IAAI,MAAM,CAAA,uBAAA,EAA0B,GAAA,CAAI,MAAM,CAAA,GAAA,EAAM,IAAA,IAAQ,GAAA,CAAI,UAAU,CAAA,CAAE,CAAA;AAAA,IACpF;AAEA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB;AAAA,EAEA,MAAM,cAAc,uBAAA,EAAiE;AACnF,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,IAAA,CAAK,OAAA,EAAS,iBAAiB,CAAA;AACpD,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAU,GAAA,EAAK;AAAA,MACpC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,aAAa,IAAA,CAAK,MAAA;AAAA,QAClB,cAAA,EAAgB;AAAA,OAClB;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,yBAAyB;AAAA,KACjD,CAAA;AAED,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,MAAA,MAAM,IAAI,MAAM,CAAA,uBAAA,EAA0B,GAAA,CAAI,MAAM,CAAA,GAAA,EAAM,IAAA,IAAQ,GAAA,CAAI,UAAU,CAAA,CAAE,CAAA;AAAA,IACpF;AAEA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB;AAAA,EAIA,SAAA,CAAU,GAAA,EAAa,OAAA,GAA+B,EAAC,EAAuB;AAC5E,IAAA,MAAM,oBAAA,GAAuB,OAAA,CAAQ,iBAAA,IAAqB,CAAC,aAAA,EAAc;AACzE,IAAA,MAAM,QAAQ,EAAE,GAAI,OAAA,CAAQ,KAAA,IAAS,EAAC,EAAG;AAIzC,IAAA,IAAI,oBAAA,IAAwB,KAAA,CAAM,MAAA,IAAU,IAAA,EAAM;AAChD,MAAA,KAAA,CAAM,SAAS,IAAA,CAAK,MAAA;AAAA,IACtB;AAEA,IAAA,MAAM,MAAM,UAAA,CAAW,IAAA,CAAK,WAAW,CAAA,CAAA,EAAI,GAAG,IAAI,KAAK,CAAA;AACvD,IAAA,MAAM,EAAA,GAAK,uBACP,IAAI,IAAA,CAAK,cAAc,GAAG,CAAA,GAC1B,IAAI,IAAA,CAAK,aAAA;AAAA,MACP,GAAA;AAAA,MACA;AAAA,QACE,OAAA,EAAS;AAAA,UACP,aAAa,IAAA,CAAK;AAAA;AACpB;AACF,KACF;AAEJ,IAAA,EAAA,CAAG,MAAA,GAAS,MAAM,OAAA,CAAQ,MAAA,IAAS;AACnC,IAAA,EAAA,CAAG,OAAA,GAAU,CAAC,EAAA,KAAY,OAAA,CAAQ,UAAU,EAAgB,CAAA;AAC5D,IAAA,EAAA,CAAG,OAAA,GAAU,CAAC,EAAA,KAAY,OAAA,CAAQ,UAAU,EAAW,CAAA;AACvD,IAAA,EAAA,CAAG,SAAA,GAAY,CAAC,GAAA,KAAa;AAC3B,MAAA,MAAM,GAAA,GAAM,eAAA,CAAgB,GAAA,CAAI,IAAI,CAAA;AACpC,MAAA,MAAM,IAAA,GAAO,GAAA,GAAM,aAAA,CAAc,GAAG,IAAI,GAAA,CAAI,IAAA;AAC5C,MAAA,OAAA,CAAQ,YAAY,IAAI,CAAA;AAAA,IAC1B,CAAA;AAEA,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,EAAA;AAAA,MACR,KAAA,EAAO,MAAM,EAAA,CAAG,KAAA;AAAM,KACxB;AAAA,EACF;AACF;AAEO,IAAM,YAAA,GAAe,CAAC,OAAA,KAAiC,IAAI,aAAa,OAAO;AAE/E,IAAM,mBAAN,MAAuB;AAAA,EACnB,OAAA;AAAA,EACQ,SAAA;AAAA,EAEjB,WAAA,CAAY,OAAA,GAAmC,EAAC,EAAG;AACjD,IAAA,IAAA,CAAK,OAAA,GAAU,QAAQ,OAAA,IAAW,wBAAA;AAClC,IAAA,IAAA,CAAK,SAAA,GAAY,QAAQ,KAAA,IAAS,KAAA;AAAA,EACpC;AAAA,EAEA,MAAM,MAAA,GAA2B;AAC/B,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,IAAA,CAAK,OAAA,EAAS,SAAS,CAAA;AAC5C,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAU,KAAK,EAAE,MAAA,EAAQ,OAAO,CAAA;AACvD,IAAA,OAAO,GAAA,CAAI,EAAA;AAAA,EACb;AAAA,EAEA,MAAM,WAAA,CACJ,MAAA,EACA,OAAA,GAAoD,EAAC,EAC/B;AACtB,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,QAAA,CAAS,IAAA,CAAK,OAAA,EAAS,CAAA,KAAA,EAAQ,kBAAA,CAAmB,MAAM,CAAC,CAAA,CAAE,CAAC,CAAA;AAChF,IAAA,IAAI,QAAQ,KAAA,EAAO,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,SAAS,GAAG,CAAA;AACpD,IAAA,IAAI,QAAQ,SAAA,EAAW,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,aAAa,GAAG,CAAA;AAE5D,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,UAAS,EAAG,EAAE,MAAA,EAAQ,KAAA,EAAO,CAAA;AAClE,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,MAAA,MAAM,IAAI,MAAM,CAAA,4BAAA,EAA+B,GAAA,CAAI,MAAM,CAAA,GAAA,EAAM,IAAA,IAAQ,GAAA,CAAI,UAAU,CAAA,CAAE,CAAA;AAAA,IACzF;AAEA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB;AAAA,EAEA,MAAM,oBAAA,CACJ,MAAA,EACA,UAAA,EACA,OAAA,GAAoD,EAAC,EAC/B;AACtB,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,QAAA,CAAS,IAAA,CAAK,OAAA,EAAS,CAAA,KAAA,EAAQ,kBAAA,CAAmB,MAAM,CAAC,CAAA,OAAA,CAAS,CAAC,CAAA;AACvF,IAAA,KAAA,MAAW,IAAA,IAAQ,UAAA,IAAc,EAAC,EAAG;AACnC,MAAA,GAAA,CAAI,YAAA,CAAa,MAAA,CAAO,YAAA,EAAc,IAAI,CAAA;AAAA,IAC5C;AACA,IAAA,IAAI,QAAQ,KAAA,EAAO,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,SAAS,GAAG,CAAA;AACpD,IAAA,IAAI,QAAQ,SAAA,EAAW,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,aAAa,GAAG,CAAA;AAE5D,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,UAAS,EAAG,EAAE,MAAA,EAAQ,KAAA,EAAO,CAAA;AAClE,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,MAAA,MAAM,IAAI,MAAM,CAAA,4BAAA,EAA+B,GAAA,CAAI,MAAM,CAAA,GAAA,EAAM,IAAA,IAAQ,GAAA,CAAI,UAAU,CAAA,CAAE,CAAA;AAAA,IACzF;AAEA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB;AAAA,EAEA,MAAM,qBAAA,CACJ,MAAA,EACA,UAAA,EACA,OAAA,GAAoD,EAAC,EAC/B;AACtB,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,QAAA,CAAS,IAAA,CAAK,OAAA,EAAS,CAAA,KAAA,EAAQ,kBAAA,CAAmB,MAAM,CAAC,CAAA,OAAA,CAAS,CAAC,CAAA;AACvF,IAAA,IAAI,QAAQ,KAAA,EAAO,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,SAAS,GAAG,CAAA;AACpD,IAAA,IAAI,QAAQ,SAAA,EAAW,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,aAAa,GAAG,CAAA;AAE5D,IAAA,MAAM,MAAM,MAAM,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,UAAS,EAAG;AAAA,MAC/C,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,MAC9C,IAAA,EAAM,KAAK,SAAA,CAAU,EAAE,YAAY,UAAA,IAAc,IAAI;AAAA,KACtD,CAAA;AACD,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,MAAA,MAAM,IAAI,MAAM,CAAA,4BAAA,EAA+B,GAAA,CAAI,MAAM,CAAA,GAAA,EAAM,IAAA,IAAQ,GAAA,CAAI,UAAU,CAAA,CAAE,CAAA;AAAA,IACzF;AAEA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB;AACF;AAEO,IAAM,sBAAA,GAAyB,CAAC,OAAA,KACrC,IAAI,iBAAiB,OAAO","file":"index.cjs","sourcesContent":["import WebSocketImpl from \"isomorphic-ws\";\n\nexport type DritanClientOptions = {\n apiKey: string;\n baseUrl?: string;\n wsBaseUrl?: string;\n fetch?: typeof fetch;\n WebSocket?: typeof WebSocketImpl;\n};\n\nexport type KnownDexStream =\n | \"pumpamm\"\n | \"pumpfun\"\n | \"launchlab\"\n | \"dlmm\"\n | \"damm2\"\n | \"damm1\"\n | \"dbc\";\n\nexport type MeteoraThsClientOptions = {\n baseUrl?: string;\n fetch?: typeof fetch;\n};\n\nexport type TokenPriceResponse = {\n mint: string;\n dex: string;\n priceUsd: number;\n marketCap: number | null;\n liquiditySol: number | null;\n};\n\nexport type TokenMetadataResponse = {\n mint: string;\n programId: string;\n name: string;\n symbol: string;\n uri: string;\n decimals: number;\n supply: string;\n};\n\nexport type RiskGroup = {\n count: number;\n totalPercentage: number;\n};\n\nexport type TokenRiskResponse = {\n mint: string;\n globalFeesPaid: number;\n bundlers: RiskGroup;\n insiders: RiskGroup;\n snipers: RiskGroup;\n top10: number;\n devPercentage: number | null;\n};\n\nexport type TokenFirstBuyersResponse = {\n mint: string;\n buyers: unknown;\n};\n\nexport type TokenAggregatedResponse = {\n mint: string;\n price: TokenPriceResponse;\n metadata: TokenMetadataResponse | null;\n risk: TokenRiskResponse | null;\n bondingCurvePercent: number | null;\n};\n\nexport type DritanStreamOptions = {\n query?: Record<string, string | number | boolean | undefined | null>;\n /**\n * When true, includes the api key as `?apiKey=...` in the websocket URL.\n * This is required when using native browser websockets (custom headers are not supported).\n */\n sendApiKeyInQuery?: boolean;\n onOpen?: () => void;\n onClose?: (ev: CloseEvent) => void;\n onError?: (ev: Event) => void;\n onMessage?: (data: unknown) => void;\n};\n\nexport type DritanStreamHandle = {\n socket: WebSocket;\n close: () => void;\n};\n\nexport type SwapBuildRequest = {\n userPublicKey: string;\n inputMint: string;\n outputMint: string;\n amount: number | string;\n slippageBps?: number;\n swapType?: string;\n feeWallet?: string;\n feeBps?: number;\n feePercent?: number;\n};\n\nexport type SwapBuildFees = {\n platformFeeBps: number;\n platformFeeLamports: number;\n userFeeBps: number;\n userFeeLamports: number;\n tipLamports: number;\n};\n\nexport type SwapBuildResponse = {\n transactionBase64: string;\n fees: SwapBuildFees;\n quote: unknown;\n};\n\nexport type SwapBroadcastResponse = {\n signature: string;\n};\n\nexport type ThsTotals = {\n buys: number;\n sells: number;\n};\n\nexport type ThsResponse = {\n wallet: string;\n score: number;\n realizedPnLUsd: number;\n realizedPnLWeightedUsd: number;\n totals: ThsTotals;\n analyzedTxns: number;\n matchedTxCount: number;\n unmatchedTxCount: number;\n avgHoldTimeDays: number;\n avgHoldTimeHours: number;\n avgHoldTimeMinutes: number;\n avgHoldTimeSeconds: number;\n avgHoldTimePretty: string;\n};\n\nfunction buildUrl(baseUrl: string, path: string): string {\n return `${baseUrl.replace(/\\/+$/, \"\")}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`;\n}\n\nfunction buildWsUrl(\n wsBaseUrl: string,\n path: string,\n query?: Record<string, string | number | boolean | undefined | null>\n): string {\n const url = new URL(buildUrl(wsBaseUrl, path));\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v === undefined || v === null) continue;\n url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n}\n\nfunction safeJsonParse(payload: string): unknown {\n try {\n return JSON.parse(payload) as unknown;\n } catch {\n return payload;\n }\n}\n\nfunction isNodeRuntime(): boolean {\n return (\n typeof process !== \"undefined\" &&\n typeof (process as any).versions?.node === \"string\"\n );\n}\n\nfunction messageToString(data: unknown): string | null {\n if (typeof data === \"string\") return data;\n\n // ws (node) can emit Buffer\n if (typeof Buffer !== \"undefined\" && Buffer.isBuffer(data)) {\n return data.toString(\"utf8\");\n }\n\n // browser ws can emit ArrayBuffer\n if (data instanceof ArrayBuffer) {\n return new TextDecoder().decode(new Uint8Array(data));\n }\n\n return null;\n}\n\nexport class DritanClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly wsBaseUrl: string;\n private readonly fetchImpl: typeof fetch;\n private readonly WebSocketCtor: typeof WebSocketImpl;\n\n constructor(options: DritanClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = options.baseUrl ?? \"https://us-east.dritan.dev\";\n this.wsBaseUrl = options.wsBaseUrl ?? \"wss://us-east.dritan.dev\";\n this.fetchImpl = options.fetch ?? fetch;\n this.WebSocketCtor = options.WebSocket ?? WebSocketImpl;\n }\n\n async getTokenPrice(mint: string): Promise<TokenPriceResponse> {\n const url = buildUrl(this.baseUrl, `/token/price/${encodeURIComponent(mint)}`);\n const res = await this.fetchImpl(url, {\n method: \"GET\",\n headers: {\n \"x-api-key\": this.apiKey\n }\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as TokenPriceResponse;\n }\n\n async getTokenMetadata(mint: string): Promise<TokenMetadataResponse> {\n const url = buildUrl(this.baseUrl, `/token/metadata/${encodeURIComponent(mint)}`);\n const res = await this.fetchImpl(url, {\n method: \"GET\",\n headers: {\n \"x-api-key\": this.apiKey\n }\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as TokenMetadataResponse;\n }\n\n async getTokenRisk(mint: string): Promise<TokenRiskResponse> {\n const url = buildUrl(this.baseUrl, `/token/risk/${encodeURIComponent(mint)}`);\n const res = await this.fetchImpl(url, {\n method: \"GET\",\n headers: {\n \"x-api-key\": this.apiKey\n }\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as TokenRiskResponse;\n }\n\n async getFirstBuyers(mint: string): Promise<TokenFirstBuyersResponse> {\n const url = buildUrl(this.baseUrl, `/token/first-buyers/${encodeURIComponent(mint)}`);\n const res = await this.fetchImpl(url, {\n method: \"GET\",\n headers: {\n \"x-api-key\": this.apiKey\n }\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as TokenFirstBuyersResponse;\n }\n\n async getTokenAggregated(mint: string): Promise<TokenAggregatedResponse> {\n const url = buildUrl(this.baseUrl, `/token/aggregated/${encodeURIComponent(mint)}`);\n const res = await this.fetchImpl(url, {\n method: \"GET\",\n headers: {\n \"x-api-key\": this.apiKey\n }\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n const raw = (await res.json()) as any;\n return {\n mint: String(raw?.mint ?? mint),\n price: raw?.price as TokenPriceResponse,\n metadata: raw?.metadata ?? null,\n risk: raw?.risk ?? null,\n bondingCurvePercent:\n raw?.bondingCurvePercent === undefined ? null : (raw?.bondingCurvePercent ?? null)\n };\n }\n\n async buildSwap(body: SwapBuildRequest): Promise<SwapBuildResponse> {\n const url = buildUrl(this.baseUrl, \"/swap/build\");\n const res = await this.fetchImpl(url, {\n method: \"POST\",\n headers: {\n \"x-api-key\": this.apiKey,\n \"content-type\": \"application/json\"\n },\n body: JSON.stringify(body ?? {})\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as SwapBuildResponse;\n }\n\n async broadcastSwap(signedTransactionBase64: string): Promise<SwapBroadcastResponse> {\n const url = buildUrl(this.baseUrl, \"/swap/broadcast\");\n const res = await this.fetchImpl(url, {\n method: \"POST\",\n headers: {\n \"x-api-key\": this.apiKey,\n \"content-type\": \"application/json\"\n },\n body: JSON.stringify({ signedTransactionBase64 })\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as SwapBroadcastResponse;\n }\n\n streamDex(dex: KnownDexStream, options?: DritanStreamOptions): DritanStreamHandle;\n streamDex(dex: string, options?: DritanStreamOptions): DritanStreamHandle;\n streamDex(dex: string, options: DritanStreamOptions = {}): DritanStreamHandle {\n const shouldSendKeyInQuery = options.sendApiKeyInQuery ?? !isNodeRuntime();\n const query = { ...(options.query ?? {}) } as Record<\n string,\n string | number | boolean | undefined | null\n >;\n if (shouldSendKeyInQuery && query.apiKey == null) {\n query.apiKey = this.apiKey;\n }\n\n const url = buildWsUrl(this.wsBaseUrl, `/${dex}`, query);\n const ws = shouldSendKeyInQuery\n ? new this.WebSocketCtor(url)\n : new this.WebSocketCtor(\n url,\n {\n headers: {\n \"x-api-key\": this.apiKey\n }\n } as any\n );\n\n ws.onopen = () => options.onOpen?.();\n ws.onclose = (ev: any) => options.onClose?.(ev as CloseEvent);\n ws.onerror = (ev: any) => options.onError?.(ev as Event);\n ws.onmessage = (msg: any) => {\n const raw = messageToString(msg.data);\n const data = raw ? safeJsonParse(raw) : msg.data;\n options.onMessage?.(data);\n };\n\n return {\n socket: ws as unknown as WebSocket,\n close: () => ws.close()\n };\n }\n}\n\nexport const createClient = (options: DritanClientOptions) => new DritanClient(options);\n\nexport class MeteoraThsClient {\n readonly baseUrl: string;\n private readonly fetchImpl: typeof fetch;\n\n constructor(options: MeteoraThsClientOptions = {}) {\n this.baseUrl = options.baseUrl ?? \"https://ths.dritan.dev\";\n this.fetchImpl = options.fetch ?? fetch;\n }\n\n async health(): Promise<boolean> {\n const url = buildUrl(this.baseUrl, \"/health\");\n const res = await this.fetchImpl(url, { method: \"GET\" });\n return res.ok;\n }\n\n async getThsScore(\n wallet: string,\n options: { debug?: boolean; breakdown?: boolean } = {}\n ): Promise<ThsResponse> {\n const url = new URL(buildUrl(this.baseUrl, `/ths/${encodeURIComponent(wallet)}`));\n if (options.debug) url.searchParams.set(\"debug\", \"1\");\n if (options.breakdown) url.searchParams.set(\"breakdown\", \"1\");\n\n const res = await this.fetchImpl(url.toString(), { method: \"GET\" });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as ThsResponse;\n }\n\n async getThsScoreForTokens(\n wallet: string,\n tokenMints: string[],\n options: { debug?: boolean; breakdown?: boolean } = {}\n ): Promise<ThsResponse> {\n const url = new URL(buildUrl(this.baseUrl, `/ths/${encodeURIComponent(wallet)}/tokens`));\n for (const mint of tokenMints ?? []) {\n url.searchParams.append(\"tokenMints\", mint);\n }\n if (options.debug) url.searchParams.set(\"debug\", \"1\");\n if (options.breakdown) url.searchParams.set(\"breakdown\", \"1\");\n\n const res = await this.fetchImpl(url.toString(), { method: \"GET\" });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as ThsResponse;\n }\n\n async postThsScoreForTokens(\n wallet: string,\n tokenMints: string[],\n options: { debug?: boolean; breakdown?: boolean } = {}\n ): Promise<ThsResponse> {\n const url = new URL(buildUrl(this.baseUrl, `/ths/${encodeURIComponent(wallet)}/tokens`));\n if (options.debug) url.searchParams.set(\"debug\", \"1\");\n if (options.breakdown) url.searchParams.set(\"breakdown\", \"1\");\n\n const res = await this.fetchImpl(url.toString(), {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ tokenMints: tokenMints ?? [] })\n });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as ThsResponse;\n }\n}\n\nexport const createMeteoraThsClient = (options?: MeteoraThsClientOptions) =>\n new MeteoraThsClient(options);\n"]}
@@ -0,0 +1,154 @@
1
+ import WebSocketImpl from 'isomorphic-ws';
2
+
3
+ type DritanClientOptions = {
4
+ apiKey: string;
5
+ baseUrl?: string;
6
+ wsBaseUrl?: string;
7
+ fetch?: typeof fetch;
8
+ WebSocket?: typeof WebSocketImpl;
9
+ };
10
+ type KnownDexStream = "pumpamm" | "pumpfun" | "launchlab" | "dlmm" | "damm2" | "damm1" | "dbc";
11
+ type MeteoraThsClientOptions = {
12
+ baseUrl?: string;
13
+ fetch?: typeof fetch;
14
+ };
15
+ type TokenPriceResponse = {
16
+ mint: string;
17
+ dex: string;
18
+ priceUsd: number;
19
+ marketCap: number | null;
20
+ liquiditySol: number | null;
21
+ };
22
+ type TokenMetadataResponse = {
23
+ mint: string;
24
+ programId: string;
25
+ name: string;
26
+ symbol: string;
27
+ uri: string;
28
+ decimals: number;
29
+ supply: string;
30
+ };
31
+ type RiskGroup = {
32
+ count: number;
33
+ totalPercentage: number;
34
+ };
35
+ type TokenRiskResponse = {
36
+ mint: string;
37
+ globalFeesPaid: number;
38
+ bundlers: RiskGroup;
39
+ insiders: RiskGroup;
40
+ snipers: RiskGroup;
41
+ top10: number;
42
+ devPercentage: number | null;
43
+ };
44
+ type TokenFirstBuyersResponse = {
45
+ mint: string;
46
+ buyers: unknown;
47
+ };
48
+ type TokenAggregatedResponse = {
49
+ mint: string;
50
+ price: TokenPriceResponse;
51
+ metadata: TokenMetadataResponse | null;
52
+ risk: TokenRiskResponse | null;
53
+ bondingCurvePercent: number | null;
54
+ };
55
+ type DritanStreamOptions = {
56
+ query?: Record<string, string | number | boolean | undefined | null>;
57
+ /**
58
+ * When true, includes the api key as `?apiKey=...` in the websocket URL.
59
+ * This is required when using native browser websockets (custom headers are not supported).
60
+ */
61
+ sendApiKeyInQuery?: boolean;
62
+ onOpen?: () => void;
63
+ onClose?: (ev: CloseEvent) => void;
64
+ onError?: (ev: Event) => void;
65
+ onMessage?: (data: unknown) => void;
66
+ };
67
+ type DritanStreamHandle = {
68
+ socket: WebSocket;
69
+ close: () => void;
70
+ };
71
+ type SwapBuildRequest = {
72
+ userPublicKey: string;
73
+ inputMint: string;
74
+ outputMint: string;
75
+ amount: number | string;
76
+ slippageBps?: number;
77
+ swapType?: string;
78
+ feeWallet?: string;
79
+ feeBps?: number;
80
+ feePercent?: number;
81
+ };
82
+ type SwapBuildFees = {
83
+ platformFeeBps: number;
84
+ platformFeeLamports: number;
85
+ userFeeBps: number;
86
+ userFeeLamports: number;
87
+ tipLamports: number;
88
+ };
89
+ type SwapBuildResponse = {
90
+ transactionBase64: string;
91
+ fees: SwapBuildFees;
92
+ quote: unknown;
93
+ };
94
+ type SwapBroadcastResponse = {
95
+ signature: string;
96
+ };
97
+ type ThsTotals = {
98
+ buys: number;
99
+ sells: number;
100
+ };
101
+ type ThsResponse = {
102
+ wallet: string;
103
+ score: number;
104
+ realizedPnLUsd: number;
105
+ realizedPnLWeightedUsd: number;
106
+ totals: ThsTotals;
107
+ analyzedTxns: number;
108
+ matchedTxCount: number;
109
+ unmatchedTxCount: number;
110
+ avgHoldTimeDays: number;
111
+ avgHoldTimeHours: number;
112
+ avgHoldTimeMinutes: number;
113
+ avgHoldTimeSeconds: number;
114
+ avgHoldTimePretty: string;
115
+ };
116
+ declare class DritanClient {
117
+ readonly apiKey: string;
118
+ readonly baseUrl: string;
119
+ readonly wsBaseUrl: string;
120
+ private readonly fetchImpl;
121
+ private readonly WebSocketCtor;
122
+ constructor(options: DritanClientOptions);
123
+ getTokenPrice(mint: string): Promise<TokenPriceResponse>;
124
+ getTokenMetadata(mint: string): Promise<TokenMetadataResponse>;
125
+ getTokenRisk(mint: string): Promise<TokenRiskResponse>;
126
+ getFirstBuyers(mint: string): Promise<TokenFirstBuyersResponse>;
127
+ getTokenAggregated(mint: string): Promise<TokenAggregatedResponse>;
128
+ buildSwap(body: SwapBuildRequest): Promise<SwapBuildResponse>;
129
+ broadcastSwap(signedTransactionBase64: string): Promise<SwapBroadcastResponse>;
130
+ streamDex(dex: KnownDexStream, options?: DritanStreamOptions): DritanStreamHandle;
131
+ streamDex(dex: string, options?: DritanStreamOptions): DritanStreamHandle;
132
+ }
133
+ declare const createClient: (options: DritanClientOptions) => DritanClient;
134
+ declare class MeteoraThsClient {
135
+ readonly baseUrl: string;
136
+ private readonly fetchImpl;
137
+ constructor(options?: MeteoraThsClientOptions);
138
+ health(): Promise<boolean>;
139
+ getThsScore(wallet: string, options?: {
140
+ debug?: boolean;
141
+ breakdown?: boolean;
142
+ }): Promise<ThsResponse>;
143
+ getThsScoreForTokens(wallet: string, tokenMints: string[], options?: {
144
+ debug?: boolean;
145
+ breakdown?: boolean;
146
+ }): Promise<ThsResponse>;
147
+ postThsScoreForTokens(wallet: string, tokenMints: string[], options?: {
148
+ debug?: boolean;
149
+ breakdown?: boolean;
150
+ }): Promise<ThsResponse>;
151
+ }
152
+ declare const createMeteoraThsClient: (options?: MeteoraThsClientOptions) => MeteoraThsClient;
153
+
154
+ export { DritanClient, type DritanClientOptions, type DritanStreamHandle, type DritanStreamOptions, type KnownDexStream, MeteoraThsClient, type MeteoraThsClientOptions, type RiskGroup, type SwapBroadcastResponse, type SwapBuildFees, type SwapBuildRequest, type SwapBuildResponse, type ThsResponse, type ThsTotals, type TokenAggregatedResponse, type TokenFirstBuyersResponse, type TokenMetadataResponse, type TokenPriceResponse, type TokenRiskResponse, createClient, createMeteoraThsClient };
@@ -0,0 +1,154 @@
1
+ import WebSocketImpl from 'isomorphic-ws';
2
+
3
+ type DritanClientOptions = {
4
+ apiKey: string;
5
+ baseUrl?: string;
6
+ wsBaseUrl?: string;
7
+ fetch?: typeof fetch;
8
+ WebSocket?: typeof WebSocketImpl;
9
+ };
10
+ type KnownDexStream = "pumpamm" | "pumpfun" | "launchlab" | "dlmm" | "damm2" | "damm1" | "dbc";
11
+ type MeteoraThsClientOptions = {
12
+ baseUrl?: string;
13
+ fetch?: typeof fetch;
14
+ };
15
+ type TokenPriceResponse = {
16
+ mint: string;
17
+ dex: string;
18
+ priceUsd: number;
19
+ marketCap: number | null;
20
+ liquiditySol: number | null;
21
+ };
22
+ type TokenMetadataResponse = {
23
+ mint: string;
24
+ programId: string;
25
+ name: string;
26
+ symbol: string;
27
+ uri: string;
28
+ decimals: number;
29
+ supply: string;
30
+ };
31
+ type RiskGroup = {
32
+ count: number;
33
+ totalPercentage: number;
34
+ };
35
+ type TokenRiskResponse = {
36
+ mint: string;
37
+ globalFeesPaid: number;
38
+ bundlers: RiskGroup;
39
+ insiders: RiskGroup;
40
+ snipers: RiskGroup;
41
+ top10: number;
42
+ devPercentage: number | null;
43
+ };
44
+ type TokenFirstBuyersResponse = {
45
+ mint: string;
46
+ buyers: unknown;
47
+ };
48
+ type TokenAggregatedResponse = {
49
+ mint: string;
50
+ price: TokenPriceResponse;
51
+ metadata: TokenMetadataResponse | null;
52
+ risk: TokenRiskResponse | null;
53
+ bondingCurvePercent: number | null;
54
+ };
55
+ type DritanStreamOptions = {
56
+ query?: Record<string, string | number | boolean | undefined | null>;
57
+ /**
58
+ * When true, includes the api key as `?apiKey=...` in the websocket URL.
59
+ * This is required when using native browser websockets (custom headers are not supported).
60
+ */
61
+ sendApiKeyInQuery?: boolean;
62
+ onOpen?: () => void;
63
+ onClose?: (ev: CloseEvent) => void;
64
+ onError?: (ev: Event) => void;
65
+ onMessage?: (data: unknown) => void;
66
+ };
67
+ type DritanStreamHandle = {
68
+ socket: WebSocket;
69
+ close: () => void;
70
+ };
71
+ type SwapBuildRequest = {
72
+ userPublicKey: string;
73
+ inputMint: string;
74
+ outputMint: string;
75
+ amount: number | string;
76
+ slippageBps?: number;
77
+ swapType?: string;
78
+ feeWallet?: string;
79
+ feeBps?: number;
80
+ feePercent?: number;
81
+ };
82
+ type SwapBuildFees = {
83
+ platformFeeBps: number;
84
+ platformFeeLamports: number;
85
+ userFeeBps: number;
86
+ userFeeLamports: number;
87
+ tipLamports: number;
88
+ };
89
+ type SwapBuildResponse = {
90
+ transactionBase64: string;
91
+ fees: SwapBuildFees;
92
+ quote: unknown;
93
+ };
94
+ type SwapBroadcastResponse = {
95
+ signature: string;
96
+ };
97
+ type ThsTotals = {
98
+ buys: number;
99
+ sells: number;
100
+ };
101
+ type ThsResponse = {
102
+ wallet: string;
103
+ score: number;
104
+ realizedPnLUsd: number;
105
+ realizedPnLWeightedUsd: number;
106
+ totals: ThsTotals;
107
+ analyzedTxns: number;
108
+ matchedTxCount: number;
109
+ unmatchedTxCount: number;
110
+ avgHoldTimeDays: number;
111
+ avgHoldTimeHours: number;
112
+ avgHoldTimeMinutes: number;
113
+ avgHoldTimeSeconds: number;
114
+ avgHoldTimePretty: string;
115
+ };
116
+ declare class DritanClient {
117
+ readonly apiKey: string;
118
+ readonly baseUrl: string;
119
+ readonly wsBaseUrl: string;
120
+ private readonly fetchImpl;
121
+ private readonly WebSocketCtor;
122
+ constructor(options: DritanClientOptions);
123
+ getTokenPrice(mint: string): Promise<TokenPriceResponse>;
124
+ getTokenMetadata(mint: string): Promise<TokenMetadataResponse>;
125
+ getTokenRisk(mint: string): Promise<TokenRiskResponse>;
126
+ getFirstBuyers(mint: string): Promise<TokenFirstBuyersResponse>;
127
+ getTokenAggregated(mint: string): Promise<TokenAggregatedResponse>;
128
+ buildSwap(body: SwapBuildRequest): Promise<SwapBuildResponse>;
129
+ broadcastSwap(signedTransactionBase64: string): Promise<SwapBroadcastResponse>;
130
+ streamDex(dex: KnownDexStream, options?: DritanStreamOptions): DritanStreamHandle;
131
+ streamDex(dex: string, options?: DritanStreamOptions): DritanStreamHandle;
132
+ }
133
+ declare const createClient: (options: DritanClientOptions) => DritanClient;
134
+ declare class MeteoraThsClient {
135
+ readonly baseUrl: string;
136
+ private readonly fetchImpl;
137
+ constructor(options?: MeteoraThsClientOptions);
138
+ health(): Promise<boolean>;
139
+ getThsScore(wallet: string, options?: {
140
+ debug?: boolean;
141
+ breakdown?: boolean;
142
+ }): Promise<ThsResponse>;
143
+ getThsScoreForTokens(wallet: string, tokenMints: string[], options?: {
144
+ debug?: boolean;
145
+ breakdown?: boolean;
146
+ }): Promise<ThsResponse>;
147
+ postThsScoreForTokens(wallet: string, tokenMints: string[], options?: {
148
+ debug?: boolean;
149
+ breakdown?: boolean;
150
+ }): Promise<ThsResponse>;
151
+ }
152
+ declare const createMeteoraThsClient: (options?: MeteoraThsClientOptions) => MeteoraThsClient;
153
+
154
+ export { DritanClient, type DritanClientOptions, type DritanStreamHandle, type DritanStreamOptions, type KnownDexStream, MeteoraThsClient, type MeteoraThsClientOptions, type RiskGroup, type SwapBroadcastResponse, type SwapBuildFees, type SwapBuildRequest, type SwapBuildResponse, type ThsResponse, type ThsTotals, type TokenAggregatedResponse, type TokenFirstBuyersResponse, type TokenMetadataResponse, type TokenPriceResponse, type TokenRiskResponse, createClient, createMeteoraThsClient };
package/dist/index.js ADDED
@@ -0,0 +1,246 @@
1
+ import WebSocketImpl from 'isomorphic-ws';
2
+
3
+ // src/index.ts
4
+ function buildUrl(baseUrl, path) {
5
+ return `${baseUrl.replace(/\/+$/, "")}${path.startsWith("/") ? "" : "/"}${path}`;
6
+ }
7
+ function buildWsUrl(wsBaseUrl, path, query) {
8
+ const url = new URL(buildUrl(wsBaseUrl, path));
9
+ if (query) {
10
+ for (const [k, v] of Object.entries(query)) {
11
+ if (v === void 0 || v === null) continue;
12
+ url.searchParams.set(k, String(v));
13
+ }
14
+ }
15
+ return url.toString();
16
+ }
17
+ function safeJsonParse(payload) {
18
+ try {
19
+ return JSON.parse(payload);
20
+ } catch {
21
+ return payload;
22
+ }
23
+ }
24
+ function isNodeRuntime() {
25
+ return typeof process !== "undefined" && typeof process.versions?.node === "string";
26
+ }
27
+ function messageToString(data) {
28
+ if (typeof data === "string") return data;
29
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
30
+ return data.toString("utf8");
31
+ }
32
+ if (data instanceof ArrayBuffer) {
33
+ return new TextDecoder().decode(new Uint8Array(data));
34
+ }
35
+ return null;
36
+ }
37
+ var DritanClient = class {
38
+ apiKey;
39
+ baseUrl;
40
+ wsBaseUrl;
41
+ fetchImpl;
42
+ WebSocketCtor;
43
+ constructor(options) {
44
+ this.apiKey = options.apiKey;
45
+ this.baseUrl = options.baseUrl ?? "https://us-east.dritan.dev";
46
+ this.wsBaseUrl = options.wsBaseUrl ?? "wss://us-east.dritan.dev";
47
+ this.fetchImpl = options.fetch ?? fetch;
48
+ this.WebSocketCtor = options.WebSocket ?? WebSocketImpl;
49
+ }
50
+ async getTokenPrice(mint) {
51
+ const url = buildUrl(this.baseUrl, `/token/price/${encodeURIComponent(mint)}`);
52
+ const res = await this.fetchImpl(url, {
53
+ method: "GET",
54
+ headers: {
55
+ "x-api-key": this.apiKey
56
+ }
57
+ });
58
+ if (!res.ok) {
59
+ const text = await res.text().catch(() => "");
60
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
61
+ }
62
+ return await res.json();
63
+ }
64
+ async getTokenMetadata(mint) {
65
+ const url = buildUrl(this.baseUrl, `/token/metadata/${encodeURIComponent(mint)}`);
66
+ const res = await this.fetchImpl(url, {
67
+ method: "GET",
68
+ headers: {
69
+ "x-api-key": this.apiKey
70
+ }
71
+ });
72
+ if (!res.ok) {
73
+ const text = await res.text().catch(() => "");
74
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
75
+ }
76
+ return await res.json();
77
+ }
78
+ async getTokenRisk(mint) {
79
+ const url = buildUrl(this.baseUrl, `/token/risk/${encodeURIComponent(mint)}`);
80
+ const res = await this.fetchImpl(url, {
81
+ method: "GET",
82
+ headers: {
83
+ "x-api-key": this.apiKey
84
+ }
85
+ });
86
+ if (!res.ok) {
87
+ const text = await res.text().catch(() => "");
88
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
89
+ }
90
+ return await res.json();
91
+ }
92
+ async getFirstBuyers(mint) {
93
+ const url = buildUrl(this.baseUrl, `/token/first-buyers/${encodeURIComponent(mint)}`);
94
+ const res = await this.fetchImpl(url, {
95
+ method: "GET",
96
+ headers: {
97
+ "x-api-key": this.apiKey
98
+ }
99
+ });
100
+ if (!res.ok) {
101
+ const text = await res.text().catch(() => "");
102
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
103
+ }
104
+ return await res.json();
105
+ }
106
+ async getTokenAggregated(mint) {
107
+ const url = buildUrl(this.baseUrl, `/token/aggregated/${encodeURIComponent(mint)}`);
108
+ const res = await this.fetchImpl(url, {
109
+ method: "GET",
110
+ headers: {
111
+ "x-api-key": this.apiKey
112
+ }
113
+ });
114
+ if (!res.ok) {
115
+ const text = await res.text().catch(() => "");
116
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
117
+ }
118
+ const raw = await res.json();
119
+ return {
120
+ mint: String(raw?.mint ?? mint),
121
+ price: raw?.price,
122
+ metadata: raw?.metadata ?? null,
123
+ risk: raw?.risk ?? null,
124
+ bondingCurvePercent: raw?.bondingCurvePercent === void 0 ? null : raw?.bondingCurvePercent ?? null
125
+ };
126
+ }
127
+ async buildSwap(body) {
128
+ const url = buildUrl(this.baseUrl, "/swap/build");
129
+ const res = await this.fetchImpl(url, {
130
+ method: "POST",
131
+ headers: {
132
+ "x-api-key": this.apiKey,
133
+ "content-type": "application/json"
134
+ },
135
+ body: JSON.stringify(body ?? {})
136
+ });
137
+ if (!res.ok) {
138
+ const text = await res.text().catch(() => "");
139
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
140
+ }
141
+ return await res.json();
142
+ }
143
+ async broadcastSwap(signedTransactionBase64) {
144
+ const url = buildUrl(this.baseUrl, "/swap/broadcast");
145
+ const res = await this.fetchImpl(url, {
146
+ method: "POST",
147
+ headers: {
148
+ "x-api-key": this.apiKey,
149
+ "content-type": "application/json"
150
+ },
151
+ body: JSON.stringify({ signedTransactionBase64 })
152
+ });
153
+ if (!res.ok) {
154
+ const text = await res.text().catch(() => "");
155
+ throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);
156
+ }
157
+ return await res.json();
158
+ }
159
+ streamDex(dex, options = {}) {
160
+ const shouldSendKeyInQuery = options.sendApiKeyInQuery ?? !isNodeRuntime();
161
+ const query = { ...options.query ?? {} };
162
+ if (shouldSendKeyInQuery && query.apiKey == null) {
163
+ query.apiKey = this.apiKey;
164
+ }
165
+ const url = buildWsUrl(this.wsBaseUrl, `/${dex}`, query);
166
+ const ws = shouldSendKeyInQuery ? new this.WebSocketCtor(url) : new this.WebSocketCtor(
167
+ url,
168
+ {
169
+ headers: {
170
+ "x-api-key": this.apiKey
171
+ }
172
+ }
173
+ );
174
+ ws.onopen = () => options.onOpen?.();
175
+ ws.onclose = (ev) => options.onClose?.(ev);
176
+ ws.onerror = (ev) => options.onError?.(ev);
177
+ ws.onmessage = (msg) => {
178
+ const raw = messageToString(msg.data);
179
+ const data = raw ? safeJsonParse(raw) : msg.data;
180
+ options.onMessage?.(data);
181
+ };
182
+ return {
183
+ socket: ws,
184
+ close: () => ws.close()
185
+ };
186
+ }
187
+ };
188
+ var createClient = (options) => new DritanClient(options);
189
+ var MeteoraThsClient = class {
190
+ baseUrl;
191
+ fetchImpl;
192
+ constructor(options = {}) {
193
+ this.baseUrl = options.baseUrl ?? "https://ths.dritan.dev";
194
+ this.fetchImpl = options.fetch ?? fetch;
195
+ }
196
+ async health() {
197
+ const url = buildUrl(this.baseUrl, "/health");
198
+ const res = await this.fetchImpl(url, { method: "GET" });
199
+ return res.ok;
200
+ }
201
+ async getThsScore(wallet, options = {}) {
202
+ const url = new URL(buildUrl(this.baseUrl, `/ths/${encodeURIComponent(wallet)}`));
203
+ if (options.debug) url.searchParams.set("debug", "1");
204
+ if (options.breakdown) url.searchParams.set("breakdown", "1");
205
+ const res = await this.fetchImpl(url.toString(), { method: "GET" });
206
+ if (!res.ok) {
207
+ const text = await res.text().catch(() => "");
208
+ throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);
209
+ }
210
+ return await res.json();
211
+ }
212
+ async getThsScoreForTokens(wallet, tokenMints, options = {}) {
213
+ const url = new URL(buildUrl(this.baseUrl, `/ths/${encodeURIComponent(wallet)}/tokens`));
214
+ for (const mint of tokenMints ?? []) {
215
+ url.searchParams.append("tokenMints", mint);
216
+ }
217
+ if (options.debug) url.searchParams.set("debug", "1");
218
+ if (options.breakdown) url.searchParams.set("breakdown", "1");
219
+ const res = await this.fetchImpl(url.toString(), { method: "GET" });
220
+ if (!res.ok) {
221
+ const text = await res.text().catch(() => "");
222
+ throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);
223
+ }
224
+ return await res.json();
225
+ }
226
+ async postThsScoreForTokens(wallet, tokenMints, options = {}) {
227
+ const url = new URL(buildUrl(this.baseUrl, `/ths/${encodeURIComponent(wallet)}/tokens`));
228
+ if (options.debug) url.searchParams.set("debug", "1");
229
+ if (options.breakdown) url.searchParams.set("breakdown", "1");
230
+ const res = await this.fetchImpl(url.toString(), {
231
+ method: "POST",
232
+ headers: { "content-type": "application/json" },
233
+ body: JSON.stringify({ tokenMints: tokenMints ?? [] })
234
+ });
235
+ if (!res.ok) {
236
+ const text = await res.text().catch(() => "");
237
+ throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);
238
+ }
239
+ return await res.json();
240
+ }
241
+ };
242
+ var createMeteoraThsClient = (options) => new MeteoraThsClient(options);
243
+
244
+ export { DritanClient, MeteoraThsClient, createClient, createMeteoraThsClient };
245
+ //# sourceMappingURL=index.js.map
246
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import WebSocketImpl from \"isomorphic-ws\";\n\nexport type DritanClientOptions = {\n apiKey: string;\n baseUrl?: string;\n wsBaseUrl?: string;\n fetch?: typeof fetch;\n WebSocket?: typeof WebSocketImpl;\n};\n\nexport type KnownDexStream =\n | \"pumpamm\"\n | \"pumpfun\"\n | \"launchlab\"\n | \"dlmm\"\n | \"damm2\"\n | \"damm1\"\n | \"dbc\";\n\nexport type MeteoraThsClientOptions = {\n baseUrl?: string;\n fetch?: typeof fetch;\n};\n\nexport type TokenPriceResponse = {\n mint: string;\n dex: string;\n priceUsd: number;\n marketCap: number | null;\n liquiditySol: number | null;\n};\n\nexport type TokenMetadataResponse = {\n mint: string;\n programId: string;\n name: string;\n symbol: string;\n uri: string;\n decimals: number;\n supply: string;\n};\n\nexport type RiskGroup = {\n count: number;\n totalPercentage: number;\n};\n\nexport type TokenRiskResponse = {\n mint: string;\n globalFeesPaid: number;\n bundlers: RiskGroup;\n insiders: RiskGroup;\n snipers: RiskGroup;\n top10: number;\n devPercentage: number | null;\n};\n\nexport type TokenFirstBuyersResponse = {\n mint: string;\n buyers: unknown;\n};\n\nexport type TokenAggregatedResponse = {\n mint: string;\n price: TokenPriceResponse;\n metadata: TokenMetadataResponse | null;\n risk: TokenRiskResponse | null;\n bondingCurvePercent: number | null;\n};\n\nexport type DritanStreamOptions = {\n query?: Record<string, string | number | boolean | undefined | null>;\n /**\n * When true, includes the api key as `?apiKey=...` in the websocket URL.\n * This is required when using native browser websockets (custom headers are not supported).\n */\n sendApiKeyInQuery?: boolean;\n onOpen?: () => void;\n onClose?: (ev: CloseEvent) => void;\n onError?: (ev: Event) => void;\n onMessage?: (data: unknown) => void;\n};\n\nexport type DritanStreamHandle = {\n socket: WebSocket;\n close: () => void;\n};\n\nexport type SwapBuildRequest = {\n userPublicKey: string;\n inputMint: string;\n outputMint: string;\n amount: number | string;\n slippageBps?: number;\n swapType?: string;\n feeWallet?: string;\n feeBps?: number;\n feePercent?: number;\n};\n\nexport type SwapBuildFees = {\n platformFeeBps: number;\n platformFeeLamports: number;\n userFeeBps: number;\n userFeeLamports: number;\n tipLamports: number;\n};\n\nexport type SwapBuildResponse = {\n transactionBase64: string;\n fees: SwapBuildFees;\n quote: unknown;\n};\n\nexport type SwapBroadcastResponse = {\n signature: string;\n};\n\nexport type ThsTotals = {\n buys: number;\n sells: number;\n};\n\nexport type ThsResponse = {\n wallet: string;\n score: number;\n realizedPnLUsd: number;\n realizedPnLWeightedUsd: number;\n totals: ThsTotals;\n analyzedTxns: number;\n matchedTxCount: number;\n unmatchedTxCount: number;\n avgHoldTimeDays: number;\n avgHoldTimeHours: number;\n avgHoldTimeMinutes: number;\n avgHoldTimeSeconds: number;\n avgHoldTimePretty: string;\n};\n\nfunction buildUrl(baseUrl: string, path: string): string {\n return `${baseUrl.replace(/\\/+$/, \"\")}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`;\n}\n\nfunction buildWsUrl(\n wsBaseUrl: string,\n path: string,\n query?: Record<string, string | number | boolean | undefined | null>\n): string {\n const url = new URL(buildUrl(wsBaseUrl, path));\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v === undefined || v === null) continue;\n url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n}\n\nfunction safeJsonParse(payload: string): unknown {\n try {\n return JSON.parse(payload) as unknown;\n } catch {\n return payload;\n }\n}\n\nfunction isNodeRuntime(): boolean {\n return (\n typeof process !== \"undefined\" &&\n typeof (process as any).versions?.node === \"string\"\n );\n}\n\nfunction messageToString(data: unknown): string | null {\n if (typeof data === \"string\") return data;\n\n // ws (node) can emit Buffer\n if (typeof Buffer !== \"undefined\" && Buffer.isBuffer(data)) {\n return data.toString(\"utf8\");\n }\n\n // browser ws can emit ArrayBuffer\n if (data instanceof ArrayBuffer) {\n return new TextDecoder().decode(new Uint8Array(data));\n }\n\n return null;\n}\n\nexport class DritanClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly wsBaseUrl: string;\n private readonly fetchImpl: typeof fetch;\n private readonly WebSocketCtor: typeof WebSocketImpl;\n\n constructor(options: DritanClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = options.baseUrl ?? \"https://us-east.dritan.dev\";\n this.wsBaseUrl = options.wsBaseUrl ?? \"wss://us-east.dritan.dev\";\n this.fetchImpl = options.fetch ?? fetch;\n this.WebSocketCtor = options.WebSocket ?? WebSocketImpl;\n }\n\n async getTokenPrice(mint: string): Promise<TokenPriceResponse> {\n const url = buildUrl(this.baseUrl, `/token/price/${encodeURIComponent(mint)}`);\n const res = await this.fetchImpl(url, {\n method: \"GET\",\n headers: {\n \"x-api-key\": this.apiKey\n }\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as TokenPriceResponse;\n }\n\n async getTokenMetadata(mint: string): Promise<TokenMetadataResponse> {\n const url = buildUrl(this.baseUrl, `/token/metadata/${encodeURIComponent(mint)}`);\n const res = await this.fetchImpl(url, {\n method: \"GET\",\n headers: {\n \"x-api-key\": this.apiKey\n }\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as TokenMetadataResponse;\n }\n\n async getTokenRisk(mint: string): Promise<TokenRiskResponse> {\n const url = buildUrl(this.baseUrl, `/token/risk/${encodeURIComponent(mint)}`);\n const res = await this.fetchImpl(url, {\n method: \"GET\",\n headers: {\n \"x-api-key\": this.apiKey\n }\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as TokenRiskResponse;\n }\n\n async getFirstBuyers(mint: string): Promise<TokenFirstBuyersResponse> {\n const url = buildUrl(this.baseUrl, `/token/first-buyers/${encodeURIComponent(mint)}`);\n const res = await this.fetchImpl(url, {\n method: \"GET\",\n headers: {\n \"x-api-key\": this.apiKey\n }\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as TokenFirstBuyersResponse;\n }\n\n async getTokenAggregated(mint: string): Promise<TokenAggregatedResponse> {\n const url = buildUrl(this.baseUrl, `/token/aggregated/${encodeURIComponent(mint)}`);\n const res = await this.fetchImpl(url, {\n method: \"GET\",\n headers: {\n \"x-api-key\": this.apiKey\n }\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n const raw = (await res.json()) as any;\n return {\n mint: String(raw?.mint ?? mint),\n price: raw?.price as TokenPriceResponse,\n metadata: raw?.metadata ?? null,\n risk: raw?.risk ?? null,\n bondingCurvePercent:\n raw?.bondingCurvePercent === undefined ? null : (raw?.bondingCurvePercent ?? null)\n };\n }\n\n async buildSwap(body: SwapBuildRequest): Promise<SwapBuildResponse> {\n const url = buildUrl(this.baseUrl, \"/swap/build\");\n const res = await this.fetchImpl(url, {\n method: \"POST\",\n headers: {\n \"x-api-key\": this.apiKey,\n \"content-type\": \"application/json\"\n },\n body: JSON.stringify(body ?? {})\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as SwapBuildResponse;\n }\n\n async broadcastSwap(signedTransactionBase64: string): Promise<SwapBroadcastResponse> {\n const url = buildUrl(this.baseUrl, \"/swap/broadcast\");\n const res = await this.fetchImpl(url, {\n method: \"POST\",\n headers: {\n \"x-api-key\": this.apiKey,\n \"content-type\": \"application/json\"\n },\n body: JSON.stringify({ signedTransactionBase64 })\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Dritan request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as SwapBroadcastResponse;\n }\n\n streamDex(dex: KnownDexStream, options?: DritanStreamOptions): DritanStreamHandle;\n streamDex(dex: string, options?: DritanStreamOptions): DritanStreamHandle;\n streamDex(dex: string, options: DritanStreamOptions = {}): DritanStreamHandle {\n const shouldSendKeyInQuery = options.sendApiKeyInQuery ?? !isNodeRuntime();\n const query = { ...(options.query ?? {}) } as Record<\n string,\n string | number | boolean | undefined | null\n >;\n if (shouldSendKeyInQuery && query.apiKey == null) {\n query.apiKey = this.apiKey;\n }\n\n const url = buildWsUrl(this.wsBaseUrl, `/${dex}`, query);\n const ws = shouldSendKeyInQuery\n ? new this.WebSocketCtor(url)\n : new this.WebSocketCtor(\n url,\n {\n headers: {\n \"x-api-key\": this.apiKey\n }\n } as any\n );\n\n ws.onopen = () => options.onOpen?.();\n ws.onclose = (ev: any) => options.onClose?.(ev as CloseEvent);\n ws.onerror = (ev: any) => options.onError?.(ev as Event);\n ws.onmessage = (msg: any) => {\n const raw = messageToString(msg.data);\n const data = raw ? safeJsonParse(raw) : msg.data;\n options.onMessage?.(data);\n };\n\n return {\n socket: ws as unknown as WebSocket,\n close: () => ws.close()\n };\n }\n}\n\nexport const createClient = (options: DritanClientOptions) => new DritanClient(options);\n\nexport class MeteoraThsClient {\n readonly baseUrl: string;\n private readonly fetchImpl: typeof fetch;\n\n constructor(options: MeteoraThsClientOptions = {}) {\n this.baseUrl = options.baseUrl ?? \"https://ths.dritan.dev\";\n this.fetchImpl = options.fetch ?? fetch;\n }\n\n async health(): Promise<boolean> {\n const url = buildUrl(this.baseUrl, \"/health\");\n const res = await this.fetchImpl(url, { method: \"GET\" });\n return res.ok;\n }\n\n async getThsScore(\n wallet: string,\n options: { debug?: boolean; breakdown?: boolean } = {}\n ): Promise<ThsResponse> {\n const url = new URL(buildUrl(this.baseUrl, `/ths/${encodeURIComponent(wallet)}`));\n if (options.debug) url.searchParams.set(\"debug\", \"1\");\n if (options.breakdown) url.searchParams.set(\"breakdown\", \"1\");\n\n const res = await this.fetchImpl(url.toString(), { method: \"GET\" });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as ThsResponse;\n }\n\n async getThsScoreForTokens(\n wallet: string,\n tokenMints: string[],\n options: { debug?: boolean; breakdown?: boolean } = {}\n ): Promise<ThsResponse> {\n const url = new URL(buildUrl(this.baseUrl, `/ths/${encodeURIComponent(wallet)}/tokens`));\n for (const mint of tokenMints ?? []) {\n url.searchParams.append(\"tokenMints\", mint);\n }\n if (options.debug) url.searchParams.set(\"debug\", \"1\");\n if (options.breakdown) url.searchParams.set(\"breakdown\", \"1\");\n\n const res = await this.fetchImpl(url.toString(), { method: \"GET\" });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as ThsResponse;\n }\n\n async postThsScoreForTokens(\n wallet: string,\n tokenMints: string[],\n options: { debug?: boolean; breakdown?: boolean } = {}\n ): Promise<ThsResponse> {\n const url = new URL(buildUrl(this.baseUrl, `/ths/${encodeURIComponent(wallet)}/tokens`));\n if (options.debug) url.searchParams.set(\"debug\", \"1\");\n if (options.breakdown) url.searchParams.set(\"breakdown\", \"1\");\n\n const res = await this.fetchImpl(url.toString(), {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ tokenMints: tokenMints ?? [] })\n });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`Meteora THS request failed (${res.status}): ${text || res.statusText}`);\n }\n\n return (await res.json()) as ThsResponse;\n }\n}\n\nexport const createMeteoraThsClient = (options?: MeteoraThsClientOptions) =>\n new MeteoraThsClient(options);\n"]}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "dritan-sdk",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript SDK for the Dritan data plane REST API and websocket streams.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/dritan/dritan"
9
+ },
10
+ "homepage": "https://dritan.dev",
11
+ "bugs": {
12
+ "url": "https://dritan.dev"
13
+ },
14
+ "type": "module",
15
+ "main": "./dist/index.cjs",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js",
22
+ "require": "./dist/index.cjs"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "README.md"
28
+ ],
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "dev": "tsup --watch",
32
+ "lint": "tsc -p tsconfig.json --noEmit",
33
+ "prepublishOnly": "npm run build"
34
+ },
35
+ "dependencies": {
36
+ "isomorphic-ws": "^5.0.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^22.14.0",
40
+ "tsup": "^8.0.2",
41
+ "typescript": "^5.8.2"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ }
46
+ }