@lidofinance/lsv-cli 1.8.0 → 1.9.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 (41) hide show
  1. package/README.md +9 -1
  2. package/dist/abi/defi-wrapper/MellowStrategy.d.ts +429 -0
  3. package/dist/abi/defi-wrapper/MellowStrategy.js +892 -0
  4. package/dist/abi/defi-wrapper/MellowStrategy.js.map +1 -0
  5. package/dist/abi/defi-wrapper/index.d.ts +1 -0
  6. package/dist/abi/defi-wrapper/index.js +1 -0
  7. package/dist/abi/defi-wrapper/index.js.map +1 -1
  8. package/dist/configs/constants.d.ts +7 -1
  9. package/dist/features/defi-wrapper/timelock.d.ts +8928 -2
  10. package/dist/features/defi-wrapper/timelock.js +82 -8
  11. package/dist/features/defi-wrapper/timelock.js.map +1 -1
  12. package/dist/programs/defi-wrapper/use-cases/timelock-governance/common/read.js +22 -4
  13. package/dist/programs/defi-wrapper/use-cases/timelock-governance/common/read.js.map +1 -1
  14. package/dist/programs/defi-wrapper/use-cases/timelock-governance/common/write.js +194 -16
  15. package/dist/programs/defi-wrapper/use-cases/timelock-governance/common/write.js.map +1 -1
  16. package/dist/providers/wallet.d.ts +2905 -8441
  17. package/dist/tests/integration/helpers/test-client.d.ts +2071 -5761
  18. package/dist/tests/utils/ipfs-security.test.js +129 -2
  19. package/dist/tests/utils/ipfs-security.test.js.map +1 -1
  20. package/dist/tests/utils/ipfs.test.js +8 -8
  21. package/dist/tests/utils/ipfs.test.js.map +1 -1
  22. package/dist/tests/utils/parse-abi-arguments.test.d.ts +1 -0
  23. package/dist/tests/utils/parse-abi-arguments.test.js +399 -0
  24. package/dist/tests/utils/parse-abi-arguments.test.js.map +1 -0
  25. package/dist/tests/utils/stream-helpers.d.ts +1 -0
  26. package/dist/tests/utils/stream-helpers.js +11 -0
  27. package/dist/tests/utils/stream-helpers.js.map +1 -0
  28. package/dist/utils/env.d.ts +1 -0
  29. package/dist/utils/env.js +8 -0
  30. package/dist/utils/env.js.map +1 -0
  31. package/dist/utils/ipfs.d.ts +4 -2
  32. package/dist/utils/ipfs.js +75 -10
  33. package/dist/utils/ipfs.js.map +1 -1
  34. package/dist/utils/parse-abi-arguments.d.ts +24 -0
  35. package/dist/utils/parse-abi-arguments.js +159 -0
  36. package/dist/utils/parse-abi-arguments.js.map +1 -0
  37. package/dist/utils/rate-limit.d.ts +9 -0
  38. package/dist/utils/rate-limit.js +1 -6
  39. package/dist/utils/rate-limit.js.map +1 -1
  40. package/dist/version/index.js +1 -1
  41. package/package.json +8 -8
