@chaoschain/sdk 0.3.0 → 0.3.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.
@@ -0,0 +1,581 @@
1
+ import axios from 'axios';
2
+
3
+ // src/GatewayClient.ts
4
+
5
+ // src/exceptions.ts
6
+ var ChaosChainSDKError = class _ChaosChainSDKError extends Error {
7
+ details;
8
+ constructor(message, details = {}) {
9
+ super(message);
10
+ this.name = "ChaosChainSDKError";
11
+ this.details = details;
12
+ Object.setPrototypeOf(this, _ChaosChainSDKError.prototype);
13
+ }
14
+ toString() {
15
+ if (Object.keys(this.details).length > 0) {
16
+ return `${this.message} | Details: ${JSON.stringify(this.details)}`;
17
+ }
18
+ return this.message;
19
+ }
20
+ };
21
+ var GatewayError = class _GatewayError extends ChaosChainSDKError {
22
+ statusCode;
23
+ response;
24
+ category;
25
+ retryable;
26
+ constructor(message, details) {
27
+ super(message, details || {});
28
+ this.name = "GatewayError";
29
+ this.statusCode = details?.statusCode;
30
+ this.response = details?.response;
31
+ this.category = details?.category;
32
+ this.retryable = details?.retryable;
33
+ Object.setPrototypeOf(this, _GatewayError.prototype);
34
+ }
35
+ };
36
+ var GatewayConnectionError = class _GatewayConnectionError extends GatewayError {
37
+ constructor(message) {
38
+ super(message);
39
+ this.name = "GatewayConnectionError";
40
+ Object.setPrototypeOf(this, _GatewayConnectionError.prototype);
41
+ }
42
+ };
43
+ var GatewayTimeoutError = class _GatewayTimeoutError extends GatewayError {
44
+ workflowId;
45
+ lastStatus;
46
+ constructor(workflowId, message, lastStatus) {
47
+ super(message);
48
+ this.name = "GatewayTimeoutError";
49
+ this.workflowId = workflowId;
50
+ this.lastStatus = lastStatus;
51
+ Object.setPrototypeOf(this, _GatewayTimeoutError.prototype);
52
+ }
53
+ };
54
+ var WorkflowFailedError = class _WorkflowFailedError extends GatewayError {
55
+ workflowId;
56
+ workflowError;
57
+ constructor(workflowId, error) {
58
+ super(`Workflow ${workflowId} failed at step ${error.step}: ${error.message}`);
59
+ this.name = "WorkflowFailedError";
60
+ this.workflowId = workflowId;
61
+ this.workflowError = error;
62
+ Object.setPrototypeOf(this, _WorkflowFailedError.prototype);
63
+ }
64
+ };
65
+
66
+ // src/GatewayClient.ts
67
+ var GatewayClient = class {
68
+ gatewayUrl;
69
+ timeout;
70
+ maxPollTime;
71
+ pollInterval;
72
+ defaultHeaders;
73
+ auth;
74
+ retryConfig;
75
+ constructor(config) {
76
+ const rawBaseUrl = config.baseUrl ?? config.gatewayUrl ?? "https://gateway.chaoscha.in";
77
+ let parsed;
78
+ try {
79
+ parsed = new URL(rawBaseUrl);
80
+ } catch {
81
+ throw new Error(
82
+ `Invalid gateway baseUrl "${rawBaseUrl}". Provide a valid absolute URL, e.g. https://gateway.chaoscha.in`
83
+ );
84
+ }
85
+ if (!["http:", "https:"].includes(parsed.protocol)) {
86
+ throw new Error(
87
+ `Invalid gateway baseUrl protocol "${parsed.protocol}". Only http/https are supported.`
88
+ );
89
+ }
90
+ this.gatewayUrl = parsed.toString().replace(/\/$/, "");
91
+ this.timeout = this._resolveTimeout(
92
+ config.timeoutMs,
93
+ config.timeoutSeconds,
94
+ config.timeout,
95
+ 3e4
96
+ );
97
+ this.maxPollTime = this._resolveTimeout(
98
+ config.maxPollTimeMs,
99
+ config.maxPollTimeSeconds,
100
+ config.maxPollTime,
101
+ 6e5
102
+ );
103
+ this.pollInterval = this._resolveTimeout(
104
+ config.pollIntervalMs,
105
+ config.pollIntervalSeconds,
106
+ config.pollInterval,
107
+ 2e3
108
+ );
109
+ this.defaultHeaders = config.headers;
110
+ this.auth = config.auth;
111
+ this.retryConfig = config.retry;
112
+ }
113
+ // ===========================================================================
114
+ // Private: HTTP Request
115
+ // ===========================================================================
116
+ // Resolve timeout with explicit ms taking precedence, then seconds, then legacy ms.
117
+ _resolveTimeout(timeoutMs, timeoutSeconds, legacyTimeoutMs, defaultMs) {
118
+ if (typeof timeoutMs === "number") return timeoutMs;
119
+ if (typeof timeoutSeconds === "number") return timeoutSeconds * 1e3;
120
+ if (typeof legacyTimeoutMs === "number") return legacyTimeoutMs;
121
+ return defaultMs ?? 0;
122
+ }
123
+ _resolveAuthMode() {
124
+ if (!this.auth) return void 0;
125
+ if (this.auth.authMode) return this.auth.authMode;
126
+ if (this.auth.apiKey) return "apiKey";
127
+ if (this.auth.signature) return "signature";
128
+ return void 0;
129
+ }
130
+ _buildHeaders() {
131
+ const headers = {
132
+ "Content-Type": "application/json"
133
+ };
134
+ if (this.defaultHeaders) {
135
+ Object.assign(headers, this.defaultHeaders);
136
+ }
137
+ const authMode = this._resolveAuthMode();
138
+ if (authMode === "apiKey" && this.auth?.apiKey) {
139
+ headers["X-API-Key"] = this.auth.apiKey;
140
+ }
141
+ if (authMode === "signature" && this.auth?.signature) {
142
+ const timestamp = this.auth.signature.timestamp ?? Date.now();
143
+ headers["X-Signature"] = this.auth.signature.signature;
144
+ headers["X-Timestamp"] = `${timestamp}`;
145
+ headers["X-Address"] = this.auth.signature.address;
146
+ }
147
+ if (!headers["Content-Type"]) {
148
+ headers["Content-Type"] = "application/json";
149
+ }
150
+ return headers;
151
+ }
152
+ _classifyStatusCode(statusCode) {
153
+ if (statusCode === 401 || statusCode === 403) {
154
+ return { statusCode, category: "auth", retryable: false };
155
+ }
156
+ if (statusCode === 408 || statusCode === 429 || statusCode !== void 0 && statusCode >= 500) {
157
+ return { statusCode, category: "transient", retryable: true };
158
+ }
159
+ if (statusCode !== void 0 && statusCode >= 400) {
160
+ return { statusCode, category: "permanent", retryable: false };
161
+ }
162
+ return { statusCode, category: "unknown", retryable: false };
163
+ }
164
+ _normalizeError(error) {
165
+ if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND") {
166
+ const connectionError = new GatewayConnectionError(
167
+ `Failed to connect to Gateway at ${this.gatewayUrl}`
168
+ );
169
+ connectionError.details.category = "transient";
170
+ connectionError.details.retryable = true;
171
+ connectionError.category = "transient";
172
+ connectionError.retryable = true;
173
+ return connectionError;
174
+ }
175
+ if (error.code === "ETIMEDOUT" || error.code === "ECONNABORTED") {
176
+ const timeoutError = new GatewayTimeoutError(
177
+ "timeout",
178
+ `request to Gateway timed out: ${error.message}`
179
+ );
180
+ timeoutError.details.category = "transient";
181
+ timeoutError.details.retryable = true;
182
+ timeoutError.category = "transient";
183
+ timeoutError.retryable = true;
184
+ return timeoutError;
185
+ }
186
+ if (error.response) {
187
+ const data = error.response.data;
188
+ const message = data?.error || data?.message || "Unknown error from Gateway";
189
+ const classification2 = this._classifyStatusCode(error.response.status);
190
+ return new GatewayError(`Gateway returned error: ${message}`, {
191
+ statusCode: error.response.status,
192
+ response: data,
193
+ category: classification2.category,
194
+ retryable: classification2.retryable
195
+ });
196
+ }
197
+ const classification = this._classifyStatusCode(void 0);
198
+ return new GatewayError(`Gateway request failed: ${error.message}`, {
199
+ category: classification.category,
200
+ retryable: classification.retryable
201
+ });
202
+ }
203
+ _getRetryDelayMs(attempt) {
204
+ const initialDelayMs = this.retryConfig?.initialDelayMs ?? 500;
205
+ const backoffFactor = this.retryConfig?.backoffFactor ?? 2;
206
+ const maxDelayMs = this.retryConfig?.maxDelayMs ?? 8e3;
207
+ const jitterEnabled = this.retryConfig?.jitter ?? true;
208
+ const jitterRatio = this.retryConfig?.jitterRatio ?? 0.2;
209
+ let delay = Math.min(maxDelayMs, initialDelayMs * Math.pow(backoffFactor, attempt));
210
+ if (jitterEnabled) {
211
+ const delta = delay * jitterRatio;
212
+ delay = delay + (Math.random() * 2 - 1) * delta;
213
+ delay = Math.max(0, delay);
214
+ }
215
+ return Math.round(delay);
216
+ }
217
+ async _sleep(durationMs) {
218
+ await new Promise((resolve) => setTimeout(resolve, durationMs));
219
+ }
220
+ /**
221
+ * Make HTTP request to Gateway.
222
+ * Handles errors and transforms them to Gateway exceptions.
223
+ */
224
+ async _request(method, path, data) {
225
+ const url = `${this.gatewayUrl}${path}`;
226
+ const maxRetries = this.retryConfig?.maxRetries ?? 3;
227
+ const retriesEnabled = this.retryConfig?.enabled === true;
228
+ let attempt = 0;
229
+ while (true) {
230
+ try {
231
+ const response = await axios({
232
+ method,
233
+ url,
234
+ data,
235
+ timeout: this.timeout,
236
+ headers: this._buildHeaders()
237
+ });
238
+ return response.data;
239
+ } catch (error) {
240
+ const normalizedError = this._normalizeError(error);
241
+ const category = normalizedError.category;
242
+ const retryable = normalizedError.retryable;
243
+ const shouldRetry = retriesEnabled === true && category === "transient" && retryable === true && attempt < maxRetries;
244
+ if (!shouldRetry) {
245
+ throw normalizedError;
246
+ }
247
+ const delay = this._getRetryDelayMs(attempt);
248
+ attempt += 1;
249
+ await this._sleep(delay);
250
+ }
251
+ }
252
+ }
253
+ /**
254
+ * Parse workflow status from API response.
255
+ */
256
+ _parseWorkflowStatus(data) {
257
+ const progress = {
258
+ arweaveTxId: data.progress?.arweave_tx_id,
259
+ arweaveConfirmed: data.progress?.arweave_confirmed,
260
+ onchainTxHash: data.progress?.onchain_tx_hash,
261
+ onchainConfirmed: data.progress?.onchain_confirmed,
262
+ onchainBlock: data.progress?.onchain_block,
263
+ scoreTxHash: data.progress?.score_tx_hash,
264
+ commitTxHash: data.progress?.commit_tx_hash,
265
+ revealTxHash: data.progress?.reveal_tx_hash
266
+ };
267
+ const error = data.error ? {
268
+ step: data.error.step || "",
269
+ message: data.error.message || "",
270
+ code: data.error.code
271
+ } : void 0;
272
+ return {
273
+ workflowId: data.id,
274
+ workflowType: data.type,
275
+ state: data.state,
276
+ step: data.step,
277
+ createdAt: data.created_at,
278
+ updatedAt: data.updated_at,
279
+ progress,
280
+ error
281
+ };
282
+ }
283
+ // ===========================================================================
284
+ // Health Check
285
+ // ===========================================================================
286
+ async healthCheck() {
287
+ return this._request("GET", "/health");
288
+ }
289
+ async isHealthy() {
290
+ try {
291
+ const result = await this.healthCheck();
292
+ return result.status === "ok";
293
+ } catch (error) {
294
+ return false;
295
+ }
296
+ }
297
+ // ===========================================================================
298
+ // Workflow Submission
299
+ // ===========================================================================
300
+ /**
301
+ * Create a work submission workflow.
302
+ * POST /workflows/work-submission
303
+ *
304
+ * SDK prepares inputs; Gateway handles:
305
+ * - Evidence upload to Arweave
306
+ * - Transaction submission
307
+ * - Confirmation waiting
308
+ *
309
+ * @param studioAddress - Ethereum address of the studio
310
+ * @param epoch - Epoch number
311
+ * @param agentAddress - Ethereum address of the submitting agent
312
+ * @param dataHash - Bytes32 hash of the work (as hex string)
313
+ * @param threadRoot - Bytes32 DKG thread root (as hex string)
314
+ * @param evidenceRoot - Bytes32 evidence Merkle root (as hex string)
315
+ * @param evidenceContent - Raw evidence bytes (will be base64 encoded)
316
+ * @param signerAddress - Ethereum address of the signer (must be registered in Gateway)
317
+ * @returns WorkflowStatus - Initial status of the created workflow
318
+ */
319
+ async submitWork(studioAddress, epoch, agentAddress, dataHash, threadRoot, evidenceRoot, evidenceContent, signerAddress) {
320
+ const evidenceContentBase64 = Buffer.isBuffer(evidenceContent) ? evidenceContent.toString("base64") : Buffer.from(evidenceContent, "utf-8").toString("base64");
321
+ const payload = {
322
+ studio_address: studioAddress,
323
+ epoch,
324
+ agent_address: agentAddress,
325
+ data_hash: dataHash,
326
+ thread_root: threadRoot,
327
+ evidence_root: evidenceRoot,
328
+ evidence_content: evidenceContentBase64,
329
+ signer_address: signerAddress
330
+ };
331
+ const result = await this._request(
332
+ "POST",
333
+ "/workflows/work-submission",
334
+ payload
335
+ );
336
+ return this._parseWorkflowStatus(result);
337
+ }
338
+ /**
339
+ * Create a score submission workflow.
340
+ * POST /workflows/score-submission
341
+ *
342
+ * Supports two modes:
343
+ * - DIRECT (default): Simple direct scoring, requires workerAddress
344
+ * - COMMIT_REVEAL: Commit-reveal pattern, requires salt
345
+ *
346
+ * @param studioAddress - Ethereum address of the studio
347
+ * @param epoch - Epoch number
348
+ * @param validatorAddress - Ethereum address of the validator
349
+ * @param dataHash - Bytes32 hash of the work being scored (as hex string)
350
+ * @param scores - Array of dimension scores (0-10000 basis points)
351
+ * @param signerAddress - Ethereum address of the signer
352
+ * @param options - Additional options (workerAddress, salt, mode)
353
+ */
354
+ async submitScore(studioAddress, epoch, validatorAddress, dataHash, scores, signerAddress, options) {
355
+ const mode = options?.mode ?? "direct" /* DIRECT */;
356
+ if (mode === "direct" /* DIRECT */ && !options?.workerAddress) {
357
+ throw new Error("workerAddress is required for DIRECT score scoring mode");
358
+ }
359
+ if (mode === "commit_reveal" /* COMMIT_REVEAL */ && !options?.salt) {
360
+ throw new Error("salt is required for COMMIT_REVEAL score scoring mode");
361
+ }
362
+ const payload = {
363
+ studio_address: studioAddress,
364
+ epoch,
365
+ validator_address: validatorAddress,
366
+ data_hash: dataHash,
367
+ scores,
368
+ signer_address: signerAddress,
369
+ mode,
370
+ salt: options?.salt ?? "0x" + "0".repeat(64)
371
+ };
372
+ if (options?.workerAddress) {
373
+ payload.worker_address = options.workerAddress;
374
+ }
375
+ const result = await this._request(
376
+ "POST",
377
+ "/workflows/score-submission",
378
+ payload
379
+ );
380
+ return this._parseWorkflowStatus(result);
381
+ }
382
+ /**
383
+ * Create a close epoch workflow.
384
+ * POST /workflows/close-epoch
385
+ *
386
+ * This is economically final — cannot be undone.
387
+ *
388
+ * @param studioAddress - Ethereum address of the studio
389
+ * @param epoch - Epoch number to close
390
+ * @param signerAddress - Ethereum address of the signer
391
+ */
392
+ async closeEpoch(studioAddress, epoch, signerAddress) {
393
+ const payload = {
394
+ studio_address: studioAddress,
395
+ epoch,
396
+ signer_address: signerAddress
397
+ };
398
+ const result = await this._request(
399
+ "POST",
400
+ "/workflows/close-epoch",
401
+ payload
402
+ );
403
+ return this._parseWorkflowStatus(result);
404
+ }
405
+ // ===========================================================================
406
+ // Workflow Status
407
+ // ===========================================================================
408
+ /**
409
+ * Get workflow status by ID.
410
+ * GET /workflows/{id}
411
+ */
412
+ async getWorkflow(workflowId) {
413
+ const result = await this._request("GET", `/workflows/${workflowId}`);
414
+ return this._parseWorkflowStatus(result);
415
+ }
416
+ /**
417
+ * List workflows with optional filters.
418
+ * GET /workflows?studio=&state=&type=
419
+ */
420
+ async listWorkflows(options) {
421
+ const params = [];
422
+ if (options?.studio) params.push(`studio=${options.studio}`);
423
+ if (options?.state) params.push(`state=${options.state}`);
424
+ if (options?.workflowType) params.push(`type=${options.workflowType}`);
425
+ const queryString = params.length > 0 ? `?${params.join("&")}` : "";
426
+ const result = await this._request(
427
+ "GET",
428
+ `/workflows${queryString}`
429
+ );
430
+ return (result.workflows || []).map((w) => this._parseWorkflowStatus(w));
431
+ }
432
+ // ===========================================================================
433
+ // Polling and Waiting
434
+ // ===========================================================================
435
+ /**
436
+ * Poll workflow until it reaches a terminal state.
437
+ *
438
+ * @param workflowId - UUID of the workflow
439
+ * @param options - Polling options
440
+ * @throws WorkflowFailedError - If workflow reaches FAILED state
441
+ * @throws GatewayTimeoutError - If maxWait exceeded
442
+ */
443
+ async waitForCompletion(workflowId, options) {
444
+ const maxWait = options?.maxWait || this.maxPollTime;
445
+ const pollInterval = options?.pollInterval || this.pollInterval;
446
+ const startTime = Date.now();
447
+ while (true) {
448
+ const status = await this.getWorkflow(workflowId);
449
+ if (options?.onProgress) {
450
+ options.onProgress(status);
451
+ }
452
+ if (status.state === "COMPLETED" /* COMPLETED */) {
453
+ return status;
454
+ }
455
+ if (status.state === "FAILED" /* FAILED */) {
456
+ throw new WorkflowFailedError(workflowId, status.error);
457
+ }
458
+ const elapsed = Date.now() - startTime;
459
+ if (elapsed >= maxWait) {
460
+ throw new GatewayTimeoutError(
461
+ workflowId,
462
+ `Workflow ${workflowId} did not complete within ${maxWait} ms.Current state: ${status.state}, step: ${status.step}`,
463
+ status
464
+ );
465
+ }
466
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
467
+ }
468
+ }
469
+ // ===========================================================================
470
+ // Convenience Methods (submit + wait)
471
+ // ===========================================================================
472
+ /**
473
+ * Submit work and wait for completion.
474
+ */
475
+ async submitWorkAndWait(studioAddress, epoch, agentAddress, dataHash, threadRoot, evidenceRoot, evidenceContent, signerAddress, options) {
476
+ const workflow = await this.submitWork(
477
+ studioAddress,
478
+ epoch,
479
+ agentAddress,
480
+ dataHash,
481
+ threadRoot,
482
+ evidenceRoot,
483
+ evidenceContent,
484
+ signerAddress
485
+ );
486
+ return this.waitForCompletion(workflow.workflowId, options);
487
+ }
488
+ /**
489
+ * Submit score and wait for completion.
490
+ */
491
+ async submitScoreAndWait(studioAddress, epoch, validatorAddress, dataHash, scores, signerAddress, options) {
492
+ const workerAddress = options?.workerAddress ?? options?.workAddress;
493
+ const workflow = await this.submitScore(
494
+ studioAddress,
495
+ epoch,
496
+ validatorAddress,
497
+ dataHash,
498
+ scores,
499
+ signerAddress,
500
+ {
501
+ workerAddress,
502
+ salt: options?.salt,
503
+ mode: options?.mode
504
+ }
505
+ );
506
+ return this.waitForCompletion(workflow.workflowId, { onProgress: options?.onProgress });
507
+ }
508
+ /**
509
+ * Close epoch and wait for completion.
510
+ */
511
+ async closeEpochAndWait(studioAddress, epoch, signerAddress, options) {
512
+ const workflow = await this.closeEpoch(studioAddress, epoch, signerAddress);
513
+ return this.waitForCompletion(workflow.workflowId, options);
514
+ }
515
+ // ===========================================================================
516
+ // Read API — Studio Work Discovery
517
+ // ===========================================================================
518
+ /**
519
+ * Fetch pending (unfinalized) work for a studio from the gateway.
520
+ *
521
+ * @param studioAddress - 0x-prefixed studio contract address
522
+ * @param options - Optional limit/offset for pagination
523
+ * @returns Typed pending work response
524
+ */
525
+ async getPendingWork(studioAddress, options) {
526
+ const limit = options?.limit ?? 20;
527
+ const offset = options?.offset ?? 0;
528
+ const url = `${this.gatewayUrl}/v1/studio/${studioAddress}/work?status=pending&limit=${limit}&offset=${offset}`;
529
+ try {
530
+ const response = await axios.get(url, {
531
+ timeout: this.timeout,
532
+ headers: this._buildHeaders()
533
+ });
534
+ return response.data;
535
+ } catch (error) {
536
+ const axiosErr = error;
537
+ if (axiosErr.code === "ECONNREFUSED" || axiosErr.code === "ENOTFOUND" || !axiosErr.response) {
538
+ throw new GatewayConnectionError(
539
+ `ChaosChain gateway unreachable at ${this.gatewayUrl}. Check GATEWAY_URL.`
540
+ );
541
+ }
542
+ if (axiosErr.response) {
543
+ throw new GatewayError(
544
+ `Gateway returned ${axiosErr.response.status}: ${JSON.stringify(axiosErr.response.data)}`
545
+ );
546
+ }
547
+ throw error;
548
+ }
549
+ }
550
+ /**
551
+ * Fetch full evidence graph for a work submission.
552
+ * Endpoint: GET /v1/work/{hash}/evidence
553
+ */
554
+ async getWorkEvidence(workHash) {
555
+ const url = `${this.gatewayUrl}/v1/work/${workHash}/evidence`;
556
+ try {
557
+ const response = await axios.get(url, {
558
+ timeout: this.timeout,
559
+ headers: this._buildHeaders()
560
+ });
561
+ return response.data;
562
+ } catch (error) {
563
+ const axiosErr = error;
564
+ if (axiosErr.code === "ECONNREFUSED" || axiosErr.code === "ENOTFOUND" || !axiosErr.response) {
565
+ throw new GatewayConnectionError(
566
+ `ChaosChain gateway unreachable at ${this.gatewayUrl}. Check GATEWAY_URL.`
567
+ );
568
+ }
569
+ if (axiosErr.response) {
570
+ throw new GatewayError(
571
+ `Gateway returned ${axiosErr.response.status}: ${JSON.stringify(axiosErr.response.data)}`
572
+ );
573
+ }
574
+ throw error;
575
+ }
576
+ }
577
+ };
578
+
579
+ export { GatewayClient, GatewayConnectionError, GatewayError, GatewayTimeoutError, WorkflowFailedError };
580
+ //# sourceMappingURL=index.js.map
581
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/exceptions.ts","../../src/GatewayClient.ts"],"names":["classification"],"mappings":"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","file":"index.js","sourcesContent":["import { WorkflowError as WorkflowErrorType, WorkflowStatus } from './types';\n\n/**\n * Exception classes for the ChaosChain SDK.\n *\n * This module defines all custom exceptions used throughout the SDK\n * to provide clear error handling and debugging information.\n */\n\nexport class ChaosChainSDKError extends Error {\n public details: Record<string, any>;\n\n constructor(message: string, details: Record<string, any> = {}) {\n super(message);\n this.name = 'ChaosChainSDKError';\n this.details = details;\n Object.setPrototypeOf(this, ChaosChainSDKError.prototype);\n }\n\n toString(): string {\n if (Object.keys(this.details).length > 0) {\n return `${this.message} | Details: ${JSON.stringify(this.details)}`;\n }\n return this.message;\n }\n}\n\nexport class AgentRegistrationError extends ChaosChainSDKError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, details);\n this.name = 'AgentRegistrationError';\n Object.setPrototypeOf(this, AgentRegistrationError.prototype);\n }\n}\n\nexport class PaymentError extends ChaosChainSDKError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, details);\n this.name = 'PaymentError';\n Object.setPrototypeOf(this, PaymentError.prototype);\n }\n}\n\nexport class StorageError extends ChaosChainSDKError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, details);\n this.name = 'StorageError';\n Object.setPrototypeOf(this, StorageError.prototype);\n }\n}\n\nexport class IntegrityVerificationError extends ChaosChainSDKError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, details);\n this.name = 'IntegrityVerificationError';\n Object.setPrototypeOf(this, IntegrityVerificationError.prototype);\n }\n}\n\nexport class NetworkError extends ChaosChainSDKError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, details);\n this.name = 'NetworkError';\n Object.setPrototypeOf(this, NetworkError.prototype);\n }\n}\n\nexport class ContractError extends ChaosChainSDKError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, details);\n this.name = 'ContractError';\n Object.setPrototypeOf(this, ContractError.prototype);\n }\n}\n\nexport class ValidationError extends ChaosChainSDKError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, details);\n this.name = 'ValidationError';\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\nexport class ConfigurationError extends ChaosChainSDKError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, details);\n this.name = 'ConfigurationError';\n Object.setPrototypeOf(this, ConfigurationError.prototype);\n }\n}\n\nexport class AuthenticationError extends ChaosChainSDKError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, details);\n this.name = 'AuthenticationError';\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n\n/**\n * Options passed when constructing a GatewayError (statusCode, response, category, retryable).\n */\nexport interface GatewayErrorDetails {\n statusCode?: number;\n response?: Record<string, any>;\n category?: 'transient' | 'permanent' | 'auth' | 'unknown';\n retryable?: boolean;\n}\n\n/**\n * Base error from Gateway API.\n */\nexport class GatewayError extends ChaosChainSDKError {\n public readonly statusCode?: number;\n public readonly response?: Record<string, any>;\n public readonly category?: 'transient' | 'permanent' | 'auth' | 'unknown';\n public readonly retryable?: boolean;\n\n constructor(message: string, details?: GatewayErrorDetails) {\n super(message, details || {});\n this.name = 'GatewayError';\n this.statusCode = details?.statusCode;\n this.response = details?.response;\n this.category = details?.category;\n this.retryable = details?.retryable;\n Object.setPrototypeOf(this, GatewayError.prototype);\n }\n}\n\n/**\n * Failed to connect to Gateway.\n */\nexport class GatewayConnectionError extends GatewayError {\n constructor(message: string) {\n super(message);\n this.name = 'GatewayConnectionError';\n Object.setPrototypeOf(this, GatewayConnectionError.prototype);\n }\n}\n\n/**\n * Gateway request or polling timed out.\n */\nexport class GatewayTimeoutError extends GatewayError {\n public readonly workflowId: string;\n public readonly lastStatus?: WorkflowStatus;\n\n constructor(workflowId: string, message: string, lastStatus?: WorkflowStatus) {\n super(message);\n this.name = 'GatewayTimeoutError';\n this.workflowId = workflowId;\n this.lastStatus = lastStatus;\n Object.setPrototypeOf(this, GatewayTimeoutError.prototype);\n }\n}\n\n/**\n * Workflow reached FAILED state.\n */\nexport class WorkflowFailedError extends GatewayError {\n public readonly workflowId: string;\n public readonly workflowError: WorkflowErrorType;\n\n constructor(workflowId: string, error: WorkflowErrorType) {\n super(`Workflow ${workflowId} failed at step ${error.step}: ${error.message}`);\n this.name = 'WorkflowFailedError';\n this.workflowId = workflowId;\n this.workflowError = error;\n Object.setPrototypeOf(this, WorkflowFailedError.prototype);\n }\n}\n","import axios, { AxiosError } from 'axios';\nimport {\n WorkflowType,\n WorkflowState,\n WorkflowStatus,\n WorkflowProgress,\n WorkflowError as WorkflowErrorType,\n GatewayClientConfig,\n GatewayHealthResponse,\n GatewayWorkflowResponse,\n GatewayListWorkflowsResponse,\n GatewayWorkSubmissionRequest,\n GatewayScoreSubmissionRequest,\n GatewayCloseEpochRequest,\n GatewayAuthConfig,\n GatewayErrorCategory,\n GatewayErrorInfo,\n GatewayRetryConfig,\n ScoreSubmissionMode,\n PendingWorkResponse,\n WorkEvidenceResponse,\n} from './types';\nimport {\n GatewayError,\n GatewayConnectionError,\n GatewayTimeoutError,\n WorkflowFailedError,\n} from './exceptions';\n\nexport class GatewayClient {\n private gatewayUrl: string;\n private timeout: number;\n private maxPollTime: number;\n private pollInterval: number;\n private defaultHeaders?: Record<string, string>;\n private auth?: GatewayAuthConfig;\n private retryConfig?: GatewayRetryConfig;\n\n constructor(config: GatewayClientConfig) {\n const rawBaseUrl = config.baseUrl ?? config.gatewayUrl ?? 'https://gateway.chaoscha.in';\n let parsed: URL;\n try {\n parsed = new URL(rawBaseUrl);\n } catch {\n throw new Error(\n `Invalid gateway baseUrl \"${rawBaseUrl}\". Provide a valid absolute URL, e.g. https://gateway.chaoscha.in`\n );\n }\n if (!['http:', 'https:'].includes(parsed.protocol)) {\n throw new Error(\n `Invalid gateway baseUrl protocol \"${parsed.protocol}\". Only http/https are supported.`\n );\n }\n this.gatewayUrl = parsed.toString().replace(/\\/$/, ''); // Remove trailing slash\n this.timeout = this._resolveTimeout(\n config.timeoutMs,\n config.timeoutSeconds,\n config.timeout,\n 30000\n ); // Default timeout 30s\n this.maxPollTime = this._resolveTimeout(\n config.maxPollTimeMs,\n config.maxPollTimeSeconds,\n config.maxPollTime,\n 600000\n ); // Default max poll time 10min\n this.pollInterval = this._resolveTimeout(\n config.pollIntervalMs,\n config.pollIntervalSeconds,\n config.pollInterval,\n 2000\n ); // Default poll interval 2s\n this.defaultHeaders = config.headers;\n this.auth = config.auth;\n this.retryConfig = config.retry;\n }\n\n // ===========================================================================\n // Private: HTTP Request\n // ===========================================================================\n\n // Resolve timeout with explicit ms taking precedence, then seconds, then legacy ms.\n private _resolveTimeout(\n timeoutMs?: number,\n timeoutSeconds?: number,\n legacyTimeoutMs?: number,\n defaultMs?: number\n ): number {\n if (typeof timeoutMs === 'number') return timeoutMs;\n if (typeof timeoutSeconds === 'number') return timeoutSeconds * 1000;\n if (typeof legacyTimeoutMs === 'number') return legacyTimeoutMs;\n return defaultMs ?? 0;\n }\n\n private _resolveAuthMode(): GatewayAuthConfig['authMode'] | undefined {\n if (!this.auth) return undefined;\n if (this.auth.authMode) return this.auth.authMode;\n if (this.auth.apiKey) return 'apiKey';\n if (this.auth.signature) return 'signature';\n return undefined;\n }\n\n private _buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (this.defaultHeaders) {\n Object.assign(headers, this.defaultHeaders);\n }\n\n const authMode = this._resolveAuthMode();\n if (authMode === 'apiKey' && this.auth?.apiKey) {\n headers['X-API-Key'] = this.auth.apiKey;\n }\n\n // Signature auth expects caller-provided signature and optional timestamp.\n if (authMode === 'signature' && this.auth?.signature) {\n const timestamp = this.auth.signature.timestamp ?? Date.now();\n headers['X-Signature'] = this.auth.signature.signature;\n headers['X-Timestamp'] = `${timestamp}`;\n headers['X-Address'] = this.auth.signature.address;\n }\n\n if (!headers['Content-Type']) {\n headers['Content-Type'] = 'application/json';\n }\n\n return headers;\n }\n\n private _classifyStatusCode(statusCode?: number): GatewayErrorInfo {\n if (statusCode === 401 || statusCode === 403) {\n return { statusCode, category: 'auth', retryable: false };\n }\n\n if (statusCode === 408 || statusCode === 429 || (statusCode !== undefined && statusCode >= 500)) {\n return { statusCode, category: 'transient', retryable: true };\n }\n\n if (statusCode !== undefined && statusCode >= 400) {\n return { statusCode, category: 'permanent', retryable: false };\n }\n\n return { statusCode, category: 'unknown', retryable: false };\n }\n\n private _normalizeError(error: AxiosError): GatewayError {\n if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND') {\n const connectionError = new GatewayConnectionError(\n `Failed to connect to Gateway at ${this.gatewayUrl}`\n );\n connectionError.details.category = 'transient';\n connectionError.details.retryable = true;\n (connectionError as any).category = 'transient' as GatewayErrorCategory;\n (connectionError as any).retryable = true;\n return connectionError;\n }\n\n if (error.code === 'ETIMEDOUT' || error.code === 'ECONNABORTED') {\n const timeoutError = new GatewayTimeoutError(\n 'timeout',\n `request to Gateway timed out: ${error.message}`\n );\n timeoutError.details.category = 'transient';\n timeoutError.details.retryable = true;\n (timeoutError as any).category = 'transient' as GatewayErrorCategory;\n (timeoutError as any).retryable = true;\n return timeoutError;\n }\n\n if (error.response) {\n const data = error.response.data as Record<string, any>;\n const message = data?.error || data?.message || 'Unknown error from Gateway';\n const classification = this._classifyStatusCode(error.response.status);\n return new GatewayError(`Gateway returned error: ${message}`, {\n statusCode: error.response.status,\n response: data,\n category: classification.category,\n retryable: classification.retryable,\n });\n }\n\n const classification = this._classifyStatusCode(undefined);\n return new GatewayError(`Gateway request failed: ${error.message}`, {\n category: classification.category,\n retryable: classification.retryable,\n });\n }\n\n private _getRetryDelayMs(attempt: number): number {\n const initialDelayMs = this.retryConfig?.initialDelayMs ?? 500;\n const backoffFactor = this.retryConfig?.backoffFactor ?? 2;\n const maxDelayMs = this.retryConfig?.maxDelayMs ?? 8000;\n const jitterEnabled = this.retryConfig?.jitter ?? true;\n const jitterRatio = this.retryConfig?.jitterRatio ?? 0.2;\n\n let delay = Math.min(maxDelayMs, initialDelayMs * Math.pow(backoffFactor, attempt));\n if (jitterEnabled) {\n const delta = delay * jitterRatio;\n delay = delay + (Math.random() * 2 - 1) * delta;\n delay = Math.max(0, delay);\n }\n return Math.round(delay);\n }\n\n private async _sleep(durationMs: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, durationMs));\n }\n\n /**\n * Make HTTP request to Gateway.\n * Handles errors and transforms them to Gateway exceptions.\n */\n private async _request<T>(\n method: 'GET' | 'POST',\n path: string,\n data?: Record<string, any>\n ): Promise<T> {\n const url = `${this.gatewayUrl}${path}`;\n // Retries are disabled by default; only enabled retries for transient errors.\n const maxRetries = this.retryConfig?.maxRetries ?? 3;\n const retriesEnabled = this.retryConfig?.enabled === true;\n let attempt = 0;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n const response = await axios({\n method,\n url,\n data,\n timeout: this.timeout,\n headers: this._buildHeaders(),\n });\n\n return response.data as T;\n } catch (error) {\n const normalizedError = this._normalizeError(error as AxiosError);\n const category = (normalizedError as any).category as GatewayErrorCategory | undefined;\n const retryable = (normalizedError as any).retryable as boolean | undefined;\n const shouldRetry =\n retriesEnabled === true &&\n category === 'transient' &&\n retryable === true &&\n attempt < maxRetries;\n\n if (!shouldRetry) {\n throw normalizedError;\n }\n\n const delay = this._getRetryDelayMs(attempt);\n attempt += 1;\n await this._sleep(delay);\n }\n }\n }\n\n /**\n * Parse workflow status from API response.\n */\n private _parseWorkflowStatus(data: GatewayWorkflowResponse): WorkflowStatus {\n const progress: WorkflowProgress = {\n arweaveTxId: data.progress?.arweave_tx_id,\n arweaveConfirmed: data.progress?.arweave_confirmed,\n onchainTxHash: data.progress?.onchain_tx_hash,\n onchainConfirmed: data.progress?.onchain_confirmed,\n onchainBlock: data.progress?.onchain_block,\n scoreTxHash: data.progress?.score_tx_hash,\n commitTxHash: data.progress?.commit_tx_hash,\n revealTxHash: data.progress?.reveal_tx_hash,\n };\n\n const error: WorkflowErrorType | undefined = data.error\n ? {\n step: data.error.step || '',\n message: data.error.message || '',\n code: data.error.code,\n }\n : undefined;\n\n return {\n workflowId: data.id,\n workflowType: data.type as WorkflowType,\n state: data.state as WorkflowState,\n step: data.step,\n createdAt: data.created_at,\n updatedAt: data.updated_at,\n progress,\n error,\n };\n }\n\n // ===========================================================================\n // Health Check\n // ===========================================================================\n\n async healthCheck(): Promise<GatewayHealthResponse> {\n return this._request<GatewayHealthResponse>('GET', '/health');\n }\n\n async isHealthy(): Promise<boolean> {\n try {\n const result = await this.healthCheck();\n return result.status === 'ok';\n } catch (error) {\n return false;\n }\n }\n\n // ===========================================================================\n // Workflow Submission\n // ===========================================================================\n\n /**\n * Create a work submission workflow.\n * POST /workflows/work-submission\n *\n * SDK prepares inputs; Gateway handles:\n * - Evidence upload to Arweave\n * - Transaction submission\n * - Confirmation waiting\n *\n * @param studioAddress - Ethereum address of the studio\n * @param epoch - Epoch number\n * @param agentAddress - Ethereum address of the submitting agent\n * @param dataHash - Bytes32 hash of the work (as hex string)\n * @param threadRoot - Bytes32 DKG thread root (as hex string)\n * @param evidenceRoot - Bytes32 evidence Merkle root (as hex string)\n * @param evidenceContent - Raw evidence bytes (will be base64 encoded)\n * @param signerAddress - Ethereum address of the signer (must be registered in Gateway)\n * @returns WorkflowStatus - Initial status of the created workflow\n */\n async submitWork(\n studioAddress: string,\n epoch: number,\n agentAddress: string,\n dataHash: string,\n threadRoot: string,\n evidenceRoot: string,\n evidenceContent: Buffer | string,\n signerAddress: string\n ): Promise<WorkflowStatus> {\n const evidenceContentBase64 = Buffer.isBuffer(evidenceContent)\n ? evidenceContent.toString('base64')\n : Buffer.from(evidenceContent, 'utf-8').toString('base64');\n\n const payload: GatewayWorkSubmissionRequest = {\n studio_address: studioAddress,\n epoch,\n agent_address: agentAddress,\n data_hash: dataHash,\n thread_root: threadRoot,\n evidence_root: evidenceRoot,\n evidence_content: evidenceContentBase64,\n signer_address: signerAddress,\n };\n\n const result = await this._request<GatewayWorkflowResponse>(\n 'POST',\n '/workflows/work-submission',\n payload\n );\n return this._parseWorkflowStatus(result);\n }\n\n /**\n * Create a score submission workflow.\n * POST /workflows/score-submission\n *\n * Supports two modes:\n * - DIRECT (default): Simple direct scoring, requires workerAddress\n * - COMMIT_REVEAL: Commit-reveal pattern, requires salt\n *\n * @param studioAddress - Ethereum address of the studio\n * @param epoch - Epoch number\n * @param validatorAddress - Ethereum address of the validator\n * @param dataHash - Bytes32 hash of the work being scored (as hex string)\n * @param scores - Array of dimension scores (0-10000 basis points)\n * @param signerAddress - Ethereum address of the signer\n * @param options - Additional options (workerAddress, salt, mode)\n */\n async submitScore(\n studioAddress: string,\n epoch: number,\n validatorAddress: string,\n dataHash: string,\n scores: number[],\n signerAddress: string,\n options?: {\n workerAddress?: string;\n salt?: string;\n mode?: ScoreSubmissionMode;\n }\n ): Promise<WorkflowStatus> {\n const mode = options?.mode ?? ScoreSubmissionMode.DIRECT;\n\n if (mode === ScoreSubmissionMode.DIRECT && !options?.workerAddress) {\n throw new Error('workerAddress is required for DIRECT score scoring mode');\n }\n\n if (mode === ScoreSubmissionMode.COMMIT_REVEAL && !options?.salt) {\n throw new Error('salt is required for COMMIT_REVEAL score scoring mode');\n }\n\n const payload: GatewayScoreSubmissionRequest = {\n studio_address: studioAddress,\n epoch: epoch,\n validator_address: validatorAddress,\n data_hash: dataHash,\n scores,\n signer_address: signerAddress,\n mode: mode,\n salt: options?.salt ?? '0x' + '0'.repeat(64),\n };\n\n if (options?.workerAddress) {\n payload.worker_address = options.workerAddress;\n }\n\n // Gateway requires salt field (event if unused in direct mode)\n const result = await this._request<GatewayWorkflowResponse>(\n 'POST',\n '/workflows/score-submission',\n payload\n );\n return this._parseWorkflowStatus(result);\n }\n\n /**\n * Create a close epoch workflow.\n * POST /workflows/close-epoch\n *\n * This is economically final — cannot be undone.\n *\n * @param studioAddress - Ethereum address of the studio\n * @param epoch - Epoch number to close\n * @param signerAddress - Ethereum address of the signer\n */\n async closeEpoch(\n studioAddress: string,\n epoch: number,\n signerAddress: string\n ): Promise<WorkflowStatus> {\n const payload: GatewayCloseEpochRequest = {\n studio_address: studioAddress,\n epoch,\n signer_address: signerAddress,\n };\n\n const result = await this._request<GatewayWorkflowResponse>(\n 'POST',\n '/workflows/close-epoch',\n payload\n );\n return this._parseWorkflowStatus(result);\n }\n\n // ===========================================================================\n // Workflow Status\n // ===========================================================================\n\n /**\n * Get workflow status by ID.\n * GET /workflows/{id}\n */\n async getWorkflow(workflowId: string): Promise<WorkflowStatus> {\n const result = await this._request<GatewayWorkflowResponse>('GET', `/workflows/${workflowId}`);\n return this._parseWorkflowStatus(result);\n }\n\n /**\n * List workflows with optional filters.\n * GET /workflows?studio=&state=&type=\n */\n async listWorkflows(options?: {\n studio?: string;\n state?: string;\n workflowType?: string;\n }): Promise<WorkflowStatus[]> {\n const params: string[] = [];\n if (options?.studio) params.push(`studio=${options.studio}`);\n if (options?.state) params.push(`state=${options.state}`);\n if (options?.workflowType) params.push(`type=${options.workflowType}`);\n\n const queryString = params.length > 0 ? `?${params.join('&')}` : '';\n const result = await this._request<GatewayListWorkflowsResponse>(\n 'GET',\n `/workflows${queryString}`\n );\n return (result.workflows || []).map((w) => this._parseWorkflowStatus(w));\n }\n\n // ===========================================================================\n // Polling and Waiting\n // ===========================================================================\n\n /**\n * Poll workflow until it reaches a terminal state.\n *\n * @param workflowId - UUID of the workflow\n * @param options - Polling options\n * @throws WorkflowFailedError - If workflow reaches FAILED state\n * @throws GatewayTimeoutError - If maxWait exceeded\n */\n async waitForCompletion(\n workflowId: string,\n options?: {\n maxWait?: number;\n pollInterval?: number;\n onProgress?: (status: WorkflowStatus) => void;\n }\n ): Promise<WorkflowStatus> {\n const maxWait = options?.maxWait || this.maxPollTime;\n const pollInterval = options?.pollInterval || this.pollInterval;\n const startTime = Date.now();\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const status = await this.getWorkflow(workflowId);\n\n // Invoke progress callback if provided\n if (options?.onProgress) {\n options.onProgress(status);\n }\n\n if (status.state === WorkflowState.COMPLETED) {\n return status;\n }\n\n if (status.state === WorkflowState.FAILED) {\n throw new WorkflowFailedError(workflowId, status.error!);\n }\n\n const elapsed = Date.now() - startTime;\n if (elapsed >= maxWait) {\n throw new GatewayTimeoutError(\n workflowId,\n `Workflow ${workflowId} did not complete within ${maxWait} ms.` +\n `Current state: ${status.state}, step: ${status.step}`,\n status\n );\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n }\n\n // ===========================================================================\n // Convenience Methods (submit + wait)\n // ===========================================================================\n\n /**\n * Submit work and wait for completion.\n */\n async submitWorkAndWait(\n studioAddress: string,\n epoch: number,\n agentAddress: string,\n dataHash: string,\n threadRoot: string,\n evidenceRoot: string,\n evidenceContent: Buffer | string,\n signerAddress: string,\n options?: {\n onProgress?: (status: WorkflowStatus) => void;\n }\n ): Promise<WorkflowStatus> {\n const workflow = await this.submitWork(\n studioAddress,\n epoch,\n agentAddress,\n dataHash,\n threadRoot,\n evidenceRoot,\n evidenceContent,\n signerAddress\n );\n\n return this.waitForCompletion(workflow.workflowId, options);\n }\n\n /**\n * Submit score and wait for completion.\n */\n async submitScoreAndWait(\n studioAddress: string,\n epoch: number,\n validatorAddress: string,\n dataHash: string,\n scores: number[],\n signerAddress: string,\n options?: {\n workerAddress?: string;\n workAddress?: string;\n salt?: string;\n mode?: ScoreSubmissionMode;\n onProgress?: (status: WorkflowStatus) => void;\n }\n ): Promise<WorkflowStatus> {\n const workerAddress = options?.workerAddress ?? options?.workAddress;\n const workflow = await this.submitScore(\n studioAddress,\n epoch,\n validatorAddress,\n dataHash,\n scores,\n signerAddress,\n {\n workerAddress,\n salt: options?.salt,\n mode: options?.mode,\n }\n );\n\n return this.waitForCompletion(workflow.workflowId, { onProgress: options?.onProgress });\n }\n\n /**\n * Close epoch and wait for completion.\n */\n async closeEpochAndWait(\n studioAddress: string,\n epoch: number,\n signerAddress: string,\n options?: {\n onProgress?: (status: WorkflowStatus) => void;\n }\n ): Promise<WorkflowStatus> {\n const workflow = await this.closeEpoch(studioAddress, epoch, signerAddress);\n return this.waitForCompletion(workflow.workflowId, options);\n }\n\n // ===========================================================================\n // Read API — Studio Work Discovery\n // ===========================================================================\n\n /**\n * Fetch pending (unfinalized) work for a studio from the gateway.\n *\n * @param studioAddress - 0x-prefixed studio contract address\n * @param options - Optional limit/offset for pagination\n * @returns Typed pending work response\n */\n async getPendingWork(\n studioAddress: string,\n options?: { limit?: number; offset?: number }\n ): Promise<PendingWorkResponse> {\n const limit = options?.limit ?? 20;\n const offset = options?.offset ?? 0;\n const url = `${this.gatewayUrl}/v1/studio/${studioAddress}/work?status=pending&limit=${limit}&offset=${offset}`;\n\n try {\n const response = await axios.get(url, {\n timeout: this.timeout,\n headers: this._buildHeaders(),\n });\n return response.data as PendingWorkResponse;\n } catch (error: unknown) {\n const axiosErr = error as AxiosError;\n if (axiosErr.code === 'ECONNREFUSED' || axiosErr.code === 'ENOTFOUND' || !axiosErr.response) {\n throw new GatewayConnectionError(\n `ChaosChain gateway unreachable at ${this.gatewayUrl}. Check GATEWAY_URL.`,\n );\n }\n if (axiosErr.response) {\n throw new GatewayError(\n `Gateway returned ${axiosErr.response.status}: ${JSON.stringify(axiosErr.response.data)}`,\n );\n }\n throw error;\n }\n }\n\n /**\n * Fetch full evidence graph for a work submission.\n * Endpoint: GET /v1/work/{hash}/evidence\n */\n async getWorkEvidence(workHash: string): Promise<WorkEvidenceResponse> {\n const url = `${this.gatewayUrl}/v1/work/${workHash}/evidence`;\n\n try {\n const response = await axios.get(url, {\n timeout: this.timeout,\n headers: this._buildHeaders(),\n });\n return response.data as WorkEvidenceResponse;\n } catch (error: unknown) {\n const axiosErr = error as AxiosError;\n if (axiosErr.code === 'ECONNREFUSED' || axiosErr.code === 'ENOTFOUND' || !axiosErr.response) {\n throw new GatewayConnectionError(\n `ChaosChain gateway unreachable at ${this.gatewayUrl}. Check GATEWAY_URL.`\n );\n }\n if (axiosErr.response) {\n throw new GatewayError(\n `Gateway returned ${axiosErr.response.status}: ${JSON.stringify(axiosErr.response.data)}`\n );\n }\n throw error;\n }\n }\n}\n"]}