@1ly/mcp-server 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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +330 -0
  3. package/dist/budget.d.ts +7 -0
  4. package/dist/budget.d.ts.map +1 -0
  5. package/dist/budget.js +64 -0
  6. package/dist/budget.js.map +1 -0
  7. package/dist/config.d.ts +53 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +37 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/http.d.ts +26 -0
  12. package/dist/http.d.ts.map +1 -0
  13. package/dist/http.js +85 -0
  14. package/dist/http.js.map +1 -0
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +87 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/mcp.d.ts +22 -0
  20. package/dist/mcp.d.ts.map +1 -0
  21. package/dist/mcp.js +23 -0
  22. package/dist/mcp.js.map +1 -0
  23. package/dist/selftest.d.ts +2 -0
  24. package/dist/selftest.d.ts.map +1 -0
  25. package/dist/selftest.js +57 -0
  26. package/dist/selftest.js.map +1 -0
  27. package/dist/tools/call.d.ts +36 -0
  28. package/dist/tools/call.d.ts.map +1 -0
  29. package/dist/tools/call.js +131 -0
  30. package/dist/tools/call.js.map +1 -0
  31. package/dist/tools/create-link.d.ts +44 -0
  32. package/dist/tools/create-link.d.ts.map +1 -0
  33. package/dist/tools/create-link.js +62 -0
  34. package/dist/tools/create-link.js.map +1 -0
  35. package/dist/tools/delete-link.d.ts +22 -0
  36. package/dist/tools/delete-link.d.ts.map +1 -0
  37. package/dist/tools/delete-link.js +37 -0
  38. package/dist/tools/delete-link.js.map +1 -0
  39. package/dist/tools/details.d.ts +23 -0
  40. package/dist/tools/details.d.ts.map +1 -0
  41. package/dist/tools/details.js +101 -0
  42. package/dist/tools/details.js.map +1 -0
  43. package/dist/tools/get-stats.d.ts +26 -0
  44. package/dist/tools/get-stats.d.ts.map +1 -0
  45. package/dist/tools/get-stats.js +44 -0
  46. package/dist/tools/get-stats.js.map +1 -0
  47. package/dist/tools/list-links.d.ts +18 -0
  48. package/dist/tools/list-links.d.ts.map +1 -0
  49. package/dist/tools/list-links.js +30 -0
  50. package/dist/tools/list-links.js.map +1 -0
  51. package/dist/tools/review.d.ts +35 -0
  52. package/dist/tools/review.d.ts.map +1 -0
  53. package/dist/tools/review.js +73 -0
  54. package/dist/tools/review.js.map +1 -0
  55. package/dist/tools/search.d.ts +40 -0
  56. package/dist/tools/search.d.ts.map +1 -0
  57. package/dist/tools/search.js +79 -0
  58. package/dist/tools/search.js.map +1 -0
  59. package/dist/tools/update-link.d.ts +43 -0
  60. package/dist/tools/update-link.d.ts.map +1 -0
  61. package/dist/tools/update-link.js +61 -0
  62. package/dist/tools/update-link.js.map +1 -0
  63. package/dist/types.d.ts +61 -0
  64. package/dist/types.d.ts.map +1 -0
  65. package/dist/types.js +3 -0
  66. package/dist/types.js.map +1 -0
  67. package/dist/wallet/evm.d.ts +48 -0
  68. package/dist/wallet/evm.d.ts.map +1 -0
  69. package/dist/wallet/evm.js +229 -0
  70. package/dist/wallet/evm.js.map +1 -0
  71. package/dist/wallet/solana.d.ts +6 -0
  72. package/dist/wallet/solana.d.ts.map +1 -0
  73. package/dist/wallet/solana.js +95 -0
  74. package/dist/wallet/solana.js.map +1 -0
  75. package/package.json +70 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 1ly.store
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,330 @@
1
+ # @1ly/mcp-server
2
+
3
+ MCP server for [1ly.store](https://1ly.store) — Discover and pay for APIs with AI agents.
4
+
5
+ ## What is this?
6
+
7
+ This MCP server enables AI agents (Claude, GPT, Cursor, etc.) to:
8
+
9
+ 1. **Search** for APIs and services on 1ly.store
10
+ 2. **Get details** about pricing, reviews, and usage
11
+ 3. **Call APIs** with automatic crypto payments (x402 protocol)
12
+ 4. **Leave reviews** after purchases
13
+ 5. **Create and manage API links** (Developer Mode + API key)
14
+
15
+ ## Quick Start (1 minute)
16
+
17
+ Pick **one** of the following and paste it into your terminal.
18
+
19
+ ### Solana (mainnet)
20
+
21
+ ```bash
22
+ ONELY_WALLET_TYPE=solana \
23
+ ONELY_WALLET_KEY="$HOME/1ly-agent-wallet.json" \
24
+ npx @1ly/mcp-server
25
+ ```
26
+
27
+ ### Base (mainnet)
28
+
29
+ ```bash
30
+ ONELY_WALLET_TYPE=evm \
31
+ ONELY_WALLET_KEY="$HOME/.1ly-base-private-key" \
32
+ npx @1ly/mcp-server
33
+ ```
34
+
35
+ Optional safety limits:
36
+
37
+ ```bash
38
+ ONELY_BUDGET_PER_CALL=1.00
39
+ ONELY_BUDGET_DAILY=50.00
40
+ ```
41
+
42
+ ### Developer Mode (create/manage API links)
43
+
44
+ ```bash
45
+ ONELY_API_KEY="1ly_live_..." \
46
+ npx @1ly/mcp-server
47
+ ```
48
+
49
+ ## Get an API Key (Developer Mode)
50
+
51
+ 1. Sign in to 1ly store: `https://1ly.store`
52
+ 2. Open **Settings** (profile dropdown → Settings)
53
+ 3. Enable **Developer Mode**
54
+ 4. Open **Developer Settings** and click **Create API Key**
55
+ 5. Copy the key (shown once)
56
+
57
+ Keys look like:
58
+ ```
59
+ 1ly_live_xxxxxxxx...
60
+ ```
61
+
62
+ ## How API keys are used
63
+
64
+ - **For MCP tools**: set `ONELY_API_KEY` in your MCP config or environment.
65
+ The MCP server attaches it as `Authorization: Bearer <key>` automatically.
66
+ - **For direct API calls**: include the header yourself:
67
+
68
+ ```http
69
+ Authorization: Bearer 1ly_live_...
70
+ ```
71
+
72
+ ## Install (Claude Desktop)
73
+
74
+ Add to `claude_desktop_config.json`:
75
+
76
+ ```json
77
+ {
78
+ "mcpServers": {
79
+ "1ly": {
80
+ "command": "npx",
81
+ "args": ["@1ly/mcp-server"],
82
+ "env": {
83
+ "ONELY_WALLET_TYPE": "solana",
84
+ "ONELY_WALLET_KEY": "/path/to/solana-wallet.json",
85
+ "ONELY_BUDGET_PER_CALL": "1.00",
86
+ "ONELY_BUDGET_DAILY": "50.00"
87
+ }
88
+ }
89
+ }
90
+ }
91
+ ```
92
+
93
+ ### Developer Mode (API key only)
94
+
95
+ ```json
96
+ {
97
+ "mcpServers": {
98
+ "1ly": {
99
+ "command": "npx",
100
+ "args": ["@1ly/mcp-server"],
101
+ "env": {
102
+ "ONELY_API_KEY": "1ly_live_..."
103
+ }
104
+ }
105
+ }
106
+ }
107
+ ```
108
+
109
+ ## Install (Cursor)
110
+
111
+ Add to `.cursor/mcp.json`:
112
+
113
+ ```json
114
+ {
115
+ "servers": {
116
+ "1ly": {
117
+ "command": "npx @1ly/mcp-server",
118
+ "env": {
119
+ "ONELY_WALLET_TYPE": "solana",
120
+ "ONELY_WALLET_KEY": "/path/to/solana-wallet.json",
121
+ "ONELY_BUDGET_PER_CALL": "1.00",
122
+ "ONELY_BUDGET_DAILY": "50.00"
123
+ }
124
+ }
125
+ }
126
+ }
127
+ ```
128
+
129
+ ### Developer Mode (API key only)
130
+
131
+ ```json
132
+ {
133
+ "servers": {
134
+ "1ly": {
135
+ "command": "npx @1ly/mcp-server",
136
+ "env": {
137
+ "ONELY_API_KEY": "1ly_live_..."
138
+ }
139
+ }
140
+ }
141
+ }
142
+ ```
143
+
144
+ ## Verify it works (recommended)
145
+
146
+ Run a quick self-test:
147
+
148
+ ```bash
149
+ ONELY_WALLET_TYPE=solana \
150
+ ONELY_WALLET_KEY="$HOME/1ly-agent-wallet.json" \
151
+ npx @1ly/mcp-server --self-test
152
+ ```
153
+
154
+ ## What agents can do
155
+
156
+ Typical flow:
157
+
158
+ 1. `1ly_search` → find an API
159
+ 2. `1ly_get_details` → confirm price + supported networks
160
+ 3. `1ly_call` → auto‑pay with x402 v2 and return the API response
161
+ 4. `1ly_review` → optional review using the `_1ly` metadata
162
+ 5. `1ly_create_link` → create a paid or free API link (Developer Mode)
163
+
164
+ ## Tools
165
+
166
+ ### `1ly_search`
167
+
168
+ Search for APIs by keyword.
169
+
170
+ ```typescript
171
+ // Input
172
+ { query: "weather api", type: "api", maxPrice: 0.10 }
173
+
174
+ // Output
175
+ {
176
+ results: [
177
+ {
178
+ title: "Real-time Weather",
179
+ endpoint: "/api/link/joe/weather",
180
+ price: 0.01,
181
+ stats: { buyers: 150, rating: 95 }
182
+ }
183
+ ]
184
+ }
185
+ ```
186
+
187
+ ### `1ly_get_details`
188
+
189
+ Get full details about an API.
190
+
191
+ ```typescript
192
+ // Input
193
+ { endpoint: "joe/weather" }
194
+
195
+ // Output
196
+ {
197
+ title: "Real-time Weather",
198
+ description: "Global weather data with forecasts",
199
+ price: 0.01,
200
+ reviews: [...],
201
+ paymentInfo: { networks: ["solana", "base"] }
202
+ }
203
+ ```
204
+
205
+ ### `1ly_call`
206
+
207
+ Call an API with automatic payment.
208
+
209
+ ```typescript
210
+ // Input
211
+ { endpoint: "joe/weather", body: { city: "NYC" } }
212
+
213
+ // Output
214
+ {
215
+ data: { temp: 72, conditions: "sunny" },
216
+ _1ly: { purchaseId: "...", reviewToken: "..." }
217
+ }
218
+ ```
219
+
220
+ ### `1ly_review`
221
+
222
+ Leave a review after purchase.
223
+
224
+ ```typescript
225
+ // Input
226
+ { purchaseId: "...", reviewToken: "...", positive: true, comment: "Fast and accurate!" }
227
+
228
+ // Output
229
+ { success: true, reviewId: "..." }
230
+ ```
231
+
232
+ ### `1ly_create_link`
233
+
234
+ Create an API link (paid or free). Requires `ONELY_API_KEY`.
235
+
236
+ ```typescript
237
+ // Input
238
+ {
239
+ title: "Premium Trading Signals",
240
+ url: "https://example.com/signals",
241
+ price: "10.00",
242
+ description: "Daily crypto signals"
243
+ }
244
+ ```
245
+
246
+ ### `1ly_list_links`
247
+
248
+ List API links for the store. Requires `ONELY_API_KEY`.
249
+
250
+ ### `1ly_update_link`
251
+
252
+ Update an API link by id. Requires `ONELY_API_KEY`.
253
+
254
+ ### `1ly_delete_link`
255
+
256
+ Delete an API link by id. Requires `ONELY_API_KEY`.
257
+
258
+ ### `1ly_get_stats`
259
+
260
+ Fetch store or link stats. Requires `ONELY_API_KEY`.
261
+
262
+ ## Configuration
263
+
264
+ | Environment Variable | Required | Description |
265
+ |---------------------|----------|-------------|
266
+ | `ONELY_WALLET_TYPE` | Yes | `solana` or `evm` |
267
+ | `ONELY_WALLET_KEY` | Yes | Private key or path to keyfile |
268
+ | `ONELY_BUDGET_PER_CALL` | No | Max USD per call (default: 1.00) |
269
+ | `ONELY_BUDGET_DAILY` | No | Daily USD limit (default: 50.00) |
270
+ | `ONELY_NETWORK` | No | Preferred network (default: solana) |
271
+ | `ONELY_API_KEY` | No | Developer Mode API key for link management |
272
+
273
+ ## Wallet Setup
274
+
275
+ ### Solana
276
+
277
+ Create a wallet keypair:
278
+
279
+ ```bash
280
+ solana-keygen new -o ~/1ly-agent-wallet.json
281
+ ```
282
+
283
+ Fund it with USDC on Solana mainnet.
284
+
285
+ ### EVM (Base)
286
+
287
+ Create an EVM wallet (Base-compatible) and provide its **private key** via `ONELY_WALLET_KEY`.
288
+
289
+ - **Option A (recommended)**: export your private key from your wallet (e.g. MetaMask/Rabby) and save it to a local file (one line, with or without `0x` prefix).
290
+ - **Option B**: set the private key directly as an env var (not recommended for shared machines).
291
+
292
+ Examples:
293
+
294
+ ```bash
295
+ # from a file
296
+ export ONELY_WALLET_TYPE=evm
297
+ export ONELY_WALLET_KEY="$HOME/.1ly-base-private-key"
298
+
299
+ # or inline (starts with 0x...)
300
+ export ONELY_WALLET_TYPE=evm
301
+ export ONELY_WALLET_KEY="0xYOUR_PRIVATE_KEY"
302
+ ```
303
+
304
+ ## Devnet / testnets (coming soon)
305
+
306
+ We plan to offer an official devnet/testnet endpoint so you can try 1ly with test USDC before mainnet. For now, production usage requires mainnet USDC.
307
+
308
+ ## Troubleshooting
309
+
310
+ - **Missing wallet**: Set `ONELY_WALLET_TYPE` and `ONELY_WALLET_KEY`.
311
+ - **Missing API key**: Set `ONELY_API_KEY` to use link management tools.
312
+ - **402 errors on first call**: Expected — `1ly_call` handles payment automatically.
313
+ - **Insufficient funds**: Fund your wallet with USDC on the selected network.
314
+ - **Review failed**: Ensure you pass the exact `purchaseId` + `reviewToken` returned by `1ly_call`.
315
+
316
+ ## Security
317
+
318
+ - **Wallet keys stay local** — Never sent to 1ly servers
319
+ - **Budget limits** — Prevent runaway spending
320
+ - **Open source** — Audit the code yourself
321
+
322
+ ## Links
323
+
324
+ - [1ly.store](https://1ly.store) — Marketplace
325
+ - [Documentation](https://docs.1ly.store)
326
+ - [x402 Protocol](https://x402.org)
327
+
328
+ ## License
329
+
330
+ MIT
@@ -0,0 +1,7 @@
1
+ import type { Config } from "./config.js";
2
+ /**
3
+ * Enforces daily budget by reading/modifying a small JSON file on disk.
4
+ * Throws if this call would exceed the configured daily limit.
5
+ */
6
+ export declare function checkAndRecordDailySpend(config: Config, priceUsd: number): void;
7
+ //# sourceMappingURL=budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../src/budget.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAmD1C;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAuB/E"}
package/dist/budget.js ADDED
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.checkAndRecordDailySpend = checkAndRecordDailySpend;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const os_1 = __importDefault(require("os"));
9
+ const path_1 = __importDefault(require("path"));
10
+ function getBudgetStatePath() {
11
+ const envPath = process.env.ONELY_BUDGET_STATE_FILE;
12
+ if (envPath && envPath.trim().length > 0) {
13
+ return envPath;
14
+ }
15
+ return path_1.default.join(os_1.default.homedir(), ".1ly-mcp-budget.json");
16
+ }
17
+ function loadBudgetState() {
18
+ const filePath = getBudgetStatePath();
19
+ try {
20
+ if (!fs_1.default.existsSync(filePath)) {
21
+ return { date: new Date().toISOString().slice(0, 10), spentToday: 0 };
22
+ }
23
+ const raw = fs_1.default.readFileSync(filePath, "utf-8");
24
+ const parsed = JSON.parse(raw);
25
+ const today = new Date().toISOString().slice(0, 10);
26
+ // Reset if date changed or data invalid
27
+ if (!parsed.date || typeof parsed.spentToday !== "number" || parsed.date !== today) {
28
+ return { date: today, spentToday: 0 };
29
+ }
30
+ return parsed;
31
+ }
32
+ catch {
33
+ // On any error, fall back to fresh state
34
+ return { date: new Date().toISOString().slice(0, 10), spentToday: 0 };
35
+ }
36
+ }
37
+ function saveBudgetState(state) {
38
+ const filePath = getBudgetStatePath();
39
+ try {
40
+ fs_1.default.writeFileSync(filePath, JSON.stringify(state, null, 2), { encoding: "utf-8" });
41
+ }
42
+ catch {
43
+ // If we cannot persist, we still allow the call; fail-open is safer for UX
44
+ }
45
+ }
46
+ /**
47
+ * Enforces daily budget by reading/modifying a small JSON file on disk.
48
+ * Throws if this call would exceed the configured daily limit.
49
+ */
50
+ function checkAndRecordDailySpend(config, priceUsd) {
51
+ const today = new Date().toISOString().slice(0, 10);
52
+ const state = loadBudgetState();
53
+ const current = state.date === today ? state.spentToday : 0;
54
+ const next = current + priceUsd;
55
+ if (next > config.budgets.daily) {
56
+ throw new Error(`Price $${priceUsd.toFixed(4)} would exceed daily budget of $${config.budgets.daily} (already spent: $${current.toFixed(4)})`);
57
+ }
58
+ const updated = {
59
+ date: today,
60
+ spentToday: next,
61
+ };
62
+ saveBudgetState(updated);
63
+ }
64
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../src/budget.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import { z } from "zod";
2
+ export declare const ConfigSchema: z.ZodObject<{
3
+ apiBase: z.ZodDefault<z.ZodString>;
4
+ wallet: z.ZodNullable<z.ZodOptional<z.ZodObject<{
5
+ type: z.ZodEnum<["solana", "evm"]>;
6
+ key: z.ZodString;
7
+ }, "strip", z.ZodTypeAny, {
8
+ type: "solana" | "evm";
9
+ key: string;
10
+ }, {
11
+ type: "solana" | "evm";
12
+ key: string;
13
+ }>>>;
14
+ budgets: z.ZodObject<{
15
+ perCall: z.ZodDefault<z.ZodNumber>;
16
+ daily: z.ZodDefault<z.ZodNumber>;
17
+ }, "strip", z.ZodTypeAny, {
18
+ perCall: number;
19
+ daily: number;
20
+ }, {
21
+ perCall?: number | undefined;
22
+ daily?: number | undefined;
23
+ }>;
24
+ network: z.ZodDefault<z.ZodEnum<["solana", "base"]>>;
25
+ apiKey: z.ZodNullable<z.ZodOptional<z.ZodString>>;
26
+ }, "strip", z.ZodTypeAny, {
27
+ apiBase: string;
28
+ budgets: {
29
+ perCall: number;
30
+ daily: number;
31
+ };
32
+ network: "solana" | "base";
33
+ wallet?: {
34
+ type: "solana" | "evm";
35
+ key: string;
36
+ } | null | undefined;
37
+ apiKey?: string | null | undefined;
38
+ }, {
39
+ budgets: {
40
+ perCall?: number | undefined;
41
+ daily?: number | undefined;
42
+ };
43
+ apiBase?: string | undefined;
44
+ wallet?: {
45
+ type: "solana" | "evm";
46
+ key: string;
47
+ } | null | undefined;
48
+ network?: "solana" | "base" | undefined;
49
+ apiKey?: string | null | undefined;
50
+ }>;
51
+ export type Config = z.infer<typeof ConfigSchema>;
52
+ export declare function loadConfig(): Config;
53
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAevB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD,wBAAgB,UAAU,IAAI,MAAM,CAenC"}
package/dist/config.js ADDED
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConfigSchema = void 0;
4
+ exports.loadConfig = loadConfig;
5
+ const zod_1 = require("zod");
6
+ exports.ConfigSchema = zod_1.z.object({
7
+ apiBase: zod_1.z.string().url().default("https://1ly.store"),
8
+ wallet: zod_1.z
9
+ .object({
10
+ type: zod_1.z.enum(["solana", "evm"]),
11
+ key: zod_1.z.string(),
12
+ })
13
+ .optional()
14
+ .nullable(),
15
+ budgets: zod_1.z.object({
16
+ perCall: zod_1.z.number().positive().default(1.0),
17
+ daily: zod_1.z.number().positive().default(50.0),
18
+ }),
19
+ network: zod_1.z.enum(["solana", "base"]).default("solana"),
20
+ apiKey: zod_1.z.string().optional().nullable(),
21
+ });
22
+ function loadConfig() {
23
+ const walletType = process.env.ONELY_WALLET_TYPE;
24
+ const walletKey = process.env.ONELY_WALLET_KEY;
25
+ const apiKey = process.env.ONELY_API_KEY || null;
26
+ return exports.ConfigSchema.parse({
27
+ apiBase: "https://1ly.store",
28
+ wallet: walletType && walletKey ? { type: walletType, key: walletKey } : null,
29
+ budgets: {
30
+ perCall: parseFloat(process.env.ONELY_BUDGET_PER_CALL || "1.0"),
31
+ daily: parseFloat(process.env.ONELY_BUDGET_DAILY || "50.0"),
32
+ },
33
+ network: process.env.ONELY_NETWORK || "solana",
34
+ apiKey,
35
+ });
36
+ }
37
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;AAqBA,gCAeC;AApCD,6BAAwB;AAEX,QAAA,YAAY,GAAG,OAAC,CAAC,MAAM,CAAC;IACnC,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC;IACtD,MAAM,EAAE,OAAC;SACN,MAAM,CAAC;QACN,IAAI,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC/B,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE;KAChB,CAAC;SACD,QAAQ,EAAE;SACV,QAAQ,EAAE;IACb,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC;QAChB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;QAC3C,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;KAC3C,CAAC;IACF,OAAO,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACrD,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CACzC,CAAC,CAAC;AAIH,SAAgB,UAAU;IACxB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACjD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC;IAEjD,OAAO,oBAAY,CAAC,KAAK,CAAC;QACxB,OAAO,EAAE,mBAAmB;QAC5B,MAAM,EAAE,UAAU,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI;QAC7E,OAAO,EAAE;YACP,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,KAAK,CAAC;YAC/D,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,MAAM,CAAC;SAC5D;QACD,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,QAAQ;QAC9C,MAAM;KACP,CAAC,CAAC;AACL,CAAC"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ export interface FetchOptions extends RequestInit {
2
+ /** Override timeout in milliseconds (default: 15000) */
3
+ timeoutMs?: number;
4
+ /** Number of retry attempts for transient errors (default: 2) */
5
+ retries?: number;
6
+ /** Delay between retries in milliseconds (default: 500) */
7
+ retryDelayMs?: number;
8
+ }
9
+ export declare class HttpError extends Error {
10
+ readonly status?: number | undefined;
11
+ readonly url?: string | undefined;
12
+ readonly bodySnippet?: string | undefined;
13
+ constructor(message: string, status?: number | undefined, url?: string | undefined, bodySnippet?: string | undefined);
14
+ }
15
+ /**
16
+ * fetchWithTimeout wraps the global fetch with:
17
+ * - per-request timeout using AbortController
18
+ * - basic retry logic for network/timeout errors
19
+ */
20
+ export declare function fetchWithTimeout(url: string, options?: FetchOptions): Promise<Response>;
21
+ /**
22
+ * Helper to throw a rich HttpError when response.ok is false.
23
+ * Reads a small snippet of the body (if any) for easier debugging.
24
+ */
25
+ export declare function assertOk(response: Response, contextMessage: string): Promise<void>;
26
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,SAAU,SAAQ,KAAK;aAGhB,MAAM,CAAC,EAAE,MAAM;aACf,GAAG,CAAC,EAAE,MAAM;aACZ,WAAW,CAAC,EAAE,MAAM;gBAHpC,OAAO,EAAE,MAAM,EACC,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,GAAG,CAAC,EAAE,MAAM,YAAA,EACZ,WAAW,CAAC,EAAE,MAAM,YAAA;CAKvC;AAMD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,QAAQ,CAAC,CA4CnB;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,QAAQ,EAClB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAqBf"}
package/dist/http.js ADDED
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpError = void 0;
4
+ exports.fetchWithTimeout = fetchWithTimeout;
5
+ exports.assertOk = assertOk;
6
+ const DEFAULT_TIMEOUT_MS = 15_000;
7
+ const DEFAULT_RETRIES = 2;
8
+ const DEFAULT_RETRY_DELAY_MS = 500;
9
+ class HttpError extends Error {
10
+ status;
11
+ url;
12
+ bodySnippet;
13
+ constructor(message, status, url, bodySnippet) {
14
+ super(message);
15
+ this.status = status;
16
+ this.url = url;
17
+ this.bodySnippet = bodySnippet;
18
+ this.name = "HttpError";
19
+ }
20
+ }
21
+ exports.HttpError = HttpError;
22
+ function sleep(ms) {
23
+ return new Promise((resolve) => setTimeout(resolve, ms));
24
+ }
25
+ /**
26
+ * fetchWithTimeout wraps the global fetch with:
27
+ * - per-request timeout using AbortController
28
+ * - basic retry logic for network/timeout errors
29
+ */
30
+ async function fetchWithTimeout(url, options = {}) {
31
+ const { timeoutMs = DEFAULT_TIMEOUT_MS, retries = DEFAULT_RETRIES, retryDelayMs = DEFAULT_RETRY_DELAY_MS, ...fetchOptions } = options;
32
+ let lastError;
33
+ for (let attempt = 0; attempt <= retries; attempt++) {
34
+ const controller = new AbortController();
35
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
36
+ try {
37
+ const response = await fetch(url, {
38
+ ...fetchOptions,
39
+ signal: controller.signal,
40
+ });
41
+ clearTimeout(timeout);
42
+ return response;
43
+ }
44
+ catch (error) {
45
+ clearTimeout(timeout);
46
+ lastError = error;
47
+ // If this was the last attempt, rethrow
48
+ if (attempt === retries) {
49
+ throw new Error(`Request to ${url} failed after ${retries + 1} attempt(s): ${error instanceof Error ? error.message : String(error)}`);
50
+ }
51
+ // Otherwise wait and retry
52
+ await sleep(retryDelayMs);
53
+ }
54
+ }
55
+ // Should be unreachable, but TypeScript needs a return/throw
56
+ throw lastError instanceof Error
57
+ ? lastError
58
+ : new Error(`Request to ${url} failed for unknown reasons`);
59
+ }
60
+ /**
61
+ * Helper to throw a rich HttpError when response.ok is false.
62
+ * Reads a small snippet of the body (if any) for easier debugging.
63
+ */
64
+ async function assertOk(response, contextMessage) {
65
+ if (response.ok)
66
+ return;
67
+ let bodySnippet;
68
+ try {
69
+ const text = await response.text();
70
+ bodySnippet = text.slice(0, 500);
71
+ }
72
+ catch {
73
+ // Ignore body read errors
74
+ }
75
+ const url = response.url;
76
+ const messageParts = [
77
+ contextMessage,
78
+ `status=${response.status}`,
79
+ response.statusText && `statusText=${response.statusText}`,
80
+ url && `url=${url}`,
81
+ bodySnippet && `body=${bodySnippet}`,
82
+ ].filter(Boolean);
83
+ throw new HttpError(messageParts.join(" | "), response.status, url, bodySnippet);
84
+ }
85
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}