@@ -0,0 +1,399 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { parseAbiArguments } from '../../utils/parse-abi-arguments.js';
3
+ const fn = (inputs) => ({
4
+ type: 'function',
5
+ name: 'test',
6
+ inputs,
7
+ outputs: [],
8
+ stateMutability: 'nonpayable',
9
+ });
10
+ const ADDR = '0x0000000000000000000000000000000000000001';
11
+ // --- parseAbiArguments (top-level) ---
12
+ describe('parseAbiArguments', () => {
13
+ test('throws on argument count mismatch (too few)', () => {
14
+ const abi = fn([{ name: 'a', type: 'uint256' }]);
15
+ expect(() => parseAbiArguments(abi, [])).toThrow(/argument count mismatch/i);
16
+ });
17
+ test('throws on argument count mismatch (too many)', () => {
18
+ const abi = fn([]);
19
+ expect(() => parseAbiArguments(abi, ['1'])).toThrow(/argument count mismatch/i);
20
+ });
21
+ test('returns empty array for zero-arg function', () => {
22
+ expect(parseAbiArguments(fn([]), [])).toEqual([]);
23
+ });
24
+ test('parses multiple inputs of different types', () => {
25
+ const abi = fn([
26
+ { name: 'to', type: 'address' },
27
+ { name: 'amount', type: 'uint256' },
28
+ { name: 'flag', type: 'bool' },
29
+ ]);
30
+ expect(parseAbiArguments(abi, [ADDR, '1000', 'true'])).toEqual([
31
+ ADDR,
32
+ 1000n,
33
+ true,
34
+ ]);
35
+ });
36
+ });
37
+ // --- address ---
38
+ describe('address', () => {
39
+ test('valid address passes through', () => {
40
+ const abi = fn([{ name: 'x', type: 'address' }]);
41
+ expect(parseAbiArguments(abi, [ADDR])).toEqual([ADDR]);
42
+ });
43
+ test('invalid address throws', () => {
44
+ const abi = fn([{ name: 'x', type: 'address' }]);
45
+ expect(() => parseAbiArguments(abi, ['0x123'])).toThrow(/invalid address/i);
46
+ });
47
+ test('non-hex string throws', () => {
48
+ const abi = fn([{ name: 'x', type: 'address' }]);
49
+ expect(() => parseAbiArguments(abi, ['notanaddress'])).toThrow();
50
+ });
51
+ });
52
+ // --- bool ---
53
+ describe('bool', () => {
54
+ test('"true" parses to boolean true', () => {
55
+ const abi = fn([{ name: 'x', type: 'bool' }]);
56
+ expect(parseAbiArguments(abi, ['true'])).toEqual([true]);
57
+ });
58
+ test('"false" parses to boolean false', () => {
59
+ const abi = fn([{ name: 'x', type: 'bool' }]);
60
+ expect(parseAbiArguments(abi, ['false'])).toEqual([false]);
61
+ });
62
+ test('invalid bool value throws', () => {
63
+ const abi = fn([{ name: 'x', type: 'bool' }]);
64
+ expect(() => parseAbiArguments(abi, ['yes'])).toThrow(/invalid bool/i);
65
+ });
66
+ test('"1" is not accepted as bool', () => {
67
+ const abi = fn([{ name: 'x', type: 'bool' }]);
68
+ expect(() => parseAbiArguments(abi, ['1'])).toThrow();
69
+ });
70
+ });
71
+ // --- uint / int ---
72
+ describe('uint / int', () => {
73
+ test('uint256: positive integer', () => {
74
+ const abi = fn([{ name: 'x', type: 'uint256' }]);
75
+ expect(parseAbiArguments(abi, ['42'])).toEqual([42n]);
76
+ });
77
+ test('uint256: zero is valid', () => {
78
+ const abi = fn([{ name: 'x', type: 'uint256' }]);
79
+ expect(parseAbiArguments(abi, ['0'])).toEqual([0n]);
80
+ });
81
+ test('uint256: large value stays precise', () => {
82
+ const abi = fn([{ name: 'x', type: 'uint256' }]);
83
+ const big = '1000000000000000000';
84
+ expect(parseAbiArguments(abi, [big])).toEqual([1000000000000000000n]);
85
+ });
86
+ test('uint256: negative value throws', () => {
87
+ const abi = fn([{ name: 'x', type: 'uint256' }]);
88
+ expect(() => parseAbiArguments(abi, ['-1'])).toThrow(/unsigned integer cannot be negative/i);
89
+ });
90
+ test('uint8: alias works (startsWith uint)', () => {
91
+ const abi = fn([{ name: 'x', type: 'uint8' }]);
92
+ expect(parseAbiArguments(abi, ['255'])).toEqual([255n]);
93
+ });
94
+ test('int256: negative value is valid', () => {
95
+ const abi = fn([{ name: 'x', type: 'int256' }]);
96
+ expect(parseAbiArguments(abi, ['-1000'])).toEqual([-1000n]);
97
+ });
98
+ test('int8: positive and negative', () => {
99
+ const abi = fn([{ name: 'x', type: 'int8' }]);
100
+ expect(parseAbiArguments(abi, ['-128'])).toEqual([-128n]);
101
+ });
102
+ test('non-numeric string throws', () => {
103
+ const abi = fn([{ name: 'x', type: 'uint256' }]);
104
+ expect(() => parseAbiArguments(abi, ['abc'])).toThrow();
105
+ });
106
+ });
107
+ // --- bytesN (fixed-size) ---
108
+ describe('bytesN', () => {
109
+ test('bytes32: correct-size hex passes', () => {
110
+ const value = `0x${'aa'.repeat(32)}`;
111
+ const abi = fn([{ name: 'x', type: 'bytes32' }]);
112
+ expect(parseAbiArguments(abi, [value])).toEqual([value]);
113
+ });
114
+ test('bytes1: single byte passes', () => {
115
+ const abi = fn([{ name: 'x', type: 'bytes1' }]);
116
+ expect(parseAbiArguments(abi, ['0xff'])).toEqual(['0xff']);
117
+ });
118
+ test('bytes32: wrong size throws', () => {
119
+ const abi = fn([{ name: 'x', type: 'bytes32' }]);
120
+ expect(() => parseAbiArguments(abi, ['0xdead'])).toThrow(/expected 32 bytes/i);
121
+ });
122
+ test('bytes32: non-hex throws', () => {
123
+ const abi = fn([{ name: 'x', type: 'bytes32' }]);
124
+ expect(() => parseAbiArguments(abi, ['notahex'])).toThrow(/invalid hex/i);
125
+ });
126
+ test('bytes4: correct size', () => {
127
+ const abi = fn([{ name: 'x', type: 'bytes4' }]);
128
+ expect(parseAbiArguments(abi, ['0xdeadbeef'])).toEqual(['0xdeadbeef']);
129
+ });
130
+ });
131
+ // --- bytes (dynamic) ---
132
+ describe('bytes', () => {
133
+ test('valid hex passes', () => {
134
+ const abi = fn([{ name: 'x', type: 'bytes' }]);
135
+ expect(parseAbiArguments(abi, ['0xdeadbeef'])).toEqual(['0xdeadbeef']);
136
+ });
137
+ test('empty bytes (0x) is valid', () => {
138
+ const abi = fn([{ name: 'x', type: 'bytes' }]);
139
+ expect(parseAbiArguments(abi, ['0x'])).toEqual(['0x']);
140
+ });
141
+ test('non-hex string throws', () => {
142
+ const abi = fn([{ name: 'x', type: 'bytes' }]);
143
+ expect(() => parseAbiArguments(abi, ['hello'])).toThrow(/invalid hex/i);
144
+ });
145
+ });
146
+ // --- string ---
147
+ describe('string', () => {
148
+ test('any string passes through unchanged', () => {
149
+ const abi = fn([{ name: 'x', type: 'string' }]);
150
+ expect(parseAbiArguments(abi, ['hello world'])).toEqual(['hello world']);
151
+ });
152
+ test('empty string is valid', () => {
153
+ const abi = fn([{ name: 'x', type: 'string' }]);
154
+ expect(parseAbiArguments(abi, [''])).toEqual(['']);
155
+ });
156
+ });
157
+ // --- fixed-size arrays ---
158
+ describe('fixed-size array', () => {
159
+ test('uint256[3]: correct elements parsed as bigints', () => {
160
+ const abi = fn([{ name: 'x', type: 'uint256[3]' }]);
161
+ expect(parseAbiArguments(abi, ['[1,2,3]'])).toEqual([[1n, 2n, 3n]]);
162
+ });
163
+ test('uint256[3]: wrong length throws', () => {
164
+ const abi = fn([{ name: 'x', type: 'uint256[3]' }]);
165
+ expect(() => parseAbiArguments(abi, ['[1,2]'])).toThrow(/length/i);
166
+ });
167
+ test('address[2]: elements parsed as addresses', () => {
168
+ const abi = fn([{ name: 'x', type: 'address[2]' }]);
169
+ expect(parseAbiArguments(abi, [
170
+ `[${JSON.stringify(ADDR)},${JSON.stringify(ADDR)}]`,
171
+ ])).toEqual([[ADDR, ADDR]]);
172
+ });
173
+ test('bool[2]: elements parsed as booleans', () => {
174
+ const abi = fn([{ name: 'x', type: 'bool[2]' }]);
175
+ expect(parseAbiArguments(abi, ['[true,false]'])).toEqual([[true, false]]);
176
+ });
177
+ // Acceptance test — exposes String([]) bug
178
+ test('uint256[2][2]: nested fixed array parsed correctly', () => {
179
+ const abi = fn([{ name: 'x', type: 'uint256[2][2]' }]);
180
+ expect(parseAbiArguments(abi, ['[[1,2],[3,4]]'])).toEqual([
181
+ [
182
+ [1n, 2n],
183
+ [3n, 4n],
184
+ ],
185
+ ]);
186
+ });
187
+ test('non-array JSON value throws (line 78)', () => {
188
+ const abi = fn([{ name: 'x', type: 'uint256[3]' }]);
189
+ expect(() => parseAbiArguments(abi, ['42'])).toThrow(/expected a json array/i);
190
+ });
191
+ });
192
+ // --- dynamic arrays ---
193
+ describe('dynamic array', () => {
194
+ test('uint256[]: empty array', () => {
195
+ const abi = fn([{ name: 'x', type: 'uint256[]' }]);
196
+ expect(parseAbiArguments(abi, ['[]'])).toEqual([[]]);
197
+ });
198
+ test('uint256[]: multiple elements', () => {
199
+ const abi = fn([{ name: 'x', type: 'uint256[]' }]);
200
+ expect(parseAbiArguments(abi, ['[10,20,30]'])).toEqual([[10n, 20n, 30n]]);
201
+ });
202
+ test('address[]: array of addresses', () => {
203
+ const abi = fn([{ name: 'x', type: 'address[]' }]);
204
+ expect(parseAbiArguments(abi, [`[${JSON.stringify(ADDR)}]`])).toEqual([
205
+ [ADDR],
206
+ ]);
207
+ });
208
+ test('string[]: array of strings', () => {
209
+ const abi = fn([{ name: 'x', type: 'string[]' }]);
210
+ expect(parseAbiArguments(abi, ['["foo","bar"]'])).toEqual([['foo', 'bar']]);
211
+ });
212
+ test('non-array JSON value throws (line 101)', () => {
213
+ const abi = fn([{ name: 'x', type: 'uint256[]' }]);
214
+ expect(() => parseAbiArguments(abi, ['"notanarray"'])).toThrow(/expected a json array/i);
215
+ });
216
+ // Acceptance test — exposes String([]) bug
217
+ test('uint256[][]: nested dynamic array parsed correctly', () => {
218
+ const abi = fn([{ name: 'x', type: 'uint256[][]' }]);
219
+ expect(parseAbiArguments(abi, ['[[1,2],[3,4,5]]'])).toEqual([
220
+ [
221
+ [1n, 2n],
222
+ [3n, 4n, 5n],
223
+ ],
224
+ ]);
225
+ });
226
+ // Acceptance test — exposes String([]) bug
227
+ test('uint256[2][]: mixed fixed/dynamic nested array', () => {
228
+ const abi = fn([{ name: 'x', type: 'uint256[2][]' }]);
229
+ expect(parseAbiArguments(abi, ['[[1,2],[3,4]]'])).toEqual([
230
+ [
231
+ [1n, 2n],
232
+ [3n, 4n],
233
+ ],
234
+ ]);
235
+ });
236
+ });
237
+ // --- tuple ---
238
+ describe('tuple (struct)', () => {
239
+ const tupleParam = {
240
+ name: 'data',
241
+ type: 'tuple',
242
+ components: [
243
+ { name: 'addr', type: 'address' },
244
+ { name: 'amount', type: 'uint256' },
245
+ { name: 'flag', type: 'bool' },
246
+ ],
247
+ };
248
+ test('object representation: all fields parsed', () => {
249
+ const abi = fn([tupleParam]);
250
+ const input = JSON.stringify({ addr: ADDR, amount: '999', flag: 'true' });
251
+ expect(parseAbiArguments(abi, [input])).toEqual([
252
+ { addr: ADDR, amount: 999n, flag: true },
253
+ ]);
254
+ });
255
+ test('array representation: positional fields parsed', () => {
256
+ const abi = fn([tupleParam]);
257
+ const input = JSON.stringify([ADDR, '50', 'false']);
258
+ expect(parseAbiArguments(abi, [input])).toEqual([
259
+ { addr: ADDR, amount: 50n, flag: false },
260
+ ]);
261
+ });
262
+ test('array representation: wrong field count throws', () => {
263
+ const abi = fn([tupleParam]);
264
+ expect(() => parseAbiArguments(abi, [`[${JSON.stringify(ADDR)}]`])).toThrow(/expects.*fields/i);
265
+ });
266
+ test('object representation: missing field throws', () => {
267
+ const abi = fn([tupleParam]);
268
+ const input = JSON.stringify({ addr: ADDR, amount: '1' });
269
+ expect(() => parseAbiArguments(abi, [input])).toThrow(/missing field/i);
270
+ });
271
+ test('invalid JSON throws', () => {
272
+ const abi = fn([tupleParam]);
273
+ expect(() => parseAbiArguments(abi, ['{not json'])).toThrow(/invalid json/i);
274
+ });
275
+ test('non-array non-object value throws', () => {
276
+ const abi = fn([tupleParam]);
277
+ expect(() => parseAbiArguments(abi, ['42'])).toThrow(/expected json object or array/i);
278
+ });
279
+ test('array representation with unnamed component uses numeric index key (line 140)', () => {
280
+ const param = {
281
+ name: 'data',
282
+ type: 'tuple',
283
+ components: [{ type: 'uint256' }, { type: 'bool' }],
284
+ };
285
+ const abi = fn([param]);
286
+ // Component has no name — array form should use index as key
287
+ expect(parseAbiArguments(abi, ['[42, true]'])).toEqual([
288
+ { 0: 42n, 1: true },
289
+ ]);
290
+ });
291
+ test('tuple with no components throws', () => {
292
+ const bare = { name: 'x', type: 'tuple' };
293
+ const abi = fn([bare]);
294
+ expect(() => parseAbiArguments(abi, ['{}'])).toThrow(/no components/i);
295
+ });
296
+ test('tuple component with no name throws when using object form (line 153)', () => {
297
+ const param = {
298
+ name: 'data',
299
+ type: 'tuple',
300
+ components: [{ type: 'uint256' }],
301
+ };
302
+ const abi = fn([param]);
303
+ expect(() => parseAbiArguments(abi, ['{"": 1}'])).toThrow(/tuple component has no name/i);
304
+ });
305
+ // Acceptance test — exposes String({}) bug
306
+ test('tuple[]: array of tuples parsed correctly', () => {
307
+ const param = {
308
+ name: 'items',
309
+ type: 'tuple[]',
310
+ components: [
311
+ { name: 'id', type: 'uint256' },
312
+ { name: 'owner', type: 'address' },
313
+ ],
314
+ };
315
+ const abi = fn([param]);
316
+ const input = JSON.stringify([
317
+ { id: '1', owner: ADDR },
318
+ { id: '2', owner: ADDR },
319
+ ]);
320
+ expect(parseAbiArguments(abi, [input])).toEqual([
321
+ [
322
+ { id: 1n, owner: ADDR },
323
+ { id: 2n, owner: ADDR },
324
+ ],
325
+ ]);
326
+ });
327
+ // Acceptance test — exposes String({}) bug on nested tuple
328
+ test('nested tuple (tuple within tuple) parsed correctly', () => {
329
+ const param = {
330
+ name: 'outer',
331
+ type: 'tuple',
332
+ components: [
333
+ { name: 'value', type: 'uint256' },
334
+ {
335
+ name: 'inner',
336
+ type: 'tuple',
337
+ components: [
338
+ { name: 'x', type: 'uint256' },
339
+ { name: 'y', type: 'uint256' },
340
+ ],
341
+ },
342
+ ],
343
+ };
344
+ const abi = fn([param]);
345
+ const input = JSON.stringify({ value: '10', inner: { x: '1', y: '2' } });
346
+ expect(parseAbiArguments(abi, [input])).toEqual([
347
+ { value: 10n, inner: { x: 1n, y: 2n } },
348
+ ]);
349
+ });
350
+ });
351
+ // --- unsupported type ---
352
+ describe('unsupported type', () => {
353
+ test('unknown type throws', () => {
354
+ const abi = fn([{ name: 'x', type: 'function' }]);
355
+ expect(() => parseAbiArguments(abi, ['0x'])).toThrow(/unsupported abi type/i);
356
+ });
357
+ });
358
+ // --- error message format ---
359
+ describe('error message wrapping', () => {
360
+ test('error includes param name and type', () => {
361
+ const abi = fn([{ name: 'myParam', type: 'uint256' }]);
362
+ let caught;
363
+ try {
364
+ parseAbiArguments(abi, ['notanumber']);
365
+ }
366
+ catch (e) {
367
+ caught = e;
368
+ }
369
+ expect(caught?.message).toMatch(/param.*myParam/i);
370
+ expect(caught?.message).toMatch(/type.*uint256/i);
371
+ });
372
+ test('unnamed param falls back to <unnamed> in error message (line 179)', () => {
373
+ // Directly exercise the unnamed-param branch by passing a nameless input
374
+ const abi = {
375
+ type: 'function',
376
+ name: 'test',
377
+ inputs: [{ type: 'uint256' }],
378
+ outputs: [],
379
+ stateMutability: 'nonpayable',
380
+ };
381
+ expect(() => parseAbiArguments(abi, ['abc'])).toThrow(/<unnamed>/);
382
+ });
383
+ test('already-wrapped error is re-thrown without double-wrapping (line 182)', () => {
384
+ // uint256[][] with an invalid leaf value: the innermost error gets wrapped once,
385
+ // then re-thrown (not re-wrapped) by each outer level.
386
+ const abi = fn([{ name: 'x', type: 'uint256[][]' }]);
387
+ let caught;
388
+ try {
389
+ parseAbiArguments(abi, ['[["abc"]]']);
390
+ }
391
+ catch (e) {
392
+ caught = e;
393
+ }
394
+ // Should contain exactly one [param: block, not nested duplicates
395
+ const matches = caught?.message.match(/\[param:/g);
396
+ expect(matches).toHaveLength(1);
397
+ });
398
+ });
399
+ //# sourceMappingURL=parse-abi-arguments.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-abi-arguments.test.js","sourceRoot":"","sources":["../../../tests/utils/parse-abi-arguments.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const streamOf: (bytes: Uint8Array, chunkSize?: number) => ReadableStream<Uint8Array<ArrayBufferLike>>;
@@ -0,0 +1,11 @@
1
+ // Build a ReadableStream response body from bytes, chunked so tests exercise
2
+ // multi-read streaming. Default chunk keeps small payloads a single read.
3
+ export const streamOf = (bytes, chunkSize = 64 * 1024) => new ReadableStream({
4
+ start(controller) {
5
+ for (let i = 0; i < bytes.length; i += chunkSize) {
6
+ controller.enqueue(bytes.slice(i, i + chunkSize));
7
+ }
8
+ controller.close();
9
+ },
10
+ });
11
+ //# sourceMappingURL=stream-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-helpers.js","sourceRoot":"","sources":["../../../tests/utils/stream-helpers.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,0EAA0E;AAC1E,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAiB,EAAE,SAAS,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,CACnE,IAAI,cAAc,CAAa;IAC7B,KAAK,CAAC,UAAU;QACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;YACjD,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;QACpD,CAAC;QACD,UAAU,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare const parseEnvInt: (raw: string | undefined, fallback: number) => number;
@@ -0,0 +1,8 @@
1
+ // Parse an integer from an env var, falling back when unset or invalid.
2
+ export const parseEnvInt = (raw, fallback) => {
3
+ if (!raw)
4
+ return fallback;
5
+ const n = Number(raw);
6
+ return Number.isFinite(n) ? n : fallback;
7
+ };
8
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../utils/env.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,GAAuB,EACvB,QAAgB,EACR,EAAE;IACV,IAAI,CAAC,GAAG;QAAE,OAAO,QAAQ,CAAC;IAC1B,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC3C,CAAC,CAAC"}
@@ -1,20 +1,22 @@
1
1
  import { CID, Version } from 'multiformats/cid';
2
2
  export declare const IPFS_GATEWAY = "https://ipfs.io/ipfs";
3
+ export declare const DEFAULT_IPFS_MAX_CONTENT_BYTES: number;
3
4
  export type BigNumberType = 'bigint' | 'string';
4
5
  export type ReportFetchArgs = {
5
6
  cid: string;
6
7
  gateway?: string;
7
8
  bigNumberType?: BigNumberType;
9
+ maxBytes?: number;
8
10
  };
9
11
  export declare const fetchIPFS: <T>(args: ReportFetchArgs, cache?: boolean) => Promise<T>;
10
12
  export declare const fetchIPFSDirect: <T>(args: ReportFetchArgs) => Promise<T>;
11
13
  export declare const fetchIPFSBuffer: (args: ReportFetchArgs) => Promise<Uint8Array>;
12
14
  export declare const calculateIPFSAddCID: (fileContent: Uint8Array, version?: Version) => Promise<CID>;
13
- export declare const fetchIPFSDirectAndVerify: <T>(cid: string, gateway?: string) => Promise<{
15
+ export declare const fetchIPFSDirectAndVerify: <T>(cid: string, gateway?: string, maxBytes?: number) => Promise<{
14
16
  json: T;
15
17
  fileContent: Uint8Array;
16
18
  }>;
17
- export declare const fetchIPFSWithCacheAndVerify: <T>(cid: string, gateway?: string) => Promise<T>;
19
+ export declare const fetchIPFSWithCacheAndVerify: <T>(cid: string, gateway?: string, maxBytes?: number) => Promise<T>;
18
20
  type PinToIPFSArgs = {
19
21
  uploadUrl: string;
20
22
  uploadAuthorization?: string;
@@ -6,26 +6,91 @@ import fs from 'node:fs/promises';
6
6
  import path from 'node:path';
7
7
  import { logInfo, logTable } from './logging/console.js';
8
8
  import { assertSafeUrl } from './data-validators.js';
9
+ import { parseEnvInt } from './env.js';
9
10
  export const IPFS_GATEWAY = 'https://ipfs.io/ipfs';
11
+ // Max IPFS content size — guards against OOM from an oversized CID.
12
+ // Override: maxBytes arg > IPFS_MAX_CONTENT_BYTES env > this default.
13
+ export const DEFAULT_IPFS_MAX_CONTENT_BYTES = 20 * 1024 * 1024;
10
14
  const IPFS_CACHE_DIR = path.resolve('ipfs-cache');
15
+ // arg > env > default
16
+ const resolveMaxBytes = (override) => {
17
+ if (typeof override === 'number' &&
18
+ Number.isFinite(override) &&
19
+ override > 0) {
20
+ return override;
21
+ }
22
+ return Math.max(1, parseEnvInt(process.env.IPFS_MAX_CONTENT_BYTES, DEFAULT_IPFS_MAX_CONTENT_BYTES));
23
+ };
24
+ // Cheap pre-check. Header may be absent or lie — streaming is the real limit.
25
+ const assertContentLengthWithinLimit = (response, maxBytes) => {
26
+ const declared = Number(response.headers?.get('content-length'));
27
+ if (Number.isFinite(declared) && declared > maxBytes) {
28
+ throw new Error(`IPFS content too large: ${declared} bytes exceeds limit of ${maxBytes} bytes`);
29
+ }
30
+ };
31
+ // Join collected byte chunks into a single buffer.
32
+ const concatChunks = (chunks, total) => {
33
+ const out = new Uint8Array(total);
34
+ let offset = 0;
35
+ for (const chunk of chunks) {
36
+ out.set(chunk, offset);
37
+ offset += chunk.byteLength;
38
+ }
39
+ return out;
40
+ };
41
+ // Read in chunks, abort once total exceeds maxBytes (before full buffering).
42
+ const streamBodyWithLimit = async (body, maxBytes) => {
43
+ const reader = body.getReader();
44
+ const chunks = [];
45
+ let total = 0;
46
+ try {
47
+ while (true) {
48
+ const { done, value } = await reader.read();
49
+ if (done)
50
+ break;
51
+ if (!value)
52
+ continue;
53
+ total += value.byteLength;
54
+ if (total > maxBytes) {
55
+ await reader.cancel();
56
+ throw new Error(`IPFS content exceeds size limit of ${maxBytes} bytes`);
57
+ }
58
+ chunks.push(value);
59
+ }
60
+ }
61
+ finally {
62
+ reader.releaseLock?.();
63
+ }
64
+ return concatChunks(chunks, total);
65
+ };
66
+ // Streaming is the real limit; Content-Length is just an early reject.
67
+ // Fail closed if there's no body — a real fetch always has one for content.
68
+ const readBodyWithLimit = async (response, maxBytes) => {
69
+ assertContentLengthWithinLimit(response, maxBytes);
70
+ if (!response.body) {
71
+ throw new Error('IPFS response has no readable body');
72
+ }
73
+ return streamBodyWithLimit(response.body, maxBytes);
74
+ };
11
75
  export const fetchIPFS = async (args, cache = true) => {
12
- const { cid, gateway = IPFS_GATEWAY } = args;
76
+ const { cid, gateway = IPFS_GATEWAY, maxBytes } = args;
13
77
  if (cache)
14
- return fetchIPFSWithCacheAndVerify(cid, gateway);
15
- const { json } = await fetchIPFSDirectAndVerify(cid, gateway);
78
+ return fetchIPFSWithCacheAndVerify(cid, gateway, maxBytes);
79
+ const { json } = await fetchIPFSDirectAndVerify(cid, gateway, maxBytes);
16
80
  return json;
17
81
  };
18
82
  // Fetching content by CID through IPFS gateway
19
83
  export const fetchIPFSDirect = async (args) => {
20
84
  const { cid, gateway = IPFS_GATEWAY, bigNumberType = 'string' } = args;
21
85
  assertSafeUrl(gateway, 'IPFS gateway');
86
+ const maxBytes = resolveMaxBytes(args.maxBytes);
22
87
  const ipfsUrl = `${gateway}/${cid}`;
23
88
  logInfo('Fetching content from', ipfsUrl);
24
89
  const response = await fetch(ipfsUrl);
25
90
  if (!response.ok) {
26
91
  throw new Error(`Failed to fetch IPFS content: ${response.statusText}`);
27
92
  }
28
- const raw = await response.text();
93
+ const raw = new TextDecoder().decode(await readBodyWithLimit(response, maxBytes));
29
94
  const params = bigNumberType === 'bigint'
30
95
  ? { useNativeBigInt: true }
31
96
  : { storeAsString: true };
@@ -36,14 +101,14 @@ export const fetchIPFSDirect = async (args) => {
36
101
  export const fetchIPFSBuffer = async (args) => {
37
102
  const { cid, gateway = IPFS_GATEWAY } = args;
38
103
  assertSafeUrl(gateway, 'IPFS gateway');
104
+ const maxBytes = resolveMaxBytes(args.maxBytes);
39
105
  const ipfsUrl = `${gateway}/${cid}`;
40
106
  logInfo('Fetching content from', ipfsUrl);
41
107
  const response = await fetch(ipfsUrl);
42
108
  if (!response.ok) {
43
109
  throw new Error(`Failed to fetch IPFS content: ${response.statusText}`);
44
110
  }
45
- const buffer = await response.arrayBuffer();
46
- return new Uint8Array(buffer);
111
+ return readBodyWithLimit(response, maxBytes);
47
112
  };
48
113
  // Recalculate CID using full UnixFS logic (like `ipfs add`)
49
114
  export const calculateIPFSAddCID = async (fileContent, version = 0) => {
@@ -63,7 +128,7 @@ export const calculateIPFSAddCID = async (fileContent, version = 0) => {
63
128
  return lastCid;
64
129
  };
65
130
  // Downloading file from IPFS and checking its integrity
66
- export const fetchIPFSDirectAndVerify = async (cid, gateway = IPFS_GATEWAY) => {
131
+ export const fetchIPFSDirectAndVerify = async (cid, gateway = IPFS_GATEWAY, maxBytes) => {
67
132
  let originalCID;
68
133
  try {
69
134
  originalCID = CID.parse(cid);
@@ -71,7 +136,7 @@ export const fetchIPFSDirectAndVerify = async (cid, gateway = IPFS_GATEWAY) => {
71
136
  catch {
72
137
  throw new Error(`Invalid IPFS CID: ${cid}`);
73
138
  }
74
- const fileContent = await fetchIPFSBuffer({ cid, gateway });
139
+ const fileContent = await fetchIPFSBuffer({ cid, gateway, maxBytes });
75
140
  const calculatedCID = await calculateIPFSAddCID(fileContent, originalCID.version);
76
141
  if (!calculatedCID.equals(originalCID)) {
77
142
  throw new Error(`❌ File hash mismatch! Expected ${originalCID}, but got ${calculatedCID}`);
@@ -92,7 +157,7 @@ export const fetchIPFSDirectAndVerify = async (cid, gateway = IPFS_GATEWAY) => {
92
157
  json,
93
158
  };
94
159
  };
95
- export const fetchIPFSWithCacheAndVerify = async (cid, gateway = IPFS_GATEWAY) => {
160
+ export const fetchIPFSWithCacheAndVerify = async (cid, gateway = IPFS_GATEWAY, maxBytes) => {
96
161
  assertSafeUrl(gateway, 'IPFS gateway');
97
162
  try {
98
163
  CID.parse(cid);
@@ -109,7 +174,7 @@ export const fetchIPFSWithCacheAndVerify = async (cid, gateway = IPFS_GATEWAY) =
109
174
  }
110
175
  catch {
111
176
  // Not in cache, fetch from IPFS
112
- const { json } = await fetchIPFSDirectAndVerify(cid, gateway);
177
+ const { json } = await fetchIPFSDirectAndVerify(cid, gateway, maxBytes);
113
178
  await fs.writeFile(cacheFile, JSON.stringify(json), 'utf8');
114
179
  return json;
115
180
  }