@surf-ai/sdk 1.0.0-alpha.0 → 1.0.0-alpha.2

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.
@@ -5,9 +5,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __esm = (fn, res) => function __init() {
9
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
- };
11
8
  var __export = (target, all) => {
12
9
  for (var name in all)
13
10
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -30,7 +27,23 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
27
  ));
31
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
29
 
30
+ // src/server/index.ts
31
+ var server_exports = {};
32
+ __export(server_exports, {
33
+ createServer: () => createServer,
34
+ dataApi: () => dataApi
35
+ });
36
+ module.exports = __toCommonJS(server_exports);
37
+
38
+ // src/server/runtime.ts
39
+ var import_express = __toESM(require("express"), 1);
40
+ var import_cors = __toESM(require("cors"), 1);
41
+ var import_fs2 = __toESM(require("fs"), 1);
42
+ var import_path = __toESM(require("path"), 1);
43
+ var import_croner = require("croner");
44
+
33
45
  // src/core/config.ts
46
+ var DEFAULT_API_BASE_URL = "https://api.ask.surf/gateway/v1";
34
47
  function trimTrailingSlashes(value) {
35
48
  return String(value || "").replace(/\/+$/, "");
36
49
  }
@@ -50,13 +63,9 @@ function requireSurfApiConfig() {
50
63
  function readAdminApiKey() {
51
64
  return process.env.SURF_API_KEY;
52
65
  }
53
- var DEFAULT_API_BASE_URL;
54
- var init_config = __esm({
55
- "src/core/config.ts"() {
56
- "use strict";
57
- DEFAULT_API_BASE_URL = "https://api.ask.surf/gateway/v1";
58
- }
59
- });
66
+
67
+ // src/db/schema-sync.ts
68
+ var import_fs = __toESM(require("fs"), 1);
60
69
 
61
70
  // src/core/transport.ts
62
71
  function sleep(ms) {
@@ -114,47 +123,152 @@ async function postJson(path2, body) {
114
123
  body: body ? JSON.stringify(body) : void 0
115
124
  });
116
125
  }
117
- var init_transport = __esm({
118
- "src/core/transport.ts"() {
119
- "use strict";
120
- init_config();
121
- }
122
- });
123
126
 
124
127
  // src/data/client.ts
125
- var client_exports = {};
126
- __export(client_exports, {
127
- get: () => get,
128
- post: () => post
129
- });
130
128
  async function get(path2, params) {
131
129
  return getJson(path2, params);
132
130
  }
133
131
  async function post(path2, body) {
134
132
  return postJson(path2, body);
135
133
  }
136
- var init_client = __esm({
137
- "src/data/client.ts"() {
138
- "use strict";
139
- init_transport();
140
- }
141
- });
142
134
 
