@autonomys/file-server 1.5.18 → 1.5.19

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.
@@ -1 +1 @@
1
- {"version":3,"file":"fileCache.d.ts","sourceRoot":"","sources":["../../src/caching/fileCache.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAS9E,eAAO,MAAM,eAAe,GAAI,QAAQ,eAAe;eA8B7B,MAAM,YAAY,gBAAgB,KAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;eAyBjE,MAAM,gBAAgB,YAAY;eARlC,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;kBAoBtB,MAAM;CA0BlC,CAAA"}
1
+ {"version":3,"file":"fileCache.d.ts","sourceRoot":"","sources":["../../src/caching/fileCache.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAU9E,eAAO,MAAM,eAAe,GAAI,QAAQ,eAAe;eA8B7B,MAAM,YAAY,gBAAgB,KAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;eAiCjE,MAAM,gBAAgB,YAAY;eARlC,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;kBAoBtB,MAAM;CA0BlC,CAAA"}
@@ -22,6 +22,7 @@ import { createCache } from 'cache-manager';
22
22
  import fs from 'fs';
23
23
  import fsPromises from 'fs/promises';
24
24
  import path from 'path';
25
+ import { createErrorResilientStream } from './streamUtils.js';
25
26
  import { writeFile } from './utils.js';
26
27
  const CHARS_PER_PARTITION = 2;
27
28
  export const createFileCache = (config) => {
@@ -54,10 +55,16 @@ export const createFileCache = (config) => {
54
55
  return null;
55
56
  }
56
57
  const path = cidToFilePath(cid);
57
- return Object.assign(Object.assign({}, data), { data: fs.createReadStream(path, {
58
- start: (_a = options === null || options === void 0 ? void 0 : options.byteRange) === null || _a === void 0 ? void 0 : _a[0],
59
- end: (_b = options === null || options === void 0 ? void 0 : options.byteRange) === null || _b === void 0 ? void 0 : _b[1],
60
- }) });
58
+ const sourceStream = fs.createReadStream(path, {
59
+ start: (_a = options === null || options === void 0 ? void 0 : options.byteRange) === null || _a === void 0 ? void 0 : _a[0],
60
+ end: (_b = options === null || options === void 0 ? void 0 : options.byteRange) === null || _b === void 0 ? void 0 : _b[1],
61
+ });
62
+ // Wrap with error-resilient stream for stalled stream detection
63
+ const resilientStream = createErrorResilientStream(sourceStream, {
64
+ stallTimeout: 30000, // 30 seconds
65
+ healthCheckInterval: 5000, // 5 seconds
66
+ });
67
+ return Object.assign(Object.assign({}, data), { data: resilientStream });
61
68
  });
62
69
  const has = (cid) => __awaiter(void 0, void 0, void 0, function* () {
63
70
  const path = cidToFilePath(cid);
@@ -1,4 +1,5 @@
1
1
  export * from './defaultConfigs.js';
2
2
  export * from './fileCache.js';
3
+ export * from './streamUtils.js';
3
4
  export * from './utils.js';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/caching/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/caching/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA"}
@@ -1,3 +1,4 @@
1
1
  export * from './defaultConfigs.js';
2
2
  export * from './fileCache.js';
3
+ export * from './streamUtils.js';
3
4
  export * from './utils.js';
@@ -0,0 +1,20 @@
1
+ import { Readable } from 'stream';
2
+ export interface StreamHealthMetrics {
3
+ isStalled: boolean;
4
+ lastActivity: number;
5
+ isDestroyed: boolean;
6
+ }
7
+ export interface ErrorResilientStreamOptions {
8
+ stallTimeout?: number;
9
+ healthCheckInterval?: number;
10
+ }
11
+ interface ErrorResilientStream extends Readable {
12
+ healthCheck?: () => StreamHealthMetrics;
13
+ }
14
+ /**
15
+ * Creates an error-resilient stream wrapper that prevents consumer errors from stalling the source stream
16
+ * Focuses on detecting and handling stalled streams
17
+ */
18
+ export declare const createErrorResilientStream: (sourceStream: Readable, options?: ErrorResilientStreamOptions) => ErrorResilientStream;
19
+ export {};
20
+ //# sourceMappingURL=streamUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamUtils.d.ts","sourceRoot":"","sources":["../../src/caching/streamUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAE9C,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,2BAA2B;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,UAAU,oBAAqB,SAAQ,QAAQ;IAC7C,WAAW,CAAC,EAAE,MAAM,mBAAmB,CAAA;CACxC;AAED;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GACrC,cAAc,QAAQ,EACtB,UAAS,2BAAgC,KACxC,oBAyHF,CAAA"}
@@ -0,0 +1,107 @@
1
+ import { PassThrough } from 'stream';
2
+ /**
3
+ * Creates an error-resilient stream wrapper that prevents consumer errors from stalling the source stream
4
+ * Focuses on detecting and handling stalled streams
5
+ */
6
+ export const createErrorResilientStream = (sourceStream, options = {}) => {
7
+ const { stallTimeout = 30000, // 30 seconds
8
+ healthCheckInterval = 5000, // 5 seconds
9
+ } = options;
10
+ const passThrough = new PassThrough({
11
+ highWaterMark: 64 * 1024, // 64KB buffer to handle backpressure
12
+ objectMode: false,
13
+ });
14
+ // Simple metrics for stalled stream detection
15
+ const metrics = {
16
+ isStalled: false,
17
+ lastActivity: Date.now(),
18
+ isDestroyed: false,
19
+ };
20
+ let healthCheckTimer = null;
21
+ // Health check function - only checks for stalled streams
22
+ const healthCheck = () => {
23
+ const now = Date.now();
24
+ const timeSinceLastActivity = now - metrics.lastActivity;
25
+ metrics.isStalled = timeSinceLastActivity > stallTimeout && !metrics.isDestroyed;
26
+ return Object.assign({}, metrics);
27
+ };
28
+ // Start periodic health checks for stalled streams
29
+ const startHealthChecks = () => {
30
+ if (healthCheckTimer) {
31
+ clearInterval(healthCheckTimer);
32
+ }
33
+ healthCheckTimer = setInterval(() => {
34
+ const health = healthCheck();
35
+ if (health.isStalled) {
36
+ console.warn('Stream detected as stalled:', {
37
+ timeSinceLastActivity: Date.now() - health.lastActivity,
38
+ stallTimeout,
39
+ });
40
+ // Destroy the stalled stream
41
+ passThrough.destroy(new Error('Stream stalled - no activity detected'));
42
+ }
43
+ }, healthCheckInterval);
44
+ };
45
+ // Set up backpressure-aware data flow
46
+ sourceStream.on('data', (chunk) => {
47
+ try {
48
+ metrics.lastActivity = Date.now();
49
+ metrics.isStalled = false;
50
+ if (!passThrough.destroyed) {
51
+ const canContinue = passThrough.write(chunk);
52
+ if (!canContinue) {
53
+ // Backpressure: pause source stream until drain event
54
+ sourceStream.pause();
55
+ }
56
+ }
57
+ }
58
+ catch (error) {
59
+ console.error('Error processing stream data:', error);
60
+ // Don't destroy the stream on consumer errors, just log
61
+ }
62
+ });
63
+ // Resume source stream when pass-through is ready for more data
64
+ passThrough.on('drain', () => {
65
+ if (!sourceStream.destroyed && !passThrough.destroyed) {
66
+ sourceStream.resume();
67
+ }
68
+ });
69
+ // Handle source stream end
70
+ sourceStream.on('end', () => {
71
+ if (!passThrough.destroyed) {
72
+ passThrough.end();
73
+ }
74
+ metrics.lastActivity = Date.now();
75
+ });
76
+ // Handle source stream errors
77
+ sourceStream.on('error', (error) => {
78
+ console.error('Source stream error:', error);
79
+ metrics.lastActivity = Date.now();
80
+ passThrough.destroy(error);
81
+ });
82
+ // Handle pass-through stream errors (consumer errors)
83
+ passThrough.on('error', (error) => {
84
+ console.error('Consumer stream error:', error);
85
+ metrics.lastActivity = Date.now();
86
+ // Don't propagate consumer errors to source stream
87
+ });
88
+ // Handle pass-through stream on end
89
+ passThrough.on('end', () => {
90
+ metrics.lastActivity = Date.now();
91
+ if (healthCheckTimer)
92
+ clearInterval(healthCheckTimer);
93
+ });
94
+ // Handle pass-through stream close
95
+ passThrough.on('close', () => {
96
+ metrics.isDestroyed = true;
97
+ metrics.lastActivity = Date.now();
98
+ if (healthCheckTimer) {
99
+ clearInterval(healthCheckTimer);
100
+ }
101
+ });
102
+ // Start health monitoring
103
+ startHealthChecks();
104
+ const errorResilientStream = passThrough;
105
+ errorResilientStream.healthCheck = healthCheck;
106
+ return errorResilientStream;
107
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@autonomys/file-server",
3
3
  "packageManager": "yarn@4.7.0",
4
- "version": "1.5.18",
4
+ "version": "1.5.19",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "repository": {
@@ -47,9 +47,9 @@
47
47
  "typescript": "^5.8.3"
48
48
  },
49
49
  "dependencies": {
50
- "@autonomys/asynchronous": "^1.5.18",
51
- "@autonomys/auto-dag-data": "^1.5.18",
52
- "@autonomys/auto-utils": "^1.5.18",
50
+ "@autonomys/asynchronous": "^1.5.19",
51
+ "@autonomys/auto-dag-data": "^1.5.19",
52
+ "@autonomys/auto-utils": "^1.5.19",
53
53
  "@keyvhq/sqlite": "^2.1.7",
54
54
  "cache-manager": "^6.4.2",
55
55
  "express": "^4.19.2",
@@ -61,5 +61,5 @@
61
61
  "uuid": "^11.1.0",
62
62
  "zod": "^3.24.2"
63
63
  },
64
- "gitHead": "b339864e15c46187ddcc75ebeed3d8170fbe7c9e"
64
+ "gitHead": "ada024eb3cb14bf67b3d9f1cb8545e7b7d9d14ed"
65
65
  }