@fereai/sdk 0.1.0-dev.4

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,19 @@
1
+ # @fere/sdk
2
+
3
+ TypeScript SDK for the FereAI Gateway API.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @fere/sdk
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { FereClient } from "@fere/sdk";
15
+
16
+ const client = new FereClient({ apiKey: "your-api-key", baseUrl: "https://api.fere.ai" });
17
+ ```
18
+
19
+ See the [FereAI docs](https://api.fere.ai) for full API reference.
package/dist/auth.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Auth module — Ed25519 keypair management and token lifecycle.
3
+ *
4
+ * Uses @noble/ed25519 for Ed25519 signing.
5
+ */
6
+ export declare class AuthManager {
7
+ private readonly agentName;
8
+ private readonly baseUrl;
9
+ private readonly keyPath;
10
+ private secretKey;
11
+ private publicKey;
12
+ private agentId;
13
+ private token;
14
+ private tokenExpiresAt;
15
+ constructor(agentName: string, baseUrl?: string, keyPath?: string);
16
+ private loadOrCreateKeypair;
17
+ private getPublicKey;
18
+ getPublicKeyB64(): Promise<string>;
19
+ private sign;
20
+ private saveKeypair;
21
+ private readCreds;
22
+ ensureRegistered(): Promise<string>;
23
+ ensureToken(): Promise<string>;
24
+ authHeaders(): Record<string, string>;
25
+ /** Clear cached token to force refresh on next call. */
26
+ clearToken(): void;
27
+ }
package/dist/auth.js ADDED
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ /**
3
+ * Auth module — Ed25519 keypair management and token lifecycle.
4
+ *
5
+ * Uses @noble/ed25519 for Ed25519 signing.
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.AuthManager = void 0;
42
+ const ed = __importStar(require("@noble/ed25519"));
43
+ const fs_1 = require("fs");
44
+ const path_1 = require("path");
45
+ const os_1 = require("os");
46
+ class AuthManager {
47
+ agentName;
48
+ baseUrl;
49
+ keyPath;
50
+ secretKey = null;
51
+ publicKey = null;
52
+ agentId = null;
53
+ token = null;
54
+ tokenExpiresAt = 0;
55
+ constructor(agentName, baseUrl = "https://api.fereai.xyz", keyPath) {
56
+ this.agentName = agentName;
57
+ this.baseUrl = baseUrl.replace(/\/$/, "");
58
+ this.keyPath = keyPath ?? (0, path_1.join)((0, os_1.homedir)(), ".fere", "keys.json");
59
+ }
60
+ // ----------------------------------------------------------
61
+ // Keypair management
62
+ // ----------------------------------------------------------
63
+ loadOrCreateKeypair() {
64
+ if (this.secretKey)
65
+ return;
66
+ const creds = this.readCreds();
67
+ const entry = creds[this.baseUrl]?.[this.agentName];
68
+ if (entry?.secret_key) {
69
+ this.secretKey = Buffer.from(entry.secret_key, "base64");
70
+ this.publicKey = Buffer.from(entry.public_key, "base64");
71
+ this.agentId = entry.agent_id ?? null;
72
+ }
73
+ else {
74
+ this.secretKey = ed.utils.randomPrivateKey();
75
+ this.publicKey = null; // Will be derived on first use
76
+ this.saveKeypair();
77
+ }
78
+ }
79
+ async getPublicKey() {
80
+ this.loadOrCreateKeypair();
81
+ if (!this.publicKey) {
82
+ this.publicKey = await ed.getPublicKeyAsync(this.secretKey);
83
+ this.saveKeypair();
84
+ }
85
+ return this.publicKey;
86
+ }
87
+ async getPublicKeyB64() {
88
+ const pk = await this.getPublicKey();
89
+ return Buffer.from(pk).toString("base64");
90
+ }
91
+ async sign(message) {
92
+ this.loadOrCreateKeypair();
93
+ const pk = await this.getPublicKey();
94
+ const sig = await ed.signAsync(new TextEncoder().encode(message), this.secretKey);
95
+ return Buffer.from(sig).toString("base64");
96
+ }
97
+ saveKeypair() {
98
+ const creds = this.readCreds();
99
+ if (!creds[this.baseUrl])
100
+ creds[this.baseUrl] = {};
101
+ creds[this.baseUrl][this.agentName] = {
102
+ secret_key: Buffer.from(this.secretKey).toString("base64"),
103
+ public_key: this.publicKey
104
+ ? Buffer.from(this.publicKey).toString("base64")
105
+ : "",
106
+ agent_id: this.agentId ?? undefined,
107
+ };
108
+ const dir = (0, path_1.dirname)(this.keyPath);
109
+ if (!(0, fs_1.existsSync)(dir))
110
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
111
+ (0, fs_1.writeFileSync)(this.keyPath, JSON.stringify(creds, null, 2));
112
+ }
113
+ readCreds() {
114
+ if ((0, fs_1.existsSync)(this.keyPath)) {
115
+ return JSON.parse((0, fs_1.readFileSync)(this.keyPath, "utf-8"));
116
+ }
117
+ return {};
118
+ }
119
+ // ----------------------------------------------------------
120
+ // Registration + token flow
121
+ // ----------------------------------------------------------
122
+ async ensureRegistered() {
123
+ this.loadOrCreateKeypair();
124
+ if (this.agentId)
125
+ return this.agentId;
126
+ const pubKey = await this.getPublicKeyB64();
127
+ // Step 1: Register
128
+ const regResp = await fetch(`${this.baseUrl}/v1/auth/register`, {
129
+ method: "POST",
130
+ headers: { "Content-Type": "application/json" },
131
+ body: JSON.stringify({
132
+ agent_name: this.agentName,
133
+ public_key: pubKey,
134
+ }),
135
+ });
136
+ if (!regResp.ok)
137
+ throw new Error(`Registration failed: ${regResp.status}`);
138
+ const reg = (await regResp.json());
139
+ // Step 2: Sign challenge and verify
140
+ const sig = await this.sign(reg.challenge);
141
+ const verifyResp = await fetch(`${this.baseUrl}/v1/auth/verify`, {
142
+ method: "POST",
143
+ headers: { "Content-Type": "application/json" },
144
+ body: JSON.stringify({
145
+ registration_id: reg.registration_id,
146
+ challenge: reg.challenge,
147
+ signature: sig,
148
+ }),
149
+ });
150
+ if (!verifyResp.ok)
151
+ throw new Error(`Verification failed: ${verifyResp.status}`);
152
+ const verify = (await verifyResp.json());
153
+ this.agentId = verify.agent_id;
154
+ this.saveKeypair();
155
+ return this.agentId;
156
+ }
157
+ async ensureToken() {
158
+ if (this.token && this.tokenExpiresAt > Date.now() / 1000 + 30) {
159
+ return this.token;
160
+ }
161
+ const agentId = await this.ensureRegistered();
162
+ const ts = Math.floor(Date.now() / 1000).toString();
163
+ const sig = await this.sign(ts);
164
+ const resp = await fetch(`${this.baseUrl}/v1/auth/token`, {
165
+ method: "POST",
166
+ headers: { "Content-Type": "application/json" },
167
+ body: JSON.stringify({
168
+ agent_id: agentId,
169
+ timestamp: ts,
170
+ signature: sig,
171
+ }),
172
+ });
173
+ if (resp.status === 401) {
174
+ // Re-register
175
+ this.agentId = null;
176
+ const newAgentId = await this.ensureRegistered();
177
+ const newTs = Math.floor(Date.now() / 1000).toString();
178
+ const newSig = await this.sign(newTs);
179
+ const retryResp = await fetch(`${this.baseUrl}/v1/auth/token`, {
180
+ method: "POST",
181
+ headers: { "Content-Type": "application/json" },
182
+ body: JSON.stringify({
183
+ agent_id: newAgentId,
184
+ timestamp: newTs,
185
+ signature: newSig,
186
+ }),
187
+ });
188
+ if (!retryResp.ok)
189
+ throw new Error(`Token request failed: ${retryResp.status}`);
190
+ const data = (await retryResp.json());
191
+ this.token = data.token;
192
+ this.tokenExpiresAt = Date.now() / 1000 + data.expires_in;
193
+ return this.token;
194
+ }
195
+ if (!resp.ok)
196
+ throw new Error(`Token request failed: ${resp.status}`);
197
+ const data = (await resp.json());
198
+ this.token = data.token;
199
+ this.tokenExpiresAt = Date.now() / 1000 + data.expires_in;
200
+ return this.token;
201
+ }
202
+ authHeaders() {
203
+ if (!this.token)
204
+ throw new Error("Call ensureToken() first");
205
+ return { Authorization: `Bearer ${this.token}` };
206
+ }
207
+ /** Clear cached token to force refresh on next call. */
208
+ clearToken() {
209
+ this.token = null;
210
+ this.tokenExpiresAt = 0;
211
+ }
212
+ }
213
+ exports.AuthManager = AuthManager;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * High-level SDK — developer-friendly wrapper that hides async tasks.
3
+ *
4
+ * Usage:
5
+ * ```ts
6
+ * const client = await FereClient.create({ agentName: "my-bot" });
7
+ * const result = await client.swap({
8
+ * chain_id_in: 8453,
9
+ * chain_id_out: 8453,
10
+ * token_in: "0xEeee...EEeE",
11
+ * token_out: "0x8335...2913",
12
+ * amount: "1000000000000000000",
13
+ * });
14
+ * ```
15
+ */
16
+ import type { ChatEvent, SwapRequest, LimitOrderRequest, HooksRequest, DepositRequest, WithdrawRequest } from "./types.js";
17
+ export declare class FereClient {
18
+ private readonly api;
19
+ private constructor();
20
+ static create(opts: {
21
+ agentName: string;
22
+ baseUrl?: string;
23
+ keyPath?: string;
24
+ }): Promise<FereClient>;
25
+ chat(query: string, opts?: {
26
+ threadId?: string;
27
+ agent?: string;
28
+ }): Promise<Record<string, unknown>>;
29
+ chatStream(query: string, opts?: {
30
+ threadId?: string;
31
+ agent?: string;
32
+ }): AsyncGenerator<ChatEvent>;
33
+ swap(request: SwapRequest, timeout?: number): Promise<Record<string, unknown>>;
34
+ limitOrder(request: LimitOrderRequest, timeout?: number): Promise<Record<string, unknown>>;
35
+ setHooks(request: HooksRequest): Promise<unknown>;
36
+ deposit(request: DepositRequest, timeout?: number): Promise<Record<string, unknown>>;
37
+ withdraw(request: WithdrawRequest, timeout?: number): Promise<Record<string, unknown>>;
38
+ getWallets: () => Promise<unknown>;
39
+ getHoldings: () => Promise<unknown>;
40
+ getCredits: () => Promise<import("./types.js").CreditsInfo>;
41
+ getUser: () => Promise<unknown>;
42
+ getChains: () => Promise<unknown>;
43
+ getEarnInfo: () => Promise<unknown>;
44
+ getPositions: () => Promise<unknown>;
45
+ getThreads: (skip?: number, limit?: number) => Promise<unknown[]>;
46
+ getLimitOrders: (status?: string) => Promise<unknown[]>;
47
+ getNotifications: (opts?: {
48
+ limit?: number;
49
+ offset?: number;
50
+ type?: string;
51
+ }) => Promise<unknown>;
52
+ }
package/dist/client.js ADDED
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ /**
3
+ * High-level SDK — developer-friendly wrapper that hides async tasks.
4
+ *
5
+ * Usage:
6
+ * ```ts
7
+ * const client = await FereClient.create({ agentName: "my-bot" });
8
+ * const result = await client.swap({
9
+ * chain_id_in: 8453,
10
+ * chain_id_out: 8453,
11
+ * token_in: "0xEeee...EEeE",
12
+ * token_out: "0x8335...2913",
13
+ * amount: "1000000000000000000",
14
+ * });
15
+ * ```
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.FereClient = void 0;
19
+ const low_level_js_1 = require("./low-level.js");
20
+ const DEFAULT_TIMEOUT = 120;
21
+ class FereClient {
22
+ api;
23
+ constructor(api) {
24
+ this.api = api;
25
+ }
26
+ static async create(opts) {
27
+ const api = new low_level_js_1.FereAPI(opts);
28
+ await api.authenticate();
29
+ return new FereClient(api);
30
+ }
31
+ // ----------------------------------------------------------
32
+ // Chat
33
+ // ----------------------------------------------------------
34
+ async chat(query, opts) {
35
+ const result = {};
36
+ const toolResponses = [];
37
+ for await (const event of this.api.chat(query, opts)) {
38
+ switch (event.event) {
39
+ case "meta":
40
+ result.chat_id = event.data.chat_id;
41
+ break;
42
+ case "tool_response":
43
+ toolResponses.push(event.data);
44
+ break;
45
+ case "answer":
46
+ result.answer = event.data.text ?? "";
47
+ break;
48
+ case "done":
49
+ result.done = event.data;
50
+ break;
51
+ case "error":
52
+ throw new Error(String(event.data.message ?? JSON.stringify(event.data)));
53
+ }
54
+ }
55
+ if (toolResponses.length > 0) {
56
+ result.tool_responses = toolResponses;
57
+ }
58
+ return result;
59
+ }
60
+ async *chatStream(query, opts) {
61
+ yield* this.api.chat(query, opts);
62
+ }
63
+ // ----------------------------------------------------------
64
+ // Trading (blocks until complete)
65
+ // ----------------------------------------------------------
66
+ async swap(request, timeout = DEFAULT_TIMEOUT) {
67
+ return this.api.createSwap(request, {
68
+ wait: true,
69
+ timeout,
70
+ });
71
+ }
72
+ async limitOrder(request, timeout = DEFAULT_TIMEOUT) {
73
+ return this.api.createLimitOrder(request, {
74
+ wait: true,
75
+ timeout,
76
+ });
77
+ }
78
+ async setHooks(request) {
79
+ return this.api.setHooks(request);
80
+ }
81
+ // ----------------------------------------------------------
82
+ // Earn (blocks until complete)
83
+ // ----------------------------------------------------------
84
+ async deposit(request, timeout = DEFAULT_TIMEOUT) {
85
+ return this.api.deposit(request, {
86
+ wait: true,
87
+ timeout,
88
+ });
89
+ }
90
+ async withdraw(request, timeout = DEFAULT_TIMEOUT) {
91
+ return this.api.withdraw(request, {
92
+ wait: true,
93
+ timeout,
94
+ });
95
+ }
96
+ // ----------------------------------------------------------
97
+ // Read-only (pass-through)
98
+ // ----------------------------------------------------------
99
+ getWallets = () => this.api.getWallets();
100
+ getHoldings = () => this.api.getHoldings();
101
+ getCredits = () => this.api.getCredits();
102
+ getUser = () => this.api.getUser();
103
+ getChains = () => this.api.getChains();
104
+ getEarnInfo = () => this.api.getEarnInfo();
105
+ getPositions = () => this.api.getPositions();
106
+ getThreads = (skip, limit) => this.api.getThreads(skip, limit);
107
+ getLimitOrders = (status) => this.api.getLimitOrders(status);
108
+ getNotifications = (opts) => this.api.getNotifications(opts);
109
+ }
110
+ exports.FereClient = FereClient;
@@ -0,0 +1,5 @@
1
+ export { FereAPI } from "./low-level.js";
2
+ export { FereClient } from "./client.js";
3
+ export { AuthManager } from "./auth.js";
4
+ export type { ChatEvent, TaskResponse, TaskStatusResponse, SwapRequest, LimitOrderRequest, HooksRequest, DepositRequest, WithdrawRequest, CreditsInfo, WalletInfo, } from "./types.js";
5
+ export { TaskTimeoutError } from "./types.js";
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TaskTimeoutError = exports.AuthManager = exports.FereClient = exports.FereAPI = void 0;
4
+ var low_level_js_1 = require("./low-level.js");
5
+ Object.defineProperty(exports, "FereAPI", { enumerable: true, get: function () { return low_level_js_1.FereAPI; } });
6
+ var client_js_1 = require("./client.js");
7
+ Object.defineProperty(exports, "FereClient", { enumerable: true, get: function () { return client_js_1.FereClient; } });
8
+ var auth_js_1 = require("./auth.js");
9
+ Object.defineProperty(exports, "AuthManager", { enumerable: true, get: function () { return auth_js_1.AuthManager; } });
10
+ var types_js_1 = require("./types.js");
11
+ Object.defineProperty(exports, "TaskTimeoutError", { enumerable: true, get: function () { return types_js_1.TaskTimeoutError; } });
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Low-level SDK — 1:1 typed wrappers around every gateway endpoint.
3
+ */
4
+ import type { ChatEvent, CreditsInfo, DepositRequest, HooksRequest, LimitOrderRequest, SwapRequest, TaskResponse, TaskStatusResponse, WithdrawRequest } from "./types.js";
5
+ export declare class FereAPI {
6
+ private readonly baseUrl;
7
+ private readonly auth;
8
+ constructor(opts: {
9
+ agentName: string;
10
+ baseUrl?: string;
11
+ keyPath?: string;
12
+ });
13
+ authenticate(): Promise<string>;
14
+ private headers;
15
+ private authedGet;
16
+ private authedPost;
17
+ private authedDelete;
18
+ chat(query: string, opts?: {
19
+ threadId?: string;
20
+ agent?: string;
21
+ }): AsyncGenerator<ChatEvent>;
22
+ getThreads(skip?: number, limit?: number): Promise<unknown[]>;
23
+ getThread(threadId: string): Promise<unknown[]>;
24
+ createSwap(request: SwapRequest, opts?: {
25
+ wait?: boolean;
26
+ timeout?: number;
27
+ }): Promise<TaskResponse | Record<string, unknown>>;
28
+ createLimitOrder(request: LimitOrderRequest, opts?: {
29
+ wait?: boolean;
30
+ timeout?: number;
31
+ }): Promise<TaskResponse | Record<string, unknown>>;
32
+ getLimitOrders(status?: string): Promise<unknown[]>;
33
+ getLimitOrder(orderId: string): Promise<unknown>;
34
+ cancelLimitOrder(orderId: string): Promise<unknown>;
35
+ setHooks(request: HooksRequest): Promise<unknown>;
36
+ getWallets(): Promise<unknown>;
37
+ getHoldings(): Promise<unknown>;
38
+ getEarnInfo(): Promise<unknown>;
39
+ deposit(request: DepositRequest, opts?: {
40
+ wait?: boolean;
41
+ timeout?: number;
42
+ }): Promise<TaskResponse | Record<string, unknown>>;
43
+ withdraw(request: WithdrawRequest, opts?: {
44
+ wait?: boolean;
45
+ timeout?: number;
46
+ }): Promise<TaskResponse | Record<string, unknown>>;
47
+ getPositions(): Promise<unknown>;
48
+ getTask(taskId: string): Promise<TaskStatusResponse>;
49
+ getNotifications(opts?: {
50
+ limit?: number;
51
+ offset?: number;
52
+ type?: string;
53
+ }): Promise<unknown>;
54
+ notificationStream(): AsyncGenerator<ChatEvent>;
55
+ getCredits(): Promise<CreditsInfo>;
56
+ getUser(): Promise<unknown>;
57
+ getChains(): Promise<unknown>;
58
+ }
@@ -0,0 +1,268 @@
1
+ "use strict";
2
+ /**
3
+ * Low-level SDK — 1:1 typed wrappers around every gateway endpoint.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FereAPI = void 0;
7
+ const auth_js_1 = require("./auth.js");
8
+ const DEFAULT_BASE_URL = "https://api.fereai.xyz";
9
+ class FereAPI {
10
+ baseUrl;
11
+ auth;
12
+ constructor(opts) {
13
+ this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
14
+ this.auth = new auth_js_1.AuthManager(opts.agentName, this.baseUrl, opts.keyPath);
15
+ }
16
+ async authenticate() {
17
+ return this.auth.ensureToken();
18
+ }
19
+ async headers() {
20
+ await this.auth.ensureToken();
21
+ return {
22
+ ...this.auth.authHeaders(),
23
+ "Content-Type": "application/json",
24
+ };
25
+ }
26
+ async authedGet(path, params) {
27
+ const h = await this.headers();
28
+ const url = new URL(`${this.baseUrl}${path}`);
29
+ if (params)
30
+ Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
31
+ let resp = await fetch(url.toString(), { headers: h });
32
+ if (resp.status === 401) {
33
+ this.auth.clearToken();
34
+ const h2 = await this.headers();
35
+ resp = await fetch(url.toString(), { headers: h2 });
36
+ }
37
+ if (!resp.ok)
38
+ throw new Error(`GET ${path} failed: ${resp.status}`);
39
+ return resp.json();
40
+ }
41
+ async authedPost(path, body, params) {
42
+ const h = await this.headers();
43
+ const url = new URL(`${this.baseUrl}${path}`);
44
+ if (params)
45
+ Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
46
+ let resp = await fetch(url.toString(), {
47
+ method: "POST",
48
+ headers: h,
49
+ body: JSON.stringify(body),
50
+ });
51
+ if (resp.status === 401) {
52
+ this.auth.clearToken();
53
+ const h2 = await this.headers();
54
+ resp = await fetch(url.toString(), {
55
+ method: "POST",
56
+ headers: h2,
57
+ body: JSON.stringify(body),
58
+ });
59
+ }
60
+ if (!resp.ok)
61
+ throw new Error(`POST ${path} failed: ${resp.status}`);
62
+ return resp.json();
63
+ }
64
+ async authedDelete(path) {
65
+ const h = await this.headers();
66
+ let resp = await fetch(`${this.baseUrl}${path}`, {
67
+ method: "DELETE",
68
+ headers: h,
69
+ });
70
+ if (resp.status === 401) {
71
+ this.auth.clearToken();
72
+ const h2 = await this.headers();
73
+ resp = await fetch(`${this.baseUrl}${path}`, {
74
+ method: "DELETE",
75
+ headers: h2,
76
+ });
77
+ }
78
+ if (!resp.ok)
79
+ throw new Error(`DELETE ${path} failed: ${resp.status}`);
80
+ return resp.json();
81
+ }
82
+ // ----------------------------------------------------------
83
+ // Chat
84
+ // ----------------------------------------------------------
85
+ async *chat(query, opts) {
86
+ const h = await this.headers();
87
+ const body = {
88
+ query,
89
+ stream: true,
90
+ agent: opts?.agent ?? "ProAgent",
91
+ ...(opts?.threadId ? { thread_id: opts.threadId } : {}),
92
+ };
93
+ const resp = await fetch(`${this.baseUrl}/v1/chat`, {
94
+ method: "POST",
95
+ headers: h,
96
+ body: JSON.stringify(body),
97
+ });
98
+ if (!resp.ok)
99
+ throw new Error(`Chat failed: ${resp.status}`);
100
+ if (!resp.body)
101
+ return;
102
+ const reader = resp.body.getReader();
103
+ const decoder = new TextDecoder();
104
+ let buffer = "";
105
+ let eventType = "";
106
+ while (true) {
107
+ const { done, value } = await reader.read();
108
+ if (done)
109
+ break;
110
+ buffer += decoder.decode(value, { stream: true });
111
+ const lines = buffer.split("\n");
112
+ buffer = lines.pop() ?? "";
113
+ for (const line of lines) {
114
+ if (line.startsWith("event:")) {
115
+ eventType = line.slice(6).trim();
116
+ }
117
+ else if (line.startsWith("data:")) {
118
+ const data = JSON.parse(line.slice(5).trim());
119
+ yield { event: eventType, data };
120
+ }
121
+ }
122
+ }
123
+ }
124
+ async getThreads(skip = 0, limit = 10) {
125
+ return this.authedGet("/v1/chat/threads", {
126
+ skip: String(skip),
127
+ limit: String(limit),
128
+ });
129
+ }
130
+ async getThread(threadId) {
131
+ return this.authedGet(`/v1/chat/threads/${threadId}`);
132
+ }
133
+ // ----------------------------------------------------------
134
+ // Trading
135
+ // ----------------------------------------------------------
136
+ async createSwap(request, opts) {
137
+ const params = {};
138
+ if (opts?.wait) {
139
+ params.wait = "true";
140
+ params.timeout = String(opts.timeout ?? 60);
141
+ }
142
+ return this.authedPost("/v1/swap", request, params);
143
+ }
144
+ async createLimitOrder(request, opts) {
145
+ const params = {};
146
+ if (opts?.wait) {
147
+ params.wait = "true";
148
+ params.timeout = String(opts.timeout ?? 60);
149
+ }
150
+ return this.authedPost("/v1/limit-orders", request, params);
151
+ }
152
+ async getLimitOrders(status) {
153
+ const params = {};
154
+ if (status)
155
+ params.status = status;
156
+ return this.authedGet("/v1/limit-orders", params);
157
+ }
158
+ async getLimitOrder(orderId) {
159
+ return this.authedGet(`/v1/limit-orders/${orderId}`);
160
+ }
161
+ async cancelLimitOrder(orderId) {
162
+ return this.authedDelete(`/v1/limit-orders/${orderId}`);
163
+ }
164
+ async setHooks(request) {
165
+ return this.authedPost("/v1/hooks", request);
166
+ }
167
+ // ----------------------------------------------------------
168
+ // Wallets
169
+ // ----------------------------------------------------------
170
+ async getWallets() {
171
+ return this.authedGet("/v1/wallets");
172
+ }
173
+ async getHoldings() {
174
+ return this.authedGet("/v1/holdings");
175
+ }
176
+ // ----------------------------------------------------------
177
+ // Earn
178
+ // ----------------------------------------------------------
179
+ async getEarnInfo() {
180
+ const resp = await fetch(`${this.baseUrl}/v1/earn`);
181
+ if (!resp.ok)
182
+ throw new Error(`GET /v1/earn failed: ${resp.status}`);
183
+ return resp.json();
184
+ }
185
+ async deposit(request, opts) {
186
+ const params = {};
187
+ if (opts?.wait) {
188
+ params.wait = "true";
189
+ params.timeout = String(opts.timeout ?? 60);
190
+ }
191
+ return this.authedPost("/v1/earn/deposit", request, params);
192
+ }
193
+ async withdraw(request, opts) {
194
+ const params = {};
195
+ if (opts?.wait) {
196
+ params.wait = "true";
197
+ params.timeout = String(opts.timeout ?? 60);
198
+ }
199
+ return this.authedPost("/v1/earn/withdraw", request, params);
200
+ }
201
+ async getPositions() {
202
+ return this.authedGet("/v1/earn/positions");
203
+ }
204
+ // ----------------------------------------------------------
205
+ // Tasks
206
+ // ----------------------------------------------------------
207
+ async getTask(taskId) {
208
+ return this.authedGet(`/v1/tasks/${taskId}`);
209
+ }
210
+ // ----------------------------------------------------------
211
+ // Notifications
212
+ // ----------------------------------------------------------
213
+ async getNotifications(opts) {
214
+ const params = {};
215
+ if (opts?.limit !== undefined)
216
+ params.limit = String(opts.limit);
217
+ if (opts?.offset !== undefined)
218
+ params.offset = String(opts.offset);
219
+ if (opts?.type)
220
+ params.type = opts.type;
221
+ return this.authedGet("/v1/notifications", params);
222
+ }
223
+ async *notificationStream() {
224
+ const h = await this.headers();
225
+ const resp = await fetch(`${this.baseUrl}/v1/notifications/stream`, {
226
+ headers: h,
227
+ });
228
+ if (!resp.ok || !resp.body)
229
+ return;
230
+ const reader = resp.body.getReader();
231
+ const decoder = new TextDecoder();
232
+ let buffer = "";
233
+ let eventType = "";
234
+ while (true) {
235
+ const { done, value } = await reader.read();
236
+ if (done)
237
+ break;
238
+ buffer += decoder.decode(value, { stream: true });
239
+ const lines = buffer.split("\n");
240
+ buffer = lines.pop() ?? "";
241
+ for (const line of lines) {
242
+ if (line.startsWith("event:")) {
243
+ eventType = line.slice(6).trim();
244
+ }
245
+ else if (line.startsWith("data:")) {
246
+ const data = JSON.parse(line.slice(5).trim());
247
+ yield { event: eventType, data };
248
+ }
249
+ }
250
+ }
251
+ }
252
+ // ----------------------------------------------------------
253
+ // Credits / User / Chains
254
+ // ----------------------------------------------------------
255
+ async getCredits() {
256
+ return this.authedGet("/v1/credits");
257
+ }
258
+ async getUser() {
259
+ return this.authedGet("/v1/user");
260
+ }
261
+ async getChains() {
262
+ const resp = await fetch(`${this.baseUrl}/v1/chains`);
263
+ if (!resp.ok)
264
+ throw new Error(`GET /v1/chains failed: ${resp.status}`);
265
+ return resp.json();
266
+ }
267
+ }
268
+ exports.FereAPI = FereAPI;
@@ -0,0 +1,87 @@
1
+ /** Typed request/response models for the FereAI Gateway API. */
2
+ export interface TaskResponse {
3
+ task_id: string;
4
+ status: string;
5
+ poll_url?: string;
6
+ notification_stream?: string;
7
+ }
8
+ export interface TaskStatusResponse {
9
+ task_id: string;
10
+ status: string;
11
+ result?: Record<string, unknown>;
12
+ }
13
+ export interface ChatEvent {
14
+ event: string;
15
+ data: Record<string, unknown>;
16
+ }
17
+ export interface TokenInfo {
18
+ token: string;
19
+ expires_in: number;
20
+ }
21
+ export interface RegisterInfo {
22
+ registration_id: string;
23
+ challenge: string;
24
+ }
25
+ export interface WalletInfo {
26
+ address: string;
27
+ chain_type: string;
28
+ }
29
+ export interface CreditsInfo {
30
+ credits_available: number | null;
31
+ }
32
+ export interface SwapRequest {
33
+ chain_id_in: number;
34
+ chain_id_out: number;
35
+ token_in: string;
36
+ token_out: string;
37
+ amount: string;
38
+ slippage_bps?: number;
39
+ dryrun?: boolean;
40
+ stop_loss?: {
41
+ price_percentage: number;
42
+ sell_percentage: number;
43
+ };
44
+ take_profit?: {
45
+ price_percentage: number;
46
+ sell_percentage: number;
47
+ };
48
+ cancel_conditional_orders?: boolean;
49
+ }
50
+ export interface LimitOrderRequest {
51
+ chain_id_in: number;
52
+ chain_id_out: number;
53
+ token_in: string;
54
+ token_out: string;
55
+ amount: string;
56
+ price_usd_trigger: number;
57
+ trigger_token_address: string;
58
+ trigger_token_chain: string;
59
+ condition: "gte" | "lte";
60
+ slippage_bps?: number;
61
+ query?: string;
62
+ }
63
+ export interface HooksRequest {
64
+ chain_id: number;
65
+ token_address: string;
66
+ stop_loss?: {
67
+ price_percentage: number;
68
+ sell_percentage: number;
69
+ };
70
+ take_profit?: {
71
+ price_percentage: number;
72
+ sell_percentage: number;
73
+ };
74
+ }
75
+ export interface DepositRequest {
76
+ amount_usdc: number;
77
+ position_id?: string;
78
+ }
79
+ export interface WithdrawRequest {
80
+ position_id: string;
81
+ amount_usdc: number;
82
+ }
83
+ export declare class TaskTimeoutError extends Error {
84
+ readonly taskId: string;
85
+ readonly timeout: number;
86
+ constructor(taskId: string, timeout: number);
87
+ }
package/dist/types.js ADDED
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ /** Typed request/response models for the FereAI Gateway API. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.TaskTimeoutError = void 0;
5
+ class TaskTimeoutError extends Error {
6
+ taskId;
7
+ timeout;
8
+ constructor(taskId, timeout) {
9
+ super(`Task ${taskId} did not complete within ${timeout}s`);
10
+ this.name = "TaskTimeoutError";
11
+ this.taskId = taskId;
12
+ this.timeout = timeout;
13
+ }
14
+ }
15
+ exports.TaskTimeoutError = TaskTimeoutError;
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@fereai/sdk",
3
+ "version": "0.1.0-dev.4",
4
+ "description": "TypeScript SDK for the FereAI Gateway API",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "prepublishOnly": "tsc"
13
+ },
14
+ "dependencies": {
15
+ "@noble/ed25519": "^2.0.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^22.0",
19
+ "typescript": "^5.5"
20
+ },
21
+ "license": "MIT",
22
+ "author": "Fere AI <info@fere.ai>"
23
+ }