143
- // src/server/index.ts
144
- var server_exports = {};
145
- __export(server_exports, {
146
- createServer: () => createServer,
147
- dataApi: () => dataApi
148
- });
149
- module.exports = __toCommonJS(server_exports);
135
+ // src/db/schema-sync.ts
136
+ var syncing = false;
137
+ async function syncSchema(options) {
138
+ const { schemaPath, retries = 3, retryDelay = 2e3 } = options;
139
+ for (let i = 0; i < retries; i++) {
140
+ try {
141
+ await doSyncSchema(schemaPath);
142
+ return;
143
+ } catch (err) {
144
+ console.error(`DB schema sync attempt ${i + 1}/${retries} failed: ${err.message}`);
145
+ if (i < retries - 1) await new Promise((r) => setTimeout(r, retryDelay * (i + 1)));
146
+ }
147
+ }
148
+ console.error("DB schema sync failed after all retries");
149
+ }
150
+ async function doSyncSchema(schemaPath) {
151
+ if (syncing) return;
152
+ syncing = true;
153
+ try {
154
+ if (!import_fs.default.existsSync(schemaPath)) return;
155
+ let schema;
156
+ if (schemaPath.endsWith(".ts")) {
157
+ try {
158
+ schema = await import(`${schemaPath}?t=${Date.now()}`);
159
+ } catch (err) {
160
+ if (err instanceof SyntaxError) {
161
+ console.log("DB: schema file has syntax error, waiting for next change...");
162
+ return;
163
+ }
164
+ if (err.message.includes("Cannot find module") || err.message.includes("is not a function")) {
165
+ return;
166
+ }
167
+ throw err;
168
+ }
169
+ } else {
170
+ try {
171
+ delete require.cache[require.resolve(schemaPath)];
172
+ } catch {
173
+ }
174
+ try {
175
+ schema = require(schemaPath);
176
+ } catch (err) {
177
+ if (err instanceof SyntaxError) {
178
+ console.log("DB: schema file has syntax error, waiting for next change...");
179
+ return;
180
+ }
181
+ if (err.message.includes("Cannot find module") || err.message.includes("is not a function")) {
182
+ return;
183
+ }
184
+ throw err;
185
+ }
186
+ }
187
+ let getTableConfig;
188
+ try {
189
+ getTableConfig = require("drizzle-orm/pg-core").getTableConfig;
190
+ } catch {
191
+ return;
192
+ }
193
+ const tables = Object.values(schema).filter(
194
+ (t) => t && typeof t === "object" && /* @__PURE__ */ Symbol.for("drizzle:Name") in t
195
+ );
196
+ if (tables.length === 0) return;
197
+ await post("db/provision", {});
198
+ const existing = (await get("db/tables")).map((t) => t.name);
199
+ const missing = tables.filter((t) => !existing.includes(getTableConfig(t).name));
200
+ if (missing.length > 0) {
201
+ const { generateDrizzleJson, generateMigration } = require("drizzle-kit/api");
202
+ const missingSchema = {};
203
+ for (const t of missing) missingSchema[getTableConfig(t).name] = t;
204
+ const sqls = await generateMigration(generateDrizzleJson({}), generateDrizzleJson(missingSchema));
205
+ for (const sql of sqls) {
206
+ for (let attempt = 0; attempt < 2; attempt++) {
207
+ try {
208
+ await post("db/query", { sql, params: [] });
209
+ console.log(`DB: Executed: ${sql.slice(0, 80)}...`);
210
+ break;
211
+ } catch (err) {
212
+ if (attempt === 0) {
213
+ console.warn(`DB: Retrying after: ${err.message}`);
214
+ await new Promise((r) => setTimeout(r, 1500));
215
+ } else {
216
+ console.error(`DB: Failed: ${sql.slice(0, 80)}... \u2014 ${err.message}`);
217
+ }
218
+ }
219
+ }
220
+ }
221
+ }
222
+ const existingTables = tables.filter((t) => existing.includes(getTableConfig(t).name));
223
+ for (const t of existingTables) {
224
+ const cfg = getTableConfig(t);
225
+ try {
226
+ const live = await get("db/table-schema", { table: cfg.name });
227
+ const liveCols = new Set((live.columns || []).map((c) => c.name));
228
+ for (const col of cfg.columns) {
229
+ if (!liveCols.has(col.name)) {
230
+ const colType = col.getSQLType();
231
+ const ddl = `ALTER TABLE "${cfg.name}" ADD COLUMN IF NOT EXISTS "${col.name}" ${colType}`;
232
+ try {
233
+ await post("db/query", { sql: ddl, params: [] });
234
+ console.log(`DB: Added column ${col.name} to ${cfg.name}`);
235
+ } catch (err) {
236
+ console.warn(`DB: Failed to add column ${col.name} to ${cfg.name}: ${err.message}`);
237
+ }
238
+ }
239
+ }
240
+ } catch (err) {
241
+ console.warn(`DB: Column check failed for ${cfg.name}: ${err.message}`);
242
+ }
243
+ }
244
+ } finally {
245
+ syncing = false;
246
+ }
247
+ }
248
+ function watchSchema(schemaPath, options) {
249
+ const { debounceMs = 1e3, retries = 2, retryDelay = 1500 } = options || {};
250
+ if (!import_fs.default.existsSync(schemaPath)) return () => {
251
+ };
252
+ let debounce = null;
253
+ import_fs.default.watchFile(schemaPath, { interval: 2e3 }, () => {
254
+ if (debounce) clearTimeout(debounce);
255
+ debounce = setTimeout(async () => {
256
+ console.log("DB: schema file changed, re-syncing tables...");
257
+ try {
258
+ await syncSchema({ schemaPath, retries, retryDelay });
259
+ console.log("DB: schema re-sync complete");
260
+ } catch (err) {
261
+ console.error(`DB: schema re-sync failed: ${err.message}`);
262
+ }
263
+ }, debounceMs);
264
+ });
265
+ return () => {
266
+ import_fs.default.unwatchFile(schemaPath);
267
+ if (debounce) clearTimeout(debounce);
268
+ };
269
+ }
150
270
 
