@agirails/sdk 2.0.4 → 2.2.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.
- package/README.md +536 -87
- package/dist/adapters/BasicAdapter.d.ts.map +1 -1
- package/dist/adapters/BasicAdapter.js +8 -0
- package/dist/adapters/BasicAdapter.js.map +1 -1
- package/dist/adapters/StandardAdapter.d.ts +10 -5
- package/dist/adapters/StandardAdapter.d.ts.map +1 -1
- package/dist/adapters/StandardAdapter.js +19 -6
- package/dist/adapters/StandardAdapter.js.map +1 -1
- package/dist/config/networks.d.ts +9 -0
- package/dist/config/networks.d.ts.map +1 -1
- package/dist/config/networks.js +25 -10
- package/dist/config/networks.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -1
- package/dist/index.js.map +1 -1
- package/dist/level0/provide.d.ts.map +1 -1
- package/dist/level0/provide.js +2 -1
- package/dist/level0/provide.js.map +1 -1
- package/dist/level1/Agent.d.ts.map +1 -1
- package/dist/level1/Agent.js +11 -3
- package/dist/level1/Agent.js.map +1 -1
- package/dist/protocol/ACTPKernel.d.ts.map +1 -1
- package/dist/protocol/ACTPKernel.js +7 -5
- package/dist/protocol/ACTPKernel.js.map +1 -1
- package/dist/protocol/DIDResolver.js +1 -1
- package/dist/protocol/DIDResolver.js.map +1 -1
- package/dist/protocol/EASHelper.d.ts.map +1 -1
- package/dist/protocol/EASHelper.js +2 -3
- package/dist/protocol/EASHelper.js.map +1 -1
- package/dist/protocol/MessageSigner.d.ts.map +1 -1
- package/dist/protocol/MessageSigner.js +8 -8
- package/dist/protocol/MessageSigner.js.map +1 -1
- package/dist/runtime/BlockchainRuntime.d.ts +7 -0
- package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
- package/dist/runtime/BlockchainRuntime.js +38 -22
- package/dist/runtime/BlockchainRuntime.js.map +1 -1
- package/dist/runtime/IACTPRuntime.d.ts +15 -0
- package/dist/runtime/IACTPRuntime.d.ts.map +1 -1
- package/dist/runtime/MockRuntime.d.ts +7 -0
- package/dist/runtime/MockRuntime.d.ts.map +1 -1
- package/dist/runtime/MockRuntime.js +15 -4
- package/dist/runtime/MockRuntime.js.map +1 -1
- package/dist/runtime/types/MockState.d.ts +5 -2
- package/dist/runtime/types/MockState.d.ts.map +1 -1
- package/dist/runtime/types/MockState.js.map +1 -1
- package/dist/storage/ArchiveBundleBuilder.d.ts +150 -0
- package/dist/storage/ArchiveBundleBuilder.d.ts.map +1 -0
- package/dist/storage/ArchiveBundleBuilder.js +468 -0
- package/dist/storage/ArchiveBundleBuilder.js.map +1 -0
- package/dist/storage/ArweaveClient.d.ts +271 -0
- package/dist/storage/ArweaveClient.d.ts.map +1 -0
- package/dist/storage/ArweaveClient.js +761 -0
- package/dist/storage/ArweaveClient.js.map +1 -0
- package/dist/storage/FilebaseClient.d.ts +193 -0
- package/dist/storage/FilebaseClient.d.ts.map +1 -0
- package/dist/storage/FilebaseClient.js +643 -0
- package/dist/storage/FilebaseClient.js.map +1 -0
- package/dist/storage/index.d.ts +47 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +64 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/types.d.ts +291 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +18 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/types/state.d.ts +5 -4
- package/dist/types/state.d.ts.map +1 -1
- package/dist/types/state.js +10 -9
- package/dist/types/state.js.map +1 -1
- package/dist/utils/IPFSClient.d.ts.map +1 -1
- package/dist/utils/IPFSClient.js +5 -2
- package/dist/utils/IPFSClient.js.map +1 -1
- package/dist/utils/NonceManager.d.ts.map +1 -1
- package/dist/utils/NonceManager.js +3 -2
- package/dist/utils/NonceManager.js.map +1 -1
- package/dist/utils/UsedAttestationTracker.d.ts.map +1 -1
- package/dist/utils/UsedAttestationTracker.js +3 -3
- package/dist/utils/UsedAttestationTracker.js.map +1 -1
- package/dist/utils/circuitBreaker.d.ts +136 -0
- package/dist/utils/circuitBreaker.d.ts.map +1 -0
- package/dist/utils/circuitBreaker.js +253 -0
- package/dist/utils/circuitBreaker.js.map +1 -0
- package/dist/utils/retry.d.ts +120 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +260 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/validation.d.ts +100 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +248 -1
- package/dist/utils/validation.js.map +1 -1
- package/package.json +14 -2
- package/src/adapters/BasicAdapter.ts +11 -0
- package/src/adapters/StandardAdapter.ts +26 -6
- package/src/config/networks.ts +34 -10
- package/src/index.ts +54 -0
- package/src/level0/provide.ts +2 -1
- package/src/level1/Agent.ts +13 -3
- package/src/protocol/ACTPKernel.ts +7 -5
- package/src/protocol/DIDResolver.ts +1 -1
- package/src/protocol/EASHelper.ts +2 -5
- package/src/protocol/MessageSigner.ts +8 -14
- package/src/runtime/BlockchainRuntime.ts +39 -45
- package/src/runtime/IACTPRuntime.ts +16 -0
- package/src/runtime/MockRuntime.ts +16 -4
- package/src/runtime/types/MockState.ts +5 -2
- package/src/storage/ArchiveBundleBuilder.ts +563 -0
- package/src/storage/ArweaveClient.ts +945 -0
- package/src/storage/FilebaseClient.ts +790 -0
- package/src/storage/index.ts +96 -0
- package/src/storage/types.ts +348 -0
- package/src/types/state.ts +10 -9
- package/src/utils/IPFSClient.ts +5 -4
- package/src/utils/NonceManager.ts +3 -2
- package/src/utils/UsedAttestationTracker.ts +3 -5
- package/src/utils/circuitBreaker.ts +324 -0
- package/src/utils/fsSafe.ts +5 -0
- package/src/utils/retry.ts +365 -0
- package/src/utils/validation.ts +295 -1
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* FilebaseClient - IPFS Storage via Filebase S3 API (AIP-7 §4.2)
|
|
4
|
+
*
|
|
5
|
+
* Provides S3-compatible IPFS pinning via Filebase.
|
|
6
|
+
* Used for hot storage of request metadata and delivery proofs.
|
|
7
|
+
*
|
|
8
|
+
* Security Features (Post-Audit):
|
|
9
|
+
* - Gateway URL whitelist (SSRF protection)
|
|
10
|
+
* - Download size limits (DoS protection)
|
|
11
|
+
* - Credential sanitization in errors
|
|
12
|
+
* - Retry with exponential backoff
|
|
13
|
+
* - Circuit breaker for gateway health tracking
|
|
14
|
+
*
|
|
15
|
+
* @module storage/FilebaseClient
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.FilebaseClient = void 0;
|
|
19
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
20
|
+
const errors_1 = require("../errors");
|
|
21
|
+
const validation_1 = require("../utils/validation");
|
|
22
|
+
const retry_1 = require("../utils/retry");
|
|
23
|
+
const circuitBreaker_1 = require("../utils/circuitBreaker");
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Constants
|
|
26
|
+
// ============================================================================
|
|
27
|
+
const DEFAULT_ENDPOINT = 'https://s3.filebase.com';
|
|
28
|
+
const DEFAULT_GATEWAY = 'https://ipfs.filebase.io/ipfs/';
|
|
29
|
+
const DEFAULT_BUCKET = 'agirails-storage';
|
|
30
|
+
const DEFAULT_TIMEOUT = 30000; // 30 seconds
|
|
31
|
+
const DEFAULT_MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB
|
|
32
|
+
const DEFAULT_MAX_DOWNLOAD_SIZE = 50 * 1024 * 1024; // 50MB (P1-1: DoS protection)
|
|
33
|
+
const DEFAULT_REGION = 'us-east-1';
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// FilebaseClient Class
|
|
36
|
+
// ============================================================================
|
|
37
|
+
/**
|
|
38
|
+
* FilebaseClient - IPFS storage via Filebase S3 API
|
|
39
|
+
*
|
|
40
|
+
* Provides hot storage for:
|
|
41
|
+
* - AIP-1 request metadata
|
|
42
|
+
* - AIP-4 delivery proofs
|
|
43
|
+
* - Service descriptors
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const client = new FilebaseClient({
|
|
48
|
+
* accessKey: process.env.FILEBASE_ACCESS_KEY!,
|
|
49
|
+
* secretKey: process.env.FILEBASE_SECRET_KEY!,
|
|
50
|
+
* bucket: 'my-agirails-bucket'
|
|
51
|
+
* });
|
|
52
|
+
*
|
|
53
|
+
* // Upload JSON
|
|
54
|
+
* const result = await client.uploadJSON({ message: 'Hello IPFS!' });
|
|
55
|
+
* console.log('CID:', result.cid);
|
|
56
|
+
*
|
|
57
|
+
* // Download JSON
|
|
58
|
+
* const data = await client.downloadJSON(result.cid);
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
class FilebaseClient {
|
|
62
|
+
/**
|
|
63
|
+
* Create a new FilebaseClient
|
|
64
|
+
*
|
|
65
|
+
* @param config - Filebase configuration
|
|
66
|
+
* @throws {ValidationError} If required config is missing or gateway URL not whitelisted
|
|
67
|
+
*/
|
|
68
|
+
constructor(config) {
|
|
69
|
+
// Validate required config
|
|
70
|
+
if (!config.accessKey) {
|
|
71
|
+
throw new errors_1.ValidationError('accessKey', 'Filebase access key is required');
|
|
72
|
+
}
|
|
73
|
+
if (!config.secretKey) {
|
|
74
|
+
throw new errors_1.ValidationError('secretKey', 'Filebase secret key is required');
|
|
75
|
+
}
|
|
76
|
+
// P0-1: Validate gateway URL against whitelist (SSRF protection)
|
|
77
|
+
const gatewayUrl = config.gatewayUrl || DEFAULT_GATEWAY;
|
|
78
|
+
(0, validation_1.validateGatewayURL)(gatewayUrl, validation_1.ALLOWED_IPFS_GATEWAYS, 'gatewayUrl');
|
|
79
|
+
// Initialize S3 client
|
|
80
|
+
this.s3 = new client_s3_1.S3Client({
|
|
81
|
+
endpoint: config.endpoint || DEFAULT_ENDPOINT,
|
|
82
|
+
region: DEFAULT_REGION,
|
|
83
|
+
credentials: {
|
|
84
|
+
accessKeyId: config.accessKey,
|
|
85
|
+
secretAccessKey: config.secretKey
|
|
86
|
+
},
|
|
87
|
+
forcePathStyle: true // Required for S3-compatible services
|
|
88
|
+
});
|
|
89
|
+
this.bucket = config.bucket || DEFAULT_BUCKET;
|
|
90
|
+
this.gatewayUrl = gatewayUrl;
|
|
91
|
+
this.timeout = config.timeout || DEFAULT_TIMEOUT;
|
|
92
|
+
this.maxFileSize = config.maxFileSize || DEFAULT_MAX_FILE_SIZE;
|
|
93
|
+
this.maxDownloadSize = config.maxDownloadSize || DEFAULT_MAX_DOWNLOAD_SIZE;
|
|
94
|
+
// P1-2: Default retry options
|
|
95
|
+
this.retryOptions = {
|
|
96
|
+
maxAttempts: 3,
|
|
97
|
+
initialDelayMs: 1000,
|
|
98
|
+
maxDelayMs: 10000,
|
|
99
|
+
backoffMultiplier: 2
|
|
100
|
+
};
|
|
101
|
+
// Circuit breaker for gateway health tracking
|
|
102
|
+
this.circuitBreakerEnabled = config.circuitBreaker?.enabled !== false;
|
|
103
|
+
if (this.circuitBreakerEnabled) {
|
|
104
|
+
this.circuitBreaker = new circuitBreaker_1.GatewayCircuitBreaker({
|
|
105
|
+
failureThreshold: config.circuitBreaker?.failureThreshold,
|
|
106
|
+
resetTimeoutMs: config.circuitBreaker?.resetTimeoutMs,
|
|
107
|
+
failureWindowMs: config.circuitBreaker?.failureWindowMs,
|
|
108
|
+
successThreshold: config.circuitBreaker?.successThreshold
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
this.circuitBreaker = null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// ==========================================================================
|
|
116
|
+
// Public Methods
|
|
117
|
+
// ==========================================================================
|
|
118
|
+
/**
|
|
119
|
+
* Upload JSON to IPFS via Filebase (automatic pinning)
|
|
120
|
+
*
|
|
121
|
+
* @param data - JSON-serializable data to upload
|
|
122
|
+
* @param options - Upload options
|
|
123
|
+
* @returns Upload result with CID
|
|
124
|
+
* @throws {FileSizeLimitExceededError} If data exceeds max size
|
|
125
|
+
* @throws {StorageAuthenticationError} If credentials are invalid
|
|
126
|
+
* @throws {UploadTimeoutError} If upload times out
|
|
127
|
+
* @throws {StorageError} If upload fails
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* const result = await client.uploadJSON({
|
|
132
|
+
* version: '1.0.0',
|
|
133
|
+
* serviceType: 'text-generation',
|
|
134
|
+
* inputData: { prompt: 'Hello!' }
|
|
135
|
+
* });
|
|
136
|
+
* console.log('Uploaded to IPFS:', result.cid);
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
async uploadJSON(data, options) {
|
|
140
|
+
// Serialize to JSON
|
|
141
|
+
const jsonString = JSON.stringify(data);
|
|
142
|
+
const buffer = Buffer.from(jsonString, 'utf-8');
|
|
143
|
+
// Check file size
|
|
144
|
+
if (buffer.length > this.maxFileSize) {
|
|
145
|
+
throw new errors_1.FileSizeLimitExceededError(buffer.length, this.maxFileSize);
|
|
146
|
+
}
|
|
147
|
+
// Generate unique key if not provided
|
|
148
|
+
const key = options?.key || this.generateKey('.json');
|
|
149
|
+
try {
|
|
150
|
+
// Upload to Filebase (auto-pins to IPFS)
|
|
151
|
+
const command = new client_s3_1.PutObjectCommand({
|
|
152
|
+
Bucket: this.bucket,
|
|
153
|
+
Key: key,
|
|
154
|
+
Body: buffer,
|
|
155
|
+
ContentType: 'application/json',
|
|
156
|
+
Metadata: options?.metadata
|
|
157
|
+
});
|
|
158
|
+
const response = await this.withTimeout(this.s3.send(command), this.timeout, 'upload');
|
|
159
|
+
// Extract CID from response headers
|
|
160
|
+
// Filebase returns CID in x-amz-meta-cid header
|
|
161
|
+
const cid = response.$metadata?.httpStatusCode === 200
|
|
162
|
+
? await this.getCIDFromKey(key)
|
|
163
|
+
: undefined;
|
|
164
|
+
if (!cid) {
|
|
165
|
+
throw new errors_1.StorageError('upload', 'Failed to retrieve CID after upload');
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
cid,
|
|
169
|
+
size: buffer.length,
|
|
170
|
+
uploadedAt: new Date()
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
// Handle specific errors
|
|
175
|
+
if (error instanceof errors_1.FileSizeLimitExceededError)
|
|
176
|
+
throw error;
|
|
177
|
+
if (error instanceof errors_1.UploadTimeoutError)
|
|
178
|
+
throw error;
|
|
179
|
+
if (error.name === 'CredentialsProviderError' || error.Code === 'InvalidAccessKeyId') {
|
|
180
|
+
throw new errors_1.StorageAuthenticationError('Filebase');
|
|
181
|
+
}
|
|
182
|
+
if (error.Code === 'SlowDown' || error.statusCode === 429) {
|
|
183
|
+
const retryAfter = error.$metadata?.httpHeaders?.['retry-after'];
|
|
184
|
+
throw new errors_1.StorageRateLimitError(retryAfter ? parseInt(retryAfter, 10) : undefined);
|
|
185
|
+
}
|
|
186
|
+
// P0-2: Sanitize error message (may contain AWS credentials)
|
|
187
|
+
throw new errors_1.StorageError('upload', (0, validation_1.sanitizeErrorMessage)(error), {
|
|
188
|
+
originalError: error.name,
|
|
189
|
+
key
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Download JSON from IPFS via gateway
|
|
195
|
+
*
|
|
196
|
+
* Security Features:
|
|
197
|
+
* - Size limit enforcement (P1-1: DoS protection)
|
|
198
|
+
* - Retry with exponential backoff (P1-2)
|
|
199
|
+
* - Centralized CID validation (P1-3)
|
|
200
|
+
* - Credential sanitization in errors (P0-2)
|
|
201
|
+
*
|
|
202
|
+
* @param cid - IPFS CID to download
|
|
203
|
+
* @returns Downloaded and parsed JSON data
|
|
204
|
+
* @throws {InvalidCIDError} If CID format is invalid
|
|
205
|
+
* @throws {ContentNotFoundError} If content not found
|
|
206
|
+
* @throws {FileSizeLimitExceededError} If content exceeds size limit
|
|
207
|
+
* @throws {DownloadTimeoutError} If download times out
|
|
208
|
+
* @throws {StorageError} If download fails
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* const data = await client.downloadJSON('bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi');
|
|
213
|
+
* console.log('Downloaded:', data);
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
async downloadJSON(cid) {
|
|
217
|
+
// P1-3: Use centralized CID validation
|
|
218
|
+
(0, validation_1.validateCID)(cid);
|
|
219
|
+
const url = `${this.gatewayUrl}${cid}`;
|
|
220
|
+
// Circuit breaker: check gateway health before attempting download
|
|
221
|
+
if (this.circuitBreaker && !this.circuitBreaker.isHealthy(this.gatewayUrl)) {
|
|
222
|
+
const state = this.circuitBreaker.getState(this.gatewayUrl);
|
|
223
|
+
const failures = this.circuitBreaker.getFailureCount(this.gatewayUrl);
|
|
224
|
+
throw new errors_1.StorageError('download', `Gateway circuit breaker OPEN for ${this.gatewayUrl}. ` +
|
|
225
|
+
`State: ${state}, Failures: ${failures}. ` +
|
|
226
|
+
`Please wait for cooldown period before retrying.`, { cid, circuitState: state });
|
|
227
|
+
}
|
|
228
|
+
// P1-2: Wrap in retry logic
|
|
229
|
+
return (0, retry_1.withRetry)(async () => {
|
|
230
|
+
const controller = new AbortController();
|
|
231
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
232
|
+
try {
|
|
233
|
+
const response = await fetch(url, {
|
|
234
|
+
signal: controller.signal,
|
|
235
|
+
headers: {
|
|
236
|
+
'Accept': 'application/json'
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
clearTimeout(timeoutId);
|
|
240
|
+
if (!response.ok) {
|
|
241
|
+
if (response.status === 404) {
|
|
242
|
+
throw new errors_1.ContentNotFoundError(cid);
|
|
243
|
+
}
|
|
244
|
+
throw new errors_1.StorageError('download', `HTTP ${response.status}: ${response.statusText}`, { cid });
|
|
245
|
+
}
|
|
246
|
+
// P1-1: Check Content-Length header before downloading
|
|
247
|
+
const contentLength = response.headers.get('content-length');
|
|
248
|
+
if (contentLength && parseInt(contentLength, 10) > this.maxDownloadSize) {
|
|
249
|
+
throw new errors_1.FileSizeLimitExceededError(parseInt(contentLength, 10), this.maxDownloadSize);
|
|
250
|
+
}
|
|
251
|
+
// P1-1: Stream response with size limit enforcement
|
|
252
|
+
const reader = response.body?.getReader();
|
|
253
|
+
if (!reader) {
|
|
254
|
+
throw new errors_1.StorageError('download', 'No response body', { cid });
|
|
255
|
+
}
|
|
256
|
+
const chunks = [];
|
|
257
|
+
let totalSize = 0;
|
|
258
|
+
while (true) {
|
|
259
|
+
const { done, value } = await reader.read();
|
|
260
|
+
if (done)
|
|
261
|
+
break;
|
|
262
|
+
totalSize += value.length;
|
|
263
|
+
// P1-1: Enforce size limit during streaming
|
|
264
|
+
if (totalSize > this.maxDownloadSize) {
|
|
265
|
+
reader.cancel();
|
|
266
|
+
throw new errors_1.FileSizeLimitExceededError(totalSize, this.maxDownloadSize);
|
|
267
|
+
}
|
|
268
|
+
chunks.push(value);
|
|
269
|
+
}
|
|
270
|
+
// Combine chunks into text
|
|
271
|
+
const decoder = new TextDecoder();
|
|
272
|
+
const text = chunks.map(chunk => decoder.decode(chunk, { stream: true })).join('') +
|
|
273
|
+
decoder.decode();
|
|
274
|
+
const data = JSON.parse(text);
|
|
275
|
+
// Circuit breaker: record success
|
|
276
|
+
if (this.circuitBreaker) {
|
|
277
|
+
this.circuitBreaker.recordSuccess(this.gatewayUrl);
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
data,
|
|
281
|
+
size: totalSize,
|
|
282
|
+
downloadedAt: new Date()
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
clearTimeout(timeoutId);
|
|
287
|
+
// Circuit breaker: record failure for retryable errors
|
|
288
|
+
// (non-retryable errors like 404 shouldn't count as gateway failures)
|
|
289
|
+
if (this.circuitBreaker && this.isGatewayFailure(error)) {
|
|
290
|
+
this.circuitBreaker.recordFailure(this.gatewayUrl);
|
|
291
|
+
}
|
|
292
|
+
if (error instanceof errors_1.ContentNotFoundError)
|
|
293
|
+
throw error;
|
|
294
|
+
if (error instanceof errors_1.FileSizeLimitExceededError)
|
|
295
|
+
throw error;
|
|
296
|
+
if (error.name === 'AbortError') {
|
|
297
|
+
throw new errors_1.DownloadTimeoutError(cid, this.timeout);
|
|
298
|
+
}
|
|
299
|
+
if (error instanceof SyntaxError) {
|
|
300
|
+
throw new errors_1.StorageError('download', `Invalid JSON content for CID: ${cid}`, { cid });
|
|
301
|
+
}
|
|
302
|
+
// P0-2: Sanitize error message
|
|
303
|
+
throw new errors_1.StorageError('download', (0, validation_1.sanitizeErrorMessage)(error), {
|
|
304
|
+
cid,
|
|
305
|
+
originalError: error.name
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}, this.retryOptions);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Upload binary data to IPFS
|
|
312
|
+
*
|
|
313
|
+
* @param data - Binary data to upload
|
|
314
|
+
* @param contentType - MIME type of the content
|
|
315
|
+
* @param options - Upload options
|
|
316
|
+
* @returns Upload result with CID
|
|
317
|
+
*/
|
|
318
|
+
async uploadBinary(data, contentType, options) {
|
|
319
|
+
const buffer = Buffer.from(data);
|
|
320
|
+
// Check file size
|
|
321
|
+
if (buffer.length > this.maxFileSize) {
|
|
322
|
+
throw new errors_1.FileSizeLimitExceededError(buffer.length, this.maxFileSize);
|
|
323
|
+
}
|
|
324
|
+
// Generate key with appropriate extension
|
|
325
|
+
const extension = this.getExtensionFromContentType(contentType);
|
|
326
|
+
const key = options?.key || this.generateKey(extension);
|
|
327
|
+
try {
|
|
328
|
+
const command = new client_s3_1.PutObjectCommand({
|
|
329
|
+
Bucket: this.bucket,
|
|
330
|
+
Key: key,
|
|
331
|
+
Body: buffer,
|
|
332
|
+
ContentType: contentType,
|
|
333
|
+
Metadata: options?.metadata
|
|
334
|
+
});
|
|
335
|
+
await this.withTimeout(this.s3.send(command), this.timeout, 'upload');
|
|
336
|
+
const cid = await this.getCIDFromKey(key);
|
|
337
|
+
if (!cid) {
|
|
338
|
+
throw new errors_1.StorageError('upload', 'Failed to retrieve CID after upload');
|
|
339
|
+
}
|
|
340
|
+
return {
|
|
341
|
+
cid,
|
|
342
|
+
size: buffer.length,
|
|
343
|
+
uploadedAt: new Date()
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
if (error instanceof errors_1.FileSizeLimitExceededError)
|
|
348
|
+
throw error;
|
|
349
|
+
if (error instanceof errors_1.UploadTimeoutError)
|
|
350
|
+
throw error;
|
|
351
|
+
if (error instanceof errors_1.StorageError)
|
|
352
|
+
throw error;
|
|
353
|
+
// P0-2: Sanitize error message (may contain AWS credentials)
|
|
354
|
+
throw new errors_1.StorageError('upload', (0, validation_1.sanitizeErrorMessage)(error), {
|
|
355
|
+
originalError: error.name,
|
|
356
|
+
key
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Download binary data from IPFS
|
|
362
|
+
*
|
|
363
|
+
* Security Features:
|
|
364
|
+
* - Size limit enforcement (P1-1: DoS protection)
|
|
365
|
+
* - Retry with exponential backoff (P1-2)
|
|
366
|
+
* - Centralized CID validation (P1-3)
|
|
367
|
+
*
|
|
368
|
+
* @param cid - IPFS CID to download
|
|
369
|
+
* @returns Downloaded binary data
|
|
370
|
+
*/
|
|
371
|
+
async downloadBinary(cid) {
|
|
372
|
+
// P1-3: Use centralized CID validation
|
|
373
|
+
(0, validation_1.validateCID)(cid);
|
|
374
|
+
const url = `${this.gatewayUrl}${cid}`;
|
|
375
|
+
// Circuit breaker: check gateway health before attempting download
|
|
376
|
+
if (this.circuitBreaker && !this.circuitBreaker.isHealthy(this.gatewayUrl)) {
|
|
377
|
+
const state = this.circuitBreaker.getState(this.gatewayUrl);
|
|
378
|
+
const failures = this.circuitBreaker.getFailureCount(this.gatewayUrl);
|
|
379
|
+
throw new errors_1.StorageError('download', `Gateway circuit breaker OPEN for ${this.gatewayUrl}. ` +
|
|
380
|
+
`State: ${state}, Failures: ${failures}. ` +
|
|
381
|
+
`Please wait for cooldown period before retrying.`, { cid, circuitState: state });
|
|
382
|
+
}
|
|
383
|
+
// P1-2: Wrap in retry logic
|
|
384
|
+
return (0, retry_1.withRetry)(async () => {
|
|
385
|
+
const controller = new AbortController();
|
|
386
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
387
|
+
try {
|
|
388
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
389
|
+
clearTimeout(timeoutId);
|
|
390
|
+
if (!response.ok) {
|
|
391
|
+
if (response.status === 404) {
|
|
392
|
+
throw new errors_1.ContentNotFoundError(cid);
|
|
393
|
+
}
|
|
394
|
+
throw new errors_1.StorageError('download', `HTTP ${response.status}: ${response.statusText}`, { cid });
|
|
395
|
+
}
|
|
396
|
+
// P1-1: Check Content-Length header before downloading
|
|
397
|
+
const contentLength = response.headers.get('content-length');
|
|
398
|
+
if (contentLength && parseInt(contentLength, 10) > this.maxDownloadSize) {
|
|
399
|
+
throw new errors_1.FileSizeLimitExceededError(parseInt(contentLength, 10), this.maxDownloadSize);
|
|
400
|
+
}
|
|
401
|
+
// P1-1: Stream response with size limit enforcement
|
|
402
|
+
const reader = response.body?.getReader();
|
|
403
|
+
if (!reader) {
|
|
404
|
+
throw new errors_1.StorageError('download', 'No response body', { cid });
|
|
405
|
+
}
|
|
406
|
+
const chunks = [];
|
|
407
|
+
let totalSize = 0;
|
|
408
|
+
while (true) {
|
|
409
|
+
const { done, value } = await reader.read();
|
|
410
|
+
if (done)
|
|
411
|
+
break;
|
|
412
|
+
totalSize += value.length;
|
|
413
|
+
// P1-1: Enforce size limit during streaming
|
|
414
|
+
if (totalSize > this.maxDownloadSize) {
|
|
415
|
+
reader.cancel();
|
|
416
|
+
throw new errors_1.FileSizeLimitExceededError(totalSize, this.maxDownloadSize);
|
|
417
|
+
}
|
|
418
|
+
chunks.push(value);
|
|
419
|
+
}
|
|
420
|
+
// Combine chunks into Buffer
|
|
421
|
+
const buffer = Buffer.concat(chunks);
|
|
422
|
+
// Circuit breaker: record success
|
|
423
|
+
if (this.circuitBreaker) {
|
|
424
|
+
this.circuitBreaker.recordSuccess(this.gatewayUrl);
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
data: buffer,
|
|
428
|
+
size: buffer.length,
|
|
429
|
+
downloadedAt: new Date()
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
catch (error) {
|
|
433
|
+
clearTimeout(timeoutId);
|
|
434
|
+
// Circuit breaker: record failure for retryable errors
|
|
435
|
+
if (this.circuitBreaker && this.isGatewayFailure(error)) {
|
|
436
|
+
this.circuitBreaker.recordFailure(this.gatewayUrl);
|
|
437
|
+
}
|
|
438
|
+
if (error instanceof errors_1.ContentNotFoundError)
|
|
439
|
+
throw error;
|
|
440
|
+
if (error instanceof errors_1.FileSizeLimitExceededError)
|
|
441
|
+
throw error;
|
|
442
|
+
if (error.name === 'AbortError') {
|
|
443
|
+
throw new errors_1.DownloadTimeoutError(cid, this.timeout);
|
|
444
|
+
}
|
|
445
|
+
// P0-2: Sanitize error message
|
|
446
|
+
throw new errors_1.StorageError('download', (0, validation_1.sanitizeErrorMessage)(error), {
|
|
447
|
+
cid,
|
|
448
|
+
originalError: error.name
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}, this.retryOptions);
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Check if content exists on IPFS
|
|
455
|
+
*
|
|
456
|
+
* @param cid - IPFS CID to check
|
|
457
|
+
* @returns True if content exists
|
|
458
|
+
*/
|
|
459
|
+
async exists(cid) {
|
|
460
|
+
// P1-3: Use centralized CID validation
|
|
461
|
+
(0, validation_1.validateCID)(cid);
|
|
462
|
+
const url = `${this.gatewayUrl}${cid}`;
|
|
463
|
+
try {
|
|
464
|
+
const controller = new AbortController();
|
|
465
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
466
|
+
const response = await fetch(url, {
|
|
467
|
+
method: 'HEAD',
|
|
468
|
+
signal: controller.signal
|
|
469
|
+
});
|
|
470
|
+
clearTimeout(timeoutId);
|
|
471
|
+
return response.ok;
|
|
472
|
+
}
|
|
473
|
+
catch {
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Get the bucket name
|
|
479
|
+
*/
|
|
480
|
+
getBucket() {
|
|
481
|
+
return this.bucket;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Get the gateway URL
|
|
485
|
+
*/
|
|
486
|
+
getGatewayUrl() {
|
|
487
|
+
return this.gatewayUrl;
|
|
488
|
+
}
|
|
489
|
+
// ==========================================================================
|
|
490
|
+
// Private Methods
|
|
491
|
+
// ==========================================================================
|
|
492
|
+
/**
|
|
493
|
+
* Generate unique key for S3 object
|
|
494
|
+
*/
|
|
495
|
+
generateKey(extension) {
|
|
496
|
+
const timestamp = Date.now();
|
|
497
|
+
const random = Math.random().toString(36).substring(2, 10);
|
|
498
|
+
return `${timestamp}-${random}${extension}`;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Get CID from uploaded object via HeadObject
|
|
502
|
+
* Filebase returns CID in x-amz-meta-cid header
|
|
503
|
+
*/
|
|
504
|
+
async getCIDFromKey(key) {
|
|
505
|
+
try {
|
|
506
|
+
const command = new client_s3_1.HeadObjectCommand({
|
|
507
|
+
Bucket: this.bucket,
|
|
508
|
+
Key: key
|
|
509
|
+
});
|
|
510
|
+
const response = await this.s3.send(command);
|
|
511
|
+
// Filebase stores CID in metadata
|
|
512
|
+
return response.Metadata?.cid;
|
|
513
|
+
}
|
|
514
|
+
catch {
|
|
515
|
+
return undefined;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Get file extension from content type
|
|
520
|
+
*/
|
|
521
|
+
getExtensionFromContentType(contentType) {
|
|
522
|
+
const types = {
|
|
523
|
+
'application/json': '.json',
|
|
524
|
+
'text/plain': '.txt',
|
|
525
|
+
'image/png': '.png',
|
|
526
|
+
'image/jpeg': '.jpg',
|
|
527
|
+
'application/pdf': '.pdf',
|
|
528
|
+
'application/octet-stream': '.bin'
|
|
529
|
+
};
|
|
530
|
+
return types[contentType] || '.bin';
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Wrap promise with timeout
|
|
534
|
+
*/
|
|
535
|
+
async withTimeout(promise, timeoutMs, operation) {
|
|
536
|
+
let timeoutId;
|
|
537
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
538
|
+
timeoutId = setTimeout(() => {
|
|
539
|
+
if (operation === 'upload') {
|
|
540
|
+
reject(new errors_1.UploadTimeoutError(timeoutMs));
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
reject(new errors_1.DownloadTimeoutError('unknown', timeoutMs));
|
|
544
|
+
}
|
|
545
|
+
}, timeoutMs);
|
|
546
|
+
});
|
|
547
|
+
try {
|
|
548
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
549
|
+
}
|
|
550
|
+
finally {
|
|
551
|
+
clearTimeout(timeoutId);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Determine if an error represents a gateway failure
|
|
556
|
+
* (should be counted by circuit breaker)
|
|
557
|
+
*
|
|
558
|
+
* Gateway failures are network/server errors that indicate
|
|
559
|
+
* the gateway is unhealthy. Content-specific errors (404, invalid JSON)
|
|
560
|
+
* are NOT gateway failures.
|
|
561
|
+
*
|
|
562
|
+
* @param error - Error to check
|
|
563
|
+
* @returns true if error is a gateway failure
|
|
564
|
+
*/
|
|
565
|
+
isGatewayFailure(error) {
|
|
566
|
+
if (!error)
|
|
567
|
+
return false;
|
|
568
|
+
const e = error;
|
|
569
|
+
// 404 Not Found - content doesn't exist, not a gateway failure
|
|
570
|
+
if (error instanceof errors_1.ContentNotFoundError)
|
|
571
|
+
return false;
|
|
572
|
+
// File size exceeded - content too large, not a gateway failure
|
|
573
|
+
if (error instanceof errors_1.FileSizeLimitExceededError)
|
|
574
|
+
return false;
|
|
575
|
+
// Invalid JSON - content is corrupted, not a gateway failure
|
|
576
|
+
if (error instanceof SyntaxError)
|
|
577
|
+
return false;
|
|
578
|
+
// Timeout - gateway is slow/unresponsive, IS a failure
|
|
579
|
+
if (e.name === 'AbortError' || e.name === 'TimeoutError')
|
|
580
|
+
return true;
|
|
581
|
+
// 5xx server errors - gateway issue
|
|
582
|
+
if (e.status >= 500 && e.status < 600)
|
|
583
|
+
return true;
|
|
584
|
+
if (e.statusCode >= 500 && e.statusCode < 600)
|
|
585
|
+
return true;
|
|
586
|
+
// Network errors - gateway unreachable
|
|
587
|
+
const networkErrors = ['ECONNRESET', 'ECONNREFUSED', 'ETIMEDOUT', 'ENOTFOUND'];
|
|
588
|
+
if (e.code && networkErrors.includes(e.code))
|
|
589
|
+
return true;
|
|
590
|
+
// Rate limiting - gateway overloaded
|
|
591
|
+
if (e.status === 429 || e.statusCode === 429)
|
|
592
|
+
return true;
|
|
593
|
+
// Generic StorageError from network issues or HTTP errors
|
|
594
|
+
if (error instanceof errors_1.StorageError) {
|
|
595
|
+
const message = e.message?.toLowerCase() || '';
|
|
596
|
+
// Network-related errors
|
|
597
|
+
if (message.includes('timeout') ||
|
|
598
|
+
message.includes('network') ||
|
|
599
|
+
message.includes('connection')) {
|
|
600
|
+
return true;
|
|
601
|
+
}
|
|
602
|
+
// HTTP 5xx errors in message (e.g., "HTTP 500: Internal Server Error")
|
|
603
|
+
if (/http 5\d{2}/.test(message)) {
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
// HTTP 429 rate limiting in message
|
|
607
|
+
if (/http 429/.test(message)) {
|
|
608
|
+
return true;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
// ==========================================================================
|
|
614
|
+
// Circuit Breaker Status (Public API)
|
|
615
|
+
// ==========================================================================
|
|
616
|
+
/**
|
|
617
|
+
* Get circuit breaker status for the gateway
|
|
618
|
+
*
|
|
619
|
+
* @returns Circuit breaker status or null if disabled
|
|
620
|
+
*/
|
|
621
|
+
getCircuitBreakerStatus() {
|
|
622
|
+
if (!this.circuitBreaker) {
|
|
623
|
+
return null;
|
|
624
|
+
}
|
|
625
|
+
return {
|
|
626
|
+
enabled: true,
|
|
627
|
+
state: this.circuitBreaker.getState(this.gatewayUrl),
|
|
628
|
+
failures: this.circuitBreaker.getFailureCount(this.gatewayUrl),
|
|
629
|
+
isHealthy: this.circuitBreaker.isHealthy(this.gatewayUrl)
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Reset circuit breaker for the gateway
|
|
634
|
+
* Use this to manually reset after a known temporary outage
|
|
635
|
+
*/
|
|
636
|
+
resetCircuitBreaker() {
|
|
637
|
+
if (this.circuitBreaker) {
|
|
638
|
+
this.circuitBreaker.reset(this.gatewayUrl);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
exports.FilebaseClient = FilebaseClient;
|
|
643
|
+
//# sourceMappingURL=FilebaseClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilebaseClient.js","sourceRoot":"","sources":["../../src/storage/FilebaseClient.ts"],"names":[],"mappings":"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"}
|