@blindmarket/sdk 0.1.8 → 0.4.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 (87) hide show
  1. package/dist/executor/WorkerRuntime.d.ts +21 -0
  2. package/dist/executor/WorkerRuntime.js +56 -27
  3. package/dist/index.d.ts +75 -9
  4. package/dist/index.js +52 -3
  5. package/package.json +8 -1
  6. package/biome.json +0 -19
  7. package/examples/agent-demo.ts +0 -121
  8. package/scripts/gen-crypto-fixtures.mjs +0 -72
  9. package/src/agent/Agent.ts +0 -122
  10. package/src/agent/index.ts +0 -1
  11. package/src/api/index.ts +0 -1
  12. package/src/chain/BlindEscrowClient.ts +0 -196
  13. package/src/chain/BlindReputationClient.ts +0 -60
  14. package/src/chain/ChainClient.ts +0 -65
  15. package/src/chain/IBlindMarketChain.ts +0 -109
  16. package/src/chain/TaskRegistryClient.ts +0 -91
  17. package/src/chain/abi/BlindEscrow.json +0 -1113
  18. package/src/chain/abi/BlindReputation.json +0 -447
  19. package/src/chain/abi/TaskRegistry.json +0 -586
  20. package/src/chain/abi/index.ts +0 -5
  21. package/src/chain/createChainAdapter.ts +0 -40
  22. package/src/chain/domain-types.ts +0 -92
  23. package/src/chain/errors.ts +0 -43
  24. package/src/chain/evm/EVMChainAdapter.ts +0 -212
  25. package/src/chain/evm/index.ts +0 -1
  26. package/src/chain/index.ts +0 -12
  27. package/src/compute/index.ts +0 -1
  28. package/src/crypto/aes.ts +0 -104
  29. package/src/crypto/constants.ts +0 -7
  30. package/src/crypto/ecies.ts +0 -60
  31. package/src/crypto/envelope.ts +0 -131
  32. package/src/crypto/hkdf.ts +0 -45
  33. package/src/crypto/index.ts +0 -6
  34. package/src/crypto/keys.ts +0 -56
  35. package/src/errors/BlindMarketError.ts +0 -38
  36. package/src/errors/codes.ts +0 -67
  37. package/src/errors/index.ts +0 -3
  38. package/src/errors/subclasses.ts +0 -59
  39. package/src/events/EventBus.ts +0 -45
  40. package/src/events/index.ts +0 -2
  41. package/src/events/types.ts +0 -13
  42. package/src/executor/WorkerRuntime.ts +0 -338
  43. package/src/executor/index.ts +0 -8
  44. package/src/index.ts +0 -636
  45. package/src/keystore/InMemoryKeyStore.ts +0 -146
  46. package/src/keystore/KeyStore.ts +0 -19
  47. package/src/keystore/index.ts +0 -2
  48. package/src/network/index.ts +0 -3
  49. package/src/network/presets.ts +0 -66
  50. package/src/network/resolve.ts +0 -31
  51. package/src/network/types.ts +0 -20
  52. package/src/signer/EthersSigner.ts +0 -82
  53. package/src/signer/PrivateKeySigner.ts +0 -19
  54. package/src/signer/Signer.ts +0 -40
  55. package/src/signer/index.ts +0 -3
  56. package/src/storage/MemoryStorage.ts +0 -49
  57. package/src/storage/Storage.ts +0 -15
  58. package/src/storage/ZgStorage.ts +0 -124
  59. package/src/storage/index.ts +0 -3
  60. package/src/testing/index.ts +0 -1
  61. package/src/tools/adapters.ts +0 -177
  62. package/src/tools/helpers.ts +0 -199
  63. package/src/tools/index.ts +0 -59
  64. package/src/tools/types.ts +0 -47
  65. package/src/types.ts +0 -297
  66. package/src/verifier/index.ts +0 -1
  67. package/src/worker/Worker.ts +0 -98
  68. package/src/worker/index.ts +0 -1
  69. package/test/agent.test.ts +0 -193
  70. package/test/chain.test.ts +0 -145
  71. package/test/crypto.aes.test.ts +0 -81
  72. package/test/crypto.compat.test.ts +0 -33
  73. package/test/crypto.ecies.test.ts +0 -64
  74. package/test/envelope.test.ts +0 -82
  75. package/test/errors.test.ts +0 -64
  76. package/test/events.test.ts +0 -59
  77. package/test/fixtures/crypto.json +0 -16
  78. package/test/keystore.test.ts +0 -103
  79. package/test/network.test.ts +0 -53
  80. package/test/signer.test.ts +0 -66
  81. package/test/smoke.test.ts +0 -7
  82. package/test/storage.test.ts +0 -55
  83. package/test/worker.test.ts +0 -181
  84. package/tsconfig.build.json +0 -1
  85. package/tsconfig.json +0 -14
  86. package/tsup.config.ts +0 -32
  87. package/vitest.config.ts +0 -17
package/src/index.ts DELETED
@@ -1,636 +0,0 @@
1
- import { ethers } from 'ethers';
2
- import type {
3
- Address, Hex, HealthStatus, PlatformStats, OpenTask, TaskDetail,
4
- CreateTaskTx, ExecutorProfile, RegisterExecutorInput,
5
- DeployedAgentInfo, AgentWalletInfo, ReputationInfo, LeaderboardEntry,
6
- StorageUploadResult, Message, AgentSearchResult, TaskTemplate,
7
- VerifyTaskInput, A2ATaskState, AgentCapability,
8
- CreateAgentParams, CreateAgentResult,
9
- } from './types.js';
10
-
11
- // ── Public config ───────────────────────────────────────────────────────────
12
-
13
- export interface BlindMarketConfig {
14
- /** Backend API base URL (default: https://api.blindmarket.xyz) */
15
- apiBase?: string;
16
- /** API key — shared AGENT_API_KEY or device-flow token */
17
- apiKey: string;
18
- }
19
-
20
- // ── Agent deployment params ─────────────────────────────────────────────────
21
-
22
- export interface DeployAgentParams {
23
- name: string;
24
- instructions: string;
25
- provider: 'openai' | 'anthropic' | 'groq' | 'gemini';
26
- model: string;
27
- apiKey: string;
28
- ownerAddress: string;
29
- ownerPublicKey: string;
30
- capabilities?: string[];
31
- tools?: object[];
32
- }
33
-
34
- export interface DeployedAgent {
35
- id: string;
36
- name: string;
37
- walletAddress: string;
38
- publicKey: string;
39
- inftTokenId?: number;
40
- status: string;
41
- }
42
-
43
- // ── Helpers ─────────────────────────────────────────────────────────────────
44
-
45
- class ApiError extends Error {
46
- constructor(
47
- public status: number,
48
- message: string,
49
- public body?: unknown,
50
- ) {
51
- super(message);
52
- this.name = 'ApiError';
53
- }
54
- }
55
-
56
- // ── Main client ─────────────────────────────────────────────────────────────
57
-
58
- /**
59
- * BlindMarket REST API client.
60
- *
61
- * Two usage modes:
62
- * 1. **High-level (this class)** — talks to the BlindMarket backend over REST.
63
- * Covers the full task lifecycle, agent management, A2A, and marketplace.
64
- * 2. **Low-level primitives** — `Agent`, `Worker`, `PrivateKeySigner`, etc.
65
- * for on-chain + crypto operations when you need direct chain access.
66
- *
67
- * @example
68
- * ```ts
69
- * const bb = new BlindMarket({ apiKey: process.env.BLINDMARKET_API_KEY! });
70
- *
71
- * // Deploy an agent
72
- * const agent = await bb.deployAgent({ name: 'my-agent', ... });
73
- *
74
- * // Watch for status changes
75
- * const unsub = bb.watchTask(42, (state) => console.log(state.status));
76
- * ```
77
- */
78
- export class BlindMarket {
79
- private apiBase: string;
80
- private apiKey: string;
81
-
82
- constructor(config: BlindMarketConfig) {
83
- this.apiBase = config.apiBase ?? 'https://api.blindmarket.xyz';
84
- this.apiKey = config.apiKey;
85
- }
86
-
87
- // ── Tools ─────────────────────────────────────────────────────────────────
88
-
89
- /**
90
- * Tool definitions for AI agent frameworks. Access framework-specific formats
91
- * via property — no need to remember adapter function names.
92
- *
93
- * IMPORTANT: due to ESM circular-dependency constraints this is a standalone
94
- * function rather than an instance getter. You pass `bb` once and reach the
95
- * format you need.
96
- *
97
- * @example
98
- * ```ts
99
- * import { BlindMarket, tools } from '@blindmarket/sdk';
100
- * const bb = new BlindMarket({ apiKey });
101
- *
102
- * // OpenAI (default — also works with Vercel AI SDK)
103
- * openai.chat.completions.create({ model: 'gpt-4', tools: tools(bb).definitions });
104
- *
105
- * // LangChain
106
- * createReactAgent({ llm, tools: tools(bb).langchain });
107
- *
108
- * // Claude
109
- * anthropic.messages.create({ model, tools: tools(bb).claude });
110
- *
111
- * // Vercel
112
- * generateText({ model, tools: tools(bb).vercel });
113
- * ```
114
- */
115
-
116
- private async req<T>(method: string, path: string, body?: unknown): Promise<T> {
117
- const res = await fetch(`${this.apiBase}${path}`, {
118
- method,
119
- headers: {
120
- 'Content-Type': 'application/json',
121
- Authorization: `Bearer ${this.apiKey}`,
122
- },
123
- body: body ? JSON.stringify(body) : undefined,
124
- });
125
- const json = await res.json() as { success: boolean; data?: T; error?: { message: string } };
126
- if (!json.success) {
127
- throw new ApiError(res.status, json.error?.message ?? `HTTP ${res.status}`, json);
128
- }
129
- return json.data as T;
130
- }
131
-
132
- // ── Health & Stats ──────────────────────────────────────────────────────
133
-
134
- /** Backend liveness check. */
135
- async health(): Promise<HealthStatus> {
136
- return this.req<HealthStatus>('GET', '/health');
137
- }
138
-
139
- /** Live platform counts. */
140
- async stats(): Promise<PlatformStats> {
141
- return this.req<PlatformStats>('GET', '/api/v1/stats');
142
- }
143
-
144
- // ── Task lifecycle ──────────────────────────────────────────────────────
145
-
146
- /** List open tasks (human-readable). */
147
- async listTasks(limit = 20): Promise<OpenTask[]> {
148
- const { tasks } = await this.req<{ tasks: OpenTask[] }>('GET', `/api/v1/tasks?limit=${limit}`);
149
- return tasks;
150
- }
151
-
152
- /** Get full task details (on-chain + A2A state). */
153
- async getTask(id: string): Promise<TaskDetail> {
154
- return this.req<TaskDetail>('GET', `/api/v1/tasks/${id}`);
155
- }
156
-
157
- /**
158
- * Build an unsigned `createTask` transaction.
159
- * You must sign and broadcast it with your wallet.
160
- */
161
- async createTask(params: {
162
- agent: Address;
163
- amount: string;
164
- token: Address;
165
- category: string;
166
- locationZone: string;
167
- deadline: number;
168
- }): Promise<CreateTaskTx> {
169
- return this.req<CreateTaskTx>('POST', '/api/v1/tasks', params);
170
- }
171
-
172
- /**
173
- * Build an unsigned `assignWorker` transaction.
174
- */
175
- async assignWorker(taskId: string, worker: Address): Promise<{ unsignedTx: object }> {
176
- return this.req('POST', `/api/v1/tasks/${taskId}/assign`, { worker });
177
- }
178
-
179
- /**
180
- * Build an unsigned `cancelTask` transaction.
181
- */
182
- async cancelTask(taskId: string): Promise<{ unsignedTx: object }> {
183
- return this.req('POST', `/api/v1/tasks/${taskId}/cancel`);
184
- }
185
-
186
- /**
187
- * Build an unsigned `claimTimeout` transaction.
188
- */
189
- async claimTimeout(taskId: string): Promise<{ unsignedTx: object }> {
190
- return this.req('POST', `/api/v1/tasks/${taskId}/timeout`);
191
- }
192
-
193
- /**
194
- * Build an unsigned `submitEvidence` transaction.
195
- */
196
- async submitEvidence(params: {
197
- taskId: string;
198
- evidenceHash: Hex;
199
- }): Promise<{ unsignedTx: object }> {
200
- return this.req('POST', '/api/v1/submissions/submit', params);
201
- }
202
-
203
- // ── Agent deployment & management ─────────────────────────────────────────
204
-
205
- /**
206
- * Deploy a new agent. The backend generates a wallet, mints an INFT,
207
- * and returns the agent descriptor.
208
- *
209
- * @example
210
- * const agent = await bb.deployAgent({
211
- * name: 'research-agent',
212
- * instructions: 'You research topics and post tasks.',
213
- * provider: 'anthropic',
214
- * model: 'claude-sonnet-4-5',
215
- * apiKey: process.env.ANTHROPIC_API_KEY!,
216
- * ownerAddress: wallet.address,
217
- * ownerPublicKey: wallet.publicKey,
218
- * });
219
- */
220
- async deployAgent(params: DeployAgentParams): Promise<DeployedAgent> {
221
- return this.req<DeployedAgent>('POST', '/api/v1/agents/deploy', params);
222
- }
223
-
224
- /**
225
- * One-shot agent creation: generates a secp256k1 wallet, then registers the
226
- * agent as an executor in the A2A marketplace with the generated wallet
227
- * address and public key. Replaces the manual two-step flow of generating a
228
- * wallet, then calling registerExecutor().
229
- *
230
- * The private key is returned **once** in the response — store it securely.
231
- *
232
- * @example
233
- * const { executor, wallet } = await bb.createAgent({
234
- * displayName: 'DataBot',
235
- * capabilities: [AgentCap.DATA_PROCESSING, AgentCap.WEB_RESEARCH],
236
- * minReward: '1000000000000000000', // 1 0G in wei
237
- * });
238
- * console.log(`Agent ${wallet.address} registered as ${executor.address}`);
239
- */
240
- async createAgent(params: CreateAgentParams): Promise<CreateAgentResult> {
241
- const wallet = ethers.Wallet.createRandom();
242
- const executor: RegisterExecutorInput = {
243
- address: wallet.address as Address,
244
- displayName: params.displayName,
245
- capabilities: params.capabilities,
246
- publicKey: wallet.publicKey.slice(2), // strip 0x prefix — backend expects raw hex
247
- agentCardUrl: params.agentCardUrl,
248
- mcpEndpointUrl: params.mcpEndpointUrl,
249
- minReward: params.minReward,
250
- preferredCapabilities: params.preferredCapabilities,
251
- };
252
- const result = await this.registerExecutor(executor);
253
- return {
254
- executor: result.agent,
255
- wallet: {
256
- address: wallet.address as Address,
257
- publicKey: wallet.publicKey,
258
- privateKey: wallet.privateKey,
259
- },
260
- };
261
- }
262
-
263
- /** List deployed agents, optionally filtered by owner address. */
264
- async listAgents(ownerAddress?: string): Promise<DeployedAgentInfo[]> {
265
- const qs = ownerAddress ? `?owner=${ownerAddress}` : '';
266
- return this.req<DeployedAgentInfo[]>('GET', `/api/v1/agents${qs}`);
267
- }
268
-
269
- /** Get a single deployed agent by ID. */
270
- async getAgent(id: string): Promise<DeployedAgentInfo> {
271
- return this.req<DeployedAgentInfo>('GET', `/api/v1/agents/${id}`);
272
- }
273
-
274
- /** Get an agent's on-chain wallet address. */
275
- async getAgentWallet(id: string): Promise<AgentWalletInfo> {
276
- return this.req<AgentWalletInfo>('GET', `/api/v1/agents/${id}/wallet`);
277
- }
278
-
279
- /** Start a deployed agent. Requires owner auth. */
280
- async startAgent(id: string): Promise<DeployedAgentInfo> {
281
- return this.req<DeployedAgentInfo>('POST', `/api/v1/agents/${id}/start`);
282
- }
283
-
284
- /** Stop a deployed agent. Requires owner auth. */
285
- async stopAgent(id: string): Promise<DeployedAgentInfo> {
286
- return this.req<DeployedAgentInfo>('POST', `/api/v1/agents/${id}/stop`);
287
- }
288
-
289
- /** Pause a deployed agent. Requires owner auth. */
290
- async pauseAgent(id: string): Promise<DeployedAgentInfo> {
291
- return this.req<DeployedAgentInfo>('POST', `/api/v1/agents/${id}/pause`);
292
- }
293
-
294
- /** Restart a deployed agent. Requires owner auth. */
295
- async restartAgent(id: string): Promise<DeployedAgentInfo> {
296
- return this.req<DeployedAgentInfo>('POST', `/api/v1/agents/${id}/restart`);
297
- }
298
-
299
- /**
300
- * Update a deployed agent's config (instructions, model, tools, etc.).
301
- * Requires owner auth.
302
- */
303
- async updateAgent(id: string, patch: Partial<{
304
- instructions: string;
305
- model: string;
306
- capabilities: string[];
307
- tools: object[];
308
- minReward: string;
309
- }>): Promise<DeployedAgentInfo> {
310
- return this.req<DeployedAgentInfo>('PATCH', `/api/v1/agents/${id}`, patch);
311
- }
312
-
313
- // ── A2A executor registration ───────────────────────────────────────────
314
-
315
- /** Register as an A2A agent executor (worker-side). */
316
- async registerExecutor(params: RegisterExecutorInput): Promise<{ agent: ExecutorProfile }> {
317
- return this.req('POST', '/api/v1/a2a/register', params);
318
- }
319
-
320
- /** List registered A2A executors, optionally filtered by capability. */
321
- async listExecutors(capabilities?: string[]): Promise<{ executors: ExecutorProfile[] }> {
322
- const qs = capabilities?.length ? `?capabilities=${capabilities.join(',')}` : '';
323
- return this.req('GET', `/api/v1/a2a/executors${qs}`);
324
- }
325
-
326
- /** Get own executor profile with on-chain + decayed reputation. */
327
- async getExecutorProfile(): Promise<{ agent: ExecutorProfile }> {
328
- return this.req('GET', '/api/v1/a2a/profile');
329
- }
330
-
331
- // ── A2A task lifecycle ───────────────────────────────────────────────────
332
-
333
- /** Browse A2A tasks available for execution. */
334
- async browseA2ATasks(params?: {
335
- capabilities?: string[];
336
- minReputation?: number;
337
- }): Promise<{ tasks: A2ATaskState[] }> {
338
- const qs = new URLSearchParams();
339
- if (params?.capabilities) qs.set('capabilities', params.capabilities.join(','));
340
- if (params?.minReputation != null) qs.set('minReputation', String(params.minReputation));
341
- const suffix = qs.toString() ? `?${qs.toString()}` : '';
342
- return this.req('GET', `/api/v1/a2a/tasks${suffix}`);
343
- }
344
-
345
- /** Register intent to accept a task (bid). */
346
- async bidOnTask(taskId: string): Promise<void> {
347
- return this.req('POST', `/api/v1/a2a/tasks/${taskId}/bid`);
348
- }
349
-
350
- /** Accept a task and get wrapped AES key. Requires executor auth. */
351
- async acceptTask(taskId: string): Promise<{ task: A2ATaskState; wrappedKey: Record<string, string> }> {
352
- return this.req('POST', `/api/v1/a2a/tasks/${taskId}/accept`);
353
- }
354
-
355
- /** Submit result for an accepted task. */
356
- async submitResult(taskId: string, resultData: Record<string, unknown>): Promise<{
357
- unsignedTx: object;
358
- task: A2ATaskState;
359
- }> {
360
- return this.req('POST', `/api/v1/a2a/tasks/${taskId}/submit`, { resultData });
361
- }
362
-
363
- /** Get tasks posted by the authenticated user. */
364
- async getPostedTasks(): Promise<{ tasks: A2ATaskState[] }> {
365
- return this.req('GET', '/api/v1/a2a/tasks/posted');
366
- }
367
-
368
- /** Get tasks executed by the authenticated user. */
369
- async getExecutions(address?: string): Promise<{ tasks: A2ATaskState[] }> {
370
- const qs = address ? `?address=${address}` : '';
371
- return this.req('GET', `/api/v1/a2a/executions${qs}`);
372
- }
373
-
374
- // ── Verification ─────────────────────────────────────────────────────────
375
-
376
- /**
377
- * Trigger TEE / AI verification for a task.
378
- */
379
- async verify(params: VerifyTaskInput): Promise<{
380
- passed: boolean;
381
- confidence: number;
382
- reasoning: string;
383
- teeVerified?: boolean;
384
- }> {
385
- return this.req('POST', '/api/v1/verification/verify', {
386
- taskId: params.taskId,
387
- taskCategory: params.taskCategory,
388
- taskRequirements: params.taskRequirements,
389
- evidenceSummary: params.evidenceSummary,
390
- });
391
- }
392
-
393
- /** List available 0G Compute inference providers. */
394
- async getVerificationProviders(): Promise<{ providers: Array<{ address: Address; model: string }> }> {
395
- return this.req('GET', '/api/v1/verification/providers');
396
- }
397
-
398
- /** Check if 0G Compute is configured. */
399
- async getVerificationStatus(): Promise<{ configured: boolean; provider?: string }> {
400
- return this.req('GET', '/api/v1/verification/status');
401
- }
402
-
403
- // ── Reputation ──────────────────────────────────────────────────────────
404
-
405
- /** Get merged reputation (on-chain + off-chain) for an address. */
406
- async getReputation(address: Address): Promise<ReputationInfo> {
407
- return this.req<ReputationInfo>('GET', `/api/v1/reputation/${address}`);
408
- }
409
-
410
- /** Get top workers by decayed score. */
411
- async getLeaderboard(limit = 50): Promise<LeaderboardEntry[]> {
412
- return this.req<LeaderboardEntry[]>('GET', `/api/v1/reputation/leaderboard?limit=${limit}`);
413
- }
414
-
415
- // ── Storage ─────────────────────────────────────────────────────────────
416
-
417
- /** Upload an encrypted blob to 0G Storage. */
418
- async uploadBlob(data: Hex): Promise<StorageUploadResult> {
419
- return this.req<StorageUploadResult>('POST', '/api/v1/storage/upload', { data });
420
- }
421
-
422
- /** Download a blob by root hash. */
423
- async downloadBlob(rootHash: Hex): Promise<{ data: Hex }> {
424
- return this.req<{ data: Hex }>('GET', `/api/v1/storage/${rootHash}`);
425
- }
426
-
427
- // ── Messages ─────────────────────────────────────────────────────────────
428
-
429
- /** Send a message to another user or agent. */
430
- async sendMessage(params: {
431
- taskId: string;
432
- to: string;
433
- content: string;
434
- }): Promise<{ message: Message }> {
435
- return this.req('POST', '/api/v1/messages/send', params);
436
- }
437
-
438
- /** Get inbox messages. */
439
- async getInbox(): Promise<{ messages: Message[] }> {
440
- return this.req('GET', '/api/v1/messages/inbox');
441
- }
442
-
443
- /** Get unread message count. */
444
- async getUnreadCount(): Promise<{ count: number }> {
445
- return this.req('GET', '/api/v1/messages/unread-count');
446
- }
447
-
448
- // ── Marketplace ─────────────────────────────────────────────────────────
449
-
450
- /** Search agents by capability and/or minimum rating. */
451
- async searchAgents(params?: {
452
- capability?: string;
453
- minRating?: number;
454
- }): Promise<AgentSearchResult[]> {
455
- const qs = new URLSearchParams();
456
- if (params?.capability) qs.set('capability', params.capability);
457
- if (params?.minRating != null) qs.set('minRating', String(params.minRating));
458
- const suffix = qs.toString() ? `?${qs.toString()}` : '';
459
- return this.req<AgentSearchResult[]>('GET', `/api/v1/marketplace/agents/search${suffix}`);
460
- }
461
-
462
- /** List public task templates. */
463
- async listTemplates(): Promise<TaskTemplate[]> {
464
- return this.req<TaskTemplate[]>('GET', '/api/v1/marketplace/templates');
465
- }
466
-
467
- /** List own templates. */
468
- async listMyTemplates(): Promise<TaskTemplate[]> {
469
- return this.req<TaskTemplate[]>('GET', '/api/v1/marketplace/templates/mine');
470
- }
471
-
472
- /** Create a task template. */
473
- async createTemplate(params: Partial<TaskTemplate>): Promise<TaskTemplate> {
474
- return this.req<TaskTemplate>('POST', '/api/v1/marketplace/templates', params);
475
- }
476
-
477
- // ── Event watching ──────────────────────────────────────────────────────
478
-
479
- /**
480
- * Poll a task's status at a fixed interval. Calls `callback` on every change.
481
- * Returns an unsubscribe function.
482
- *
483
- * @example
484
- * const stop = bb.watchTask('42', (task) => {
485
- * console.log('Status:', task.status);
486
- * if (task.status === 'verified') stop();
487
- * });
488
- */
489
- watchTask(
490
- taskId: string,
491
- callback: (task: TaskDetail) => void,
492
- intervalMs = 5_000,
493
- ): () => void {
494
- let prev = '';
495
- const id = setInterval(async () => {
496
- try {
497
- const task = await this.getTask(taskId);
498
- const cur = task.a2aState?.status ?? String(task.status);
499
- if (cur !== prev) {
500
- prev = cur;
501
- callback(task);
502
- }
503
- } catch {
504
- // Silently retry on next tick
505
- }
506
- }, intervalMs);
507
- return () => clearInterval(id);
508
- }
509
-
510
- /**
511
- * Poll an agent's status at a fixed interval. Returns an unsubscribe function.
512
- */
513
- watchAgent(
514
- agentId: string,
515
- callback: (agent: DeployedAgentInfo) => void,
516
- intervalMs = 5_000,
517
- ): () => void {
518
- let prev = '';
519
- const id = setInterval(async () => {
520
- try {
521
- const agent = await this.getAgent(agentId);
522
- if (agent.status !== prev) {
523
- prev = agent.status;
524
- callback(agent);
525
- }
526
- } catch {
527
- // Silently retry on next tick
528
- }
529
- }, intervalMs);
530
- return () => clearInterval(id);
531
- }
532
-
533
- // ── Device-flow registration (static) ─────────────────────────────────────
534
-
535
- /**
536
- * Start a device-flow registration session. Generates a magic-link URL
537
- * that the user opens in a browser to sign with their wallet.
538
- *
539
- * After registering, call `BlindMarket.pollSession(token)` to wait for
540
- * the user to confirm and receive the API key.
541
- *
542
- * @example
543
- * ```ts
544
- * const wallet = ethers.Wallet.createRandom();
545
- * const { url, token } = await BlindMarket.register({
546
- * agentName: 'my-agent',
547
- * agentWallet: wallet.address,
548
- * agentPublicKey: wallet.publicKey,
549
- * });
550
- * console.log('Open', url, 'to confirm');
551
- * const apiKey = await BlindMarket.pollSession(token);
552
- * const bb = new BlindMarket({ apiKey });
553
- * ```
554
- */
555
- static async register(params: {
556
- agentName: string;
557
- agentWallet: string;
558
- agentPublicKey: string;
559
- apiBase?: string;
560
- }): Promise<{ token: string; url: string }> {
561
- const base = params.apiBase ?? 'https://api.blindmarket.xyz';
562
- const res = await fetch(`${base}/api/v1/registration/session`, {
563
- method: 'POST',
564
- headers: { 'Content-Type': 'application/json' },
565
- body: JSON.stringify({
566
- agentName: params.agentName,
567
- agentWallet: params.agentWallet,
568
- agentPublicKey: params.agentPublicKey,
569
- }),
570
- });
571
- const json = await res.json() as { success: boolean; data?: { token: string; url: string }; error?: { message: string } };
572
- if (!json.success) throw new ApiError(res.status, json.error?.message ?? 'Registration failed', json);
573
- return json.data!;
574
- }
575
-
576
- /**
577
- * Poll a device-flow registration session until the user confirms or
578
- * the session expires. Returns the API key to use with `new BlindMarket({ apiKey })`.
579
- *
580
- * @param token - The session token from `BlindMarket.register()`.
581
- * @param apiBase - Optional custom API base URL.
582
- * @param intervalMs - Poll interval (default 2s).
583
- * @param timeoutMs - Max wait time (default 5min).
584
- */
585
- static async pollSession(
586
- token: string,
587
- apiBase?: string,
588
- intervalMs = 2_000,
589
- timeoutMs = 300_000,
590
- ): Promise<string> {
591
- const base = apiBase ?? 'https://api.blindmarket.xyz';
592
- const deadline = Date.now() + timeoutMs;
593
- while (Date.now() < deadline) {
594
- const res = await fetch(`${base}/api/v1/registration/session/${token}`);
595
- const json = await res.json() as { success: boolean; data?: { status: string; apiKey?: string }; error?: { message: string } };
596
- if (!json.success) throw new ApiError(res.status, json.error?.message ?? 'Session lookup failed', json);
597
- if (json.data?.status === 'confirmed' && json.data?.apiKey) return json.data.apiKey;
598
- if (json.data?.status === 'pending') {
599
- await new Promise(r => setTimeout(r, intervalMs));
600
- continue;
601
- }
602
- throw new Error(`Unexpected session status: ${json.data?.status}`);
603
- }
604
- throw new Error('Registration session timed out');
605
- }
606
- }
607
-
608
- export { ethers };
609
- export { ApiError };
610
- export {
611
- tools,
612
- createBlindMarketTools, createTaskTools, createAgentManagementTools, createA2ATools,
613
- toLangChainTools, toVercelTools, toOpenAITools, toClaudeTools,
614
- } from './tools/index.js';
615
- export type { Tool, ToolKit, ToolDefinition } from './tools/types.js';
616
- export type { BlindMarketTools } from './tools/index.js';
617
- export * from './executor/index.js';
618
- export * from './types.js';
619
-
620
- // Chain abstraction layer
621
- export { EVMChainAdapter } from './chain/evm/index.js';
622
- export { createChainAdapter } from './chain/createChainAdapter.js';
623
- export type { CreateChainAdapterOptions } from './chain/createChainAdapter.js';
624
- export type { IBlindMarketChain } from './chain/IBlindMarketChain.js';
625
- export type {
626
- Network,
627
- EVMNetwork,
628
- BlockchainType,
629
- CreateTaskParams,
630
- DomainTask,
631
- DomainTaskMeta,
632
- DomainReputation,
633
- DomainTxReceipt,
634
- ChainSigner,
635
- } from './chain/domain-types.js';
636
- export { isEVMNetwork } from './network/resolve.js';