151
271
  // src/server/runtime.ts
152
- var import_express = __toESM(require("express"), 1);
153
- var import_cors = __toESM(require("cors"), 1);
154
- var import_fs = __toESM(require("fs"), 1);
155
- var import_path = __toESM(require("path"), 1);
156
- var import_croner = require("croner");
157
- init_config();
158
272
  function requireBearerAuth(req, res, next) {
159
273
  const apiKey = readAdminApiKey();
160
274
  if (!apiKey) {
@@ -166,9 +280,10 @@ function requireBearerAuth(req, res, next) {
166
280
  next();
167
281
  }
168
282
  function createServer(options = {}) {
169
- const port = options.port ?? (process.env.PORT ? Number.parseInt(process.env.PORT, 10) : void 0);
283
+ const rawPort = process.env.BACKEND_PORT;
284
+ const port = options.port ?? (rawPort ? Number.parseInt(rawPort, 10) : void 0);
170
285
  if (!Number.isInteger(port)) {
171
- throw new Error("createServer requires a port via options.port or process.env.PORT");
286
+ throw new Error("createServer requires a port via options.port or BACKEND_PORT env var");
172
287
  }
173
288
  const routesDir = options.routesDir || import_path.default.join(process.cwd(), "routes");
174
289
  const cronDir = options.cronDir || process.cwd();
@@ -178,8 +293,8 @@ function createServer(options = {}) {
178
293
  app.get("/api/health", (_req, res) => {
179
294
  res.json({ status: "ok" });
180
295
  });
181
- if (import_fs.default.existsSync(routesDir)) {
182
- for (const file of import_fs.default.readdirSync(routesDir)) {
296
+ if (import_fs2.default.existsSync(routesDir)) {
297
+ for (const file of import_fs2.default.readdirSync(routesDir)) {
183
298
  if (!file.endsWith(".js") && !file.endsWith(".ts")) continue;
184
299
  const name = file.replace(/\.(js|ts)$/, "");
185
300
  try {
@@ -217,108 +332,11 @@ var schemaSync = { run: async () => {
217
332
  }, watch: () => {
218
333
  } };
219
334
  function setupSchemaSync(app, schemaDir) {
220
- let syncing = false;
221
335
  let schemaReady = false;
222
- async function doSyncSchema() {
223
- if (syncing) return;
224
- syncing = true;
225
- try {
226
- const schemaPath = import_path.default.join(schemaDir, "schema.js");
227
- if (!import_fs.default.existsSync(schemaPath)) return;
228
- try {
229
- delete require.cache[require.resolve(schemaPath)];
230
- } catch {
231
- }
232
- let schema;
233
- try {
234
- schema = require(schemaPath);
235
- } catch (err) {
236
- if (err instanceof SyntaxError) {
237
- console.log("DB: schema.js has syntax error, waiting for next change...");
238
- return;
239
- }
240
- if (err.message.includes("Cannot find module") || err.message.includes("is not a function")) {
241
- return;
242
- }
243
- throw err;
244
- }
245
- let getTableConfig;
246
- try {
247
- getTableConfig = require("drizzle-orm/pg-core").getTableConfig;
248
- } catch {
249
- return;
250
- }
251
- const tables = Object.values(schema).filter(
252
- (t) => t && typeof t === "object" && /* @__PURE__ */ Symbol.for("drizzle:Name") in t
253
- );
254
- if (tables.length === 0) return;
255
- const { get: dbGet, post: dbPost } = await Promise.resolve().then(() => (init_client(), client_exports));
256
- await dbPost("db/provision");
257
- const existing = (await dbGet("db/tables")).map((t) => t.name);
258
- const missing = tables.filter((t) => !existing.includes(getTableConfig(t).name));
259
- if (missing.length > 0) {
260
- const { generateDrizzleJson, generateMigration } = require("drizzle-kit/api");
261
- const missingSchema = {};
262
- for (const t of missing) missingSchema[getTableConfig(t).name] = t;
263
- const sqls = await generateMigration(generateDrizzleJson({}), generateDrizzleJson(missingSchema));
264
- for (const sql of sqls) {
265
- for (let attempt = 0; attempt < 2; attempt++) {
266
- try {
267
- await dbPost("db/query", { sql, params: [] });
268
- console.log(`DB: Executed: ${sql.slice(0, 80)}...`);
269
- break;
270
- } catch (err) {
271
- if (attempt === 0) {
272
- console.warn(`DB: Retrying after: ${err.message}`);
273
- await new Promise((r) => setTimeout(r, 1500));
274
- } else {
275
- console.error(`DB: Failed: ${sql.slice(0, 80)}... \u2014 ${err.message}`);
276
- }
277
- }
278
- }
279
- }
280
- }
281
- const existingTables = tables.filter((t) => existing.includes(getTableConfig(t).name));
282
- for (const t of existingTables) {
283
- const cfg = getTableConfig(t);
284
- try {
285
- const live = await dbGet("db/table-schema", { table: cfg.name });
286
- const liveCols = new Set((live.columns || []).map((c) => c.name));
287
- for (const col of cfg.columns) {
288
- if (!liveCols.has(col.name)) {
289
- const colType = col.getSQLType();
290
- const ddl = `ALTER TABLE "${cfg.name}" ADD COLUMN IF NOT EXISTS "${col.name}" ${colType}`;
291
- try {
292
- await dbPost("db/query", { sql: ddl, params: [] });
293
- console.log(`DB: Added column ${col.name} to ${cfg.name}`);
294
- } catch (err) {
295
- console.warn(`DB: Failed to add column ${col.name} to ${cfg.name}: ${err.message}`);
296
- }
297
- }
298
- }
299
- } catch (err) {
300
- console.warn(`DB: Column check failed for ${cfg.name}: ${err.message}`);
301
- }
302
- }
303
- } finally {
304
- syncing = false;
305
- }
306
- }
307
- async function syncWithRetry(retries = 3, delay = 2e3) {
308
- for (let i = 0; i < retries; i++) {
309
- try {
310
- await doSyncSchema();
311
- return;
312
- } catch (err) {
313
- console.error(`DB schema sync attempt ${i + 1}/${retries} failed: ${err.message}`);
314
- if (i < retries - 1) await new Promise((r) => setTimeout(r, delay * (i + 1)));
315
- }
316
- }
317
- console.error("DB schema sync failed after all retries");
318
- }
336
+ const schemaPath = import_path.default.join(schemaDir, "schema.js");
319
337
  app.post("/api/__sync-schema", requireBearerAuth, async (_req, res) => {
320
338
  try {
321
- await syncWithRetry(2, 1500);
339
+ await syncSchema({ schemaPath, retries: 2, retryDelay: 1500 });
322
340
  res.json({ ok: true });
323
341
  } catch (err) {
324
342
  res.status(500).json({ ok: false, error: err.message });
@@ -330,7 +348,7 @@ function setupSchemaSync(app, schemaDir) {
330
348
  });
331
349
  schemaSync.run = async () => {
332
350
  try {
333
- await syncWithRetry();
351
+ await syncSchema({ schemaPath });
334
352
  schemaReady = true;
335
353
  console.log("Schema sync complete, API ready");
336
354
  } catch {
@@ -339,21 +357,7 @@ function setupSchemaSync(app, schemaDir) {
339
357
  }
340
358
  };
341
359
  schemaSync.watch = () => {
342
- const schemaPath = import_path.default.join(schemaDir, "schema.js");
343
- if (!import_fs.default.existsSync(schemaPath)) return;
344
- let debounce = null;
345
- import_fs.default.watchFile(schemaPath, { interval: 2e3 }, () => {
346
- if (debounce) clearTimeout(debounce);
347
- debounce = setTimeout(async () => {
348
- console.log("DB: schema.js changed, re-syncing tables...");
349
- try {
350
- await syncWithRetry(2, 1500);
351
- console.log("DB: schema re-sync complete");
352
- } catch (err) {
353
- console.error(`DB: schema re-sync failed: ${err.message}`);
354
- }
355
- }, 1e3);
356
- });
360
+ watchSchema(schemaPath);
357
361
  };
358
362
  }
359
363
  function setupCron(app, cronDir) {
@@ -369,10 +373,10 @@ function setupCron(app, cronDir) {
369
373
  }
370
374
  cronJobs.clear();
371
375
  const cronPath = import_path.default.join(cronDir, "cron.json");
372
- if (!import_fs.default.existsSync(cronPath)) return;
376
+ if (!import_fs2.default.existsSync(cronPath)) return;
373
377
  let tasks;
374
378
  try {
375
- tasks = JSON.parse(import_fs.default.readFileSync(cronPath, "utf-8"));
379
+ tasks = JSON.parse(import_fs2.default.readFileSync(cronPath, "utf-8"));
376
380
  } catch (e) {
377
381
  console.error("Failed to parse cron.json:", e.message);
378
382
  return;
@@ -453,7 +457,7 @@ function setupCron(app, cronDir) {
453
457
  const cronPath = import_path.default.join(cronDir, "cron.json");
454
458
  let tasks = [];
455
459
  try {
456
- if (import_fs.default.existsSync(cronPath)) tasks = JSON.parse(import_fs.default.readFileSync(cronPath, "utf8"));
460
+ if (import_fs2.default.existsSync(cronPath)) tasks = JSON.parse(import_fs2.default.readFileSync(cronPath, "utf8"));
457
461
  } catch {
458
462
  tasks = [];
459
463
  }
@@ -462,7 +466,7 @@ function setupCron(app, cronDir) {
462
466
  }
463
467
  const newTask = { id, name, schedule, handler, enabled, timeout };
464
468
  tasks.push(newTask);
465
- import_fs.default.writeFileSync(cronPath, JSON.stringify(tasks, null, 2));
469
+ import_fs2.default.writeFileSync(cronPath, JSON.stringify(tasks, null, 2));
466
470
  loadCronJobs();
467
471
  res.status(201).json(newTask);
468
472
  });
@@ -470,7 +474,7 @@ function setupCron(app, cronDir) {
470
474
  const cronPath = import_path.default.join(cronDir, "cron.json");
471
475
  let tasks = [];
472
476
  try {
473
- if (import_fs.default.existsSync(cronPath)) tasks = JSON.parse(import_fs.default.readFileSync(cronPath, "utf8"));
477
+ if (import_fs2.default.existsSync(cronPath)) tasks = JSON.parse(import_fs2.default.readFileSync(cronPath, "utf8"));
474
478
  } catch {
475
479
  tasks = [];
476
480
  }
@@ -491,7 +495,7 @@ function setupCron(app, cronDir) {
491
495
  }
492
496
  }
493
497
  tasks[idx] = { ...tasks[idx], ...updates, id: req.params.id };
494
- import_fs.default.writeFileSync(cronPath, JSON.stringify(tasks, null, 2));
498
+ import_fs2.default.writeFileSync(cronPath, JSON.stringify(tasks, null, 2));
495
499
  loadCronJobs();
496
500
  res.json(tasks[idx]);
497
501
  });
@@ -499,14 +503,14 @@ function setupCron(app, cronDir) {
499
503
  const cronPath = import_path.default.join(cronDir, "cron.json");
500
504
  let tasks = [];
501
505
  try {
502
- if (import_fs.default.existsSync(cronPath)) tasks = JSON.parse(import_fs.default.readFileSync(cronPath, "utf8"));
506
+ if (import_fs2.default.existsSync(cronPath)) tasks = JSON.parse(import_fs2.default.readFileSync(cronPath, "utf8"));
503
507
  } catch {
504
508
  tasks = [];
505
509
  }
506
510
  const idx = tasks.findIndex((t) => t.id === req.params.id);
507
511
  if (idx === -1) return res.status(404).json({ error: "Task not found" });
508
512
  tasks.splice(idx, 1);
509
- import_fs.default.writeFileSync(cronPath, JSON.stringify(tasks, null, 2));
513
+ import_fs2.default.writeFileSync(cronPath, JSON.stringify(tasks, null, 2));
510
514
  cronState.delete(req.params.id);
511
515
  loadCronJobs();
512
516
  res.json({ ok: true });
@@ -524,11 +528,7 @@ function setupCron(app, cronDir) {
524
528
  loadCronJobs();
525
529
  }
526
530
 
527
- // src/data/data-api.ts
528
- init_client();
529
-
530
531
  // src/data/categories/exchange.ts
531
- init_client();
532
532
  var exchange = {
533
533
  /** Returns order book bid/ask levels with computed stats. **Included fields:** spread, spread percentage, mid-price, and total bid/ask depth. Use `limit` to control the number of price levels (1–100, default 20). Set `type=swap` to query perpetual contract order books instead of spot. */
534
534
  depth: (params) => get("exchange/depth", params),
@@ -547,7 +547,6 @@ var exchange = {
547
547
  };
548
548
 
549
549
  // src/data/categories/fund.ts
550
- init_client();
551
550
  var fund = {
552
551
  /** Returns a fund's **profile metadata**. **Included fields:** X accounts, team members, recent research, invested project count. This does NOT return the list of investments — use `/fund/portfolio` for that. **Lookup:** by UUID (`id`) or name (`q`). Returns 404 if not found. */
553
552
  detail: (params) => get("fund/detail", params),
@@ -558,7 +557,6 @@ var fund = {
558
557
  };
559
558
 
560
559
  // src/data/categories/kalshi.ts
561
- init_client();
562
560
  var kalshi = {
563
561
  /** Returns Kalshi events with nested markets, optionally filtered by `event_ticker`. Each event includes market count and a list of markets. **Data refresh:** ~30 minutes */
564
562
  events: (params) => get("prediction-market/kalshi/events", params),
@@ -577,7 +575,6 @@ var kalshi = {
577
575
  };
578
576
 
579
577
  // src/data/categories/market.ts
580
- init_client();
581
578
  var market = {
582
579
  /** Returns daily ETF flow history for US spot ETFs. **Included fields:** net flow (USD), token price, per-ticker breakdown. Sorted by date descending. `symbol`: `BTC` or `ETH`. */
583
580
  etf: (params) => get("market/etf", params),
@@ -604,7 +601,6 @@ var market = {
604
601
  };
605
602
 
606
603
  // src/data/categories/matching.ts
607
- init_client();
608
604
  var matching = {
609
605
  /** Returns daily volume and open interest comparison for a specific matched market pair. Both `polymarket_condition_id` and `kalshi_market_ticker` are required. **Volume units:** Polymarket = USD, Kalshi = contracts. */
610
606
  market_daily: (params) => get("prediction-market/matching/daily", params),
@@ -615,7 +611,6 @@ var matching = {
615
611
  };
616
612
 
617
613
  // src/data/categories/news.ts
618
- init_client();
619
614
  var news = {
620
615
  /** Returns the full content of a single news article by its ID (returned as `id` in feed and search results). */
621
616
  detail: (params) => get("news/detail", params),
@@ -624,7 +619,6 @@ var news = {
624
619
  };
625
620
 
626
621
  // src/data/categories/onchain.ts
627
- init_client();
628
622
  var onchain = {
629
623
  /** Returns bridge protocols ranked by total USD volume over a specified time range. */
630
624
  bridge_ranking: (params) => get("onchain/bridge/ranking", params),
@@ -643,7 +637,6 @@ var onchain = {
643
637
  };
644
638
 
645
639
  // src/data/categories/polymarket.ts
646
- init_client();
647
640
  var polymarket = {
648
641
  /** Returns trade and redemption activity for a Polymarket wallet. **Data refresh:** ~30 minutes */
649
642
  activity: (params) => get("prediction-market/polymarket/activity", params),
@@ -666,14 +659,12 @@ var polymarket = {
666
659
  };
667
660
 
668
661
  // src/data/categories/prediction_market.ts
669
- init_client();
670
662
  var prediction_market = {
671
663
  /** Returns daily notional volume and open interest aggregated by category across Kalshi and Polymarket. **Filters:** `source` or `category`. **Data refresh:** daily */
672
664
  category_metrics: (params) => get("prediction-market/category-metrics", params)
673
665
  };
674
666
 
675
667
  // src/data/categories/project.ts
676
- init_client();
677
668
  var project = {
678
669
  /** Returns time-series DeFi metrics for a project. **Available metrics:** `volume`, `fee`, `fees`, `revenue`, `tvl`, `users`. **Lookup:** by UUID (`id`) or name (`q`). Filter by `chain` and date range (`from`/`to`). Returns 404 if the project is not found. **Note:** this endpoint only returns data for DeFi protocol projects (e.g. `aave`, `uniswap`, `lido`, `makerdao`). Use `q` with a DeFi protocol name. */
679
670
  defi_metrics: (params) => get("project/defi/metrics", params),
@@ -684,7 +675,6 @@ var project = {
684
675
  };
685
676
 
686
677
  // src/data/categories/search.ts
687
- init_client();
688
678
  var search = {
689
679
  /** Searches and filters airdrop opportunities. **Filters:** keyword, status, reward type, task type. Returns paginated results with optional task details. */
690
680
  airdrop: (params) => get("search/airdrop", params),
@@ -711,7 +701,6 @@ var search = {
711
701
  };
712
702
 
713
703
  // src/data/categories/social.ts
714
- init_client();
715
704
  var social = {
716
705
  /** Returns a **point-in-time snapshot** of social analytics for a project. **Available fields** (via `fields`): `sentiment`, `follower_geo`, `smart_followers`. **Lookup:** by X account ID (`x_id`) or project name (`q`, e.g. `uniswap`, `solana`). The `q` parameter must be a crypto project name, not a personal Twitter handle. Returns 404 if the project has no linked Twitter account. For sentiment **trends over time**, use `/social/mindshare` instead. */
717
706
  detail: (params) => get("social/detail", params),
@@ -738,7 +727,6 @@ var social = {
738
727
  };
739
728
 
740
729
  // src/data/categories/token.ts
741
- init_client();
742
730
  var token = {
743
731
  /** Returns recent DEX swap events for a token contract address. **Covered DEXes:** `uniswap`, `sushiswap`, `curve`, `balancer`. **Included fields:** trading pair, amounts, USD value, taker address. **Data refresh:** ~24 hours · **Chains:** Ethereum, Base */
744
732
  dex_trades: (params) => get("token/dex-trades", params),
@@ -751,7 +739,6 @@ var token = {
751
739
  };
752
740
 
753
741
  // src/data/categories/v2.ts
754
- init_client();
755
742
  var v2 = {
756
743
  /** Historical orderbook snapshots for a Kalshi market. Returns yes-side bid/ask levels. Timestamps in milliseconds, prices in cents. Data refresh: ~5 minutes */
757
744
  kalshi_orderbooks: (params) => get("gateway/v2/kalshi/orderbooks", params),
@@ -766,7 +753,6 @@ var v2 = {
766
753
  };
767
754
 
768
755
  // src/data/categories/wallet.ts
769
- init_client();
770
756
  var wallet = {
771
757
  /** Returns multiple wallet sub-resources in a single request. **Available fields** (via `fields`): `balance`, `tokens`, `labels`, `nft`. **Lookup:** by `address`. Partial failures return available fields with per-field error info. Returns 422 if `fields` is invalid. */
772
758
  detail: (params) => get("wallet/detail", params),
@@ -783,7 +769,6 @@ var wallet = {
783
769
  };
784
770
 
785
771
  // src/data/categories/web.ts
786
- init_client();
787
772
  var web = {
788
773
  /** Fetches a web page and converts it to clean, LLM-friendly markdown. **Options:** - `target_selector` — extract specific page sections - `remove_selector` — strip unwanted elements Returns 400 if the URL is invalid or unreachable. */
789
774
  fetch: (params) => get("web/fetch